首页
关于
留言
友链
电台
壁纸
我的足迹
推荐
知易而行MCP
Search
1
乐橙CMS影视管理系统最全版本
109,280 阅读
2
VIP视频解析破解电影解析模拟破解影视解析
77,798 阅读
3
乐橙CMS影视管理系统4.0.18版本
16,934 阅读
4
新浪图片链接修复教程集合
15,126 阅读
5
反调试代码调试死机代码禁止F12代码
12,094 阅读
语言
PHP
Java
Go
JavaScript
CSS
Vue
资源教程
网络杂谈
技术文章
影视交流
软件工具
Mac
知易而行
登录
Search
标签搜索
PHP
AI
LINUX
微信
MYSQL
树莓派
OpenClaw
ESP32S3
小智AI
P2P
JS
破解
乐橙cms
支付
uniapp
人工智能
技术趋势
智能玩具
ESP32
DIY
子沐~
累计撰写
124
篇文章
累计收到
372
条评论
首页
栏目
语言
PHP
Java
Go
JavaScript
CSS
Vue
资源教程
网络杂谈
技术文章
影视交流
软件工具
Mac
知易而行
页面
关于
留言
友链
电台
壁纸
我的足迹
推荐
知易而行MCP
搜索到
2
篇与
的结果
2026-02-09
树莓派4B视觉识别机械臂制作教程:从零开始打造你的智能助手
树莓派4B视觉识别机械臂制作教程:从零开始打造你的智能助手在这个智能化的时代,结合计算机视觉和机械臂技术,我们可以打造一个既有趣又实用的智能助手。本文将详细介绍如何从零开始使用树莓派4B制作一个视觉识别机械臂,包含完整的硬件清单、接线图、代码实现和调试技巧。一、项目概述1.1 功能特点 视觉识别:基于OpenCV的物体识别和定位 机械臂控制:6轴机械臂,支持多种运动模式 自动抓取:识别物体后自动移动到目标位置并抓取 远程监控:实时摄像头画面传输 语音控制:支持语音命令控制机械臂动作 1.2 所需技能 Linux系统基础操作 Python编程基础 OpenCV图像处理基础 基本的电路连接和焊接 3D打印(可选,用于机械臂外壳) 二、硬件清单2.1 核心部件 名称 型号/规格 数量 用途 主控板 树莓派4B(4GB) 1 核心控制器 SD卡 SanDisk Extreme 32GB Class 10 1 系统存储 摄像头 树莓派摄像头V2(800万像素) 1 视觉采集 机械臂 6轴金属机械臂(带舵机) 1 动作执行 舵机驱动板 PCA9685 16通道PWM驱动 1 舵机控制 电源模块 5V 10A开关电源 1 供电 LED灯带 WS2812B RGB灯带(1米) 1 状态指示 触摸屏 7寸1024×600电容触摸屏 1 人机交互 2.2 辅助配件 名称 规格 数量 用途 杜邦线 公对母、母对母各40根 1套 电路连接 面包板 830孔面包板 1 原型测试 电阻 10kΩ、1kΩ各10个 20 上拉、限流电阻 电容 100μF、10μF电解电容 5 滤波 开关 自锁开关、轻触开关各1 2 电源控制 散热片 树莓派专用散热片 1 散热 外壳 亚克力/3D打印外壳 1 机械臂底座 2.3 工具清单 电烙铁:30-40W恒温电烙铁 焊锡丝:0.8mm含铅焊锡 万用表:用于电压、电流测量 剥线钳:用于剥去线缆绝缘层 斜口钳:用于剪断线缆 螺丝刀套装:十字、一字各型号 USB数据线:用于树莓派供电和数据传输 三、采购清单与预算3.1 硬件采购清单 分类 物品 推荐品牌/型号 预计价格(元) 购买渠道 主控 树莓派4B 4GB 树莓派基金会 380 立创商城、淘宝 存储 32GB Class 10 SD卡 SanDisk Extreme 45 京东、淘宝 视觉 树莓派摄像头V2 树莓派基金会 130 立创商城、淘宝 机械臂 6轴金属机械臂套件 DFRobot/淘宝 280 淘宝、亚马逊 驱动 PCA9685舵机驱动板 Adafruit/淘宝 25 淘宝、亚马逊 电源 5V 10A开关电源 明纬/航嘉 35 京东、淘宝 显示 7寸电容触摸屏 微雪/淘宝 120 淘宝 配件 杜邦线、电阻等 杂牌 30 淘宝 硬件总计:约1045元3.2 软件准备 操作系统:Raspberry Pi OS(64位) 编程环境:Python 3.9+、OpenCV 4.5+ IDE:Thonny或VS Code 库文件:RPi.GPIO、Adafruit_PCA9685、OpenCV 四、硬件连接与安装4.1 树莓派引脚分配PCA9685舵机驱动板(I2C): - VCC → 5V电源 - GND → GND - SDA → GPIO 2(SDA1) - SCL → GPIO 3(SCL1) 摄像头模块: - SDA → CSI接口 - SCL → CSI接口 - VCC → 3.3V - GND → GND 触摸屏(HDMI接口): - HDMI → HDMI0 - USB → USB3.0 - VCC → 5V - GND → GND LED灯带(GPIO控制): - DATA → GPIO 18(PWM) - VCC → 5V - GND → GND 机械臂舵机连接(PCA9685通道): - 底部旋转舵机 → 通道0 - 大臂舵机 → 通道1 - 小臂舵机 → 通道2 - 手腕舵机 → 通道3 - 手爪旋转舵机 → 通道4 - 手爪开合舵机 → 通道54.2 电源电路设计5V 10A开关电源 │ ├─→ 树莓派(5V/3A) ├─→ PCA9685驱动板(5V/2A) ├─→ 机械臂舵机(5V/3A) ├─→ 摄像头(5V/0.5A) ├─→ 触摸屏(5V/1A) └─→ LED灯带(5V/0.5A) 注意:总电流约7A,电源需有足够余量重要提示: 确保电源输出稳定,电压纹波小于100mV 舵机工作时电流较大,建议添加1000μF滤波电容 树莓派GPIO口电流限制为16mA,不要直接驱动LED I2C总线(SDA/SCL)需要添加4.7kΩ上拉电阻 4.3 机械臂组装步骤 底座安装:将机械臂底座固定在亚克力板上 舵机安装:按顺序安装6个舵机到底座上 连杆组装:将机械臂各段通过连杆连接 线缆整理:使用扎带整理线缆,避免干扰 树莓派固定:将树莓派固定在底座后方 摄像头安装:将摄像头安装在机械臂前上方 五、软件安装与配置5.1 系统安装5.1.1 烧录系统镜像下载Raspberry Pi OS(64位)并烧录到SD卡:# 下载官方镜像 wget https://downloads.raspberrypi.org/raspios_arm64/images/raspios_arm64-2023-05-03.zip # 使用Raspberry Pi Imager烧录 # Windows: 下载Raspberry Pi Imager from https://www.raspberrypi.com/software/ # Linux/Mac: 使用dd命令烧录 dd if=raspios_arm64-2023-05-03.img of=/dev/sdX bs=4M status=progress5.1.2 首次启动配置 启动树莓派:插入SD卡、连接HDMI和USB键鼠 系统设置:选择语言、时区、WiFi等 更新系统:sudo apt update sudo apt upgrade -y 开启I2C和SPI:使用raspi-config配置 重启系统:sudo reboot 5.2 开发环境搭建5.2.1 安装Python依赖库# 更新pip pip3 install --upgrade pip # 安装OpenCV pip3 install opencv-python==4.7.0.72 # 安装PCA9685驱动库 pip3 install adafruit-circuitpython-pca9685 # 安装GPIO库 pip3 install RPi.GPIO # 安装其他依赖 pip3 install numpy==1.24.3 pip3 install pillow==10.0.0 # 安装系统库 sudo apt install -y python3-dev sudo apt install -y libi2c-dev sudo apt install -y libopencv-dev5.2.2 启用摄像头接口# 编辑config.txt sudo nano /boot/config.txt # 添加或取消注释以下行: start_x=1 gpu_mem=128 # 重启 sudo reboot5.2.3 创建项目目录# 创建项目目录 mkdir -p ~/robot_arm_project cd ~/robot_arm_project # 创建子目录 mkdir -p src mkdir -p config mkdir -p models mkdir -p logs # 创建虚拟环境 python3 -m venv venv source venv/bin/activate5.3 摄像头测试创建摄像头测试脚本:import cv2 import time def test_camera(): # 初始化摄像头 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("无法打开摄像头!") return print("摄像头测试开始,按'q'键退出") while True: ret, frame = cap.read() if not ret: print("无法读取帧!") break # 显示画面 cv2.imshow('Camera Test', frame) # 按'q'退出 if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() print("摄像头测试结束") if __name__ == '__main__': test_camera()六、核心代码实现6.1 PCA9685舵机控制创建舵机控制模块:from adafruit_servo import Servo from board import SCL, SDA import busio import time class ArmServoController: def __init__(self): # 初始化I2C总线 self.i2c = busio.I2C(SCL, SDA) # 初始化PCA9685 self.pca = Servo(0, 0x40) # 使用I2C地址0x40 self.pca.frequency = 50 # 初始化6个舵机通道 self.servos = { 'base': Servo(0), # 通道0:底部旋转 'shoulder': Servo(1), # 通道1:大臂 'elbow': Servo(2), # 通道2:小臂 'wrist': Servo(3), # 通道3:手腕 'wrist_rot': Servo(4), # 通道4:手腕旋转 'gripper': Servo(5) # 通道5:手爪 } # 初始位置(0-180度) self.home_position = { 'base': 90, 'shoulder': 90, 'elbow': 90, 'wrist': 90, 'wrist_rot': 90, 'gripper': 90 } # 移动到初始位置 self.move_to_home() def move_to_home(self): """移动所有舵机到初始位置""" print("机械臂归零中...") for name, angle in self.home_position.items(): self.servos[name].angle = angle time.sleep(1) print("机械臂归零完成") def move_servo(self, servo_name, angle): """移动指定舵机到指定角度 Args: servo_name: 舵机名称(base, shoulder, elbow, wrist, wrist_rot, gripper) angle: 角度(0-180) """ if servo_name in self.servos: self.servos[servo_name].angle = angle print(f"{servo_name}: {angle}度") else: print(f"未找到舵机: {servo_name}") def set_pose(self, pose): """设置机械臂姿态 Args: pose: 姿态字典 {'base': angle, 'shoulder': angle, ...} """ for name, angle in pose.items(): if name in self.servos: self.servos[name].angle = angle # 等待舵机移动完成 time.sleep(0.5) def gripper_open(self): """打开手爪""" self.servos['gripper'].angle = 0 time.sleep(0.5) print("手爪已打开") def gripper_close(self): """闭合手爪""" self.servos['gripper'].angle = 180 time.sleep(0.5) print("手爪已闭合") def shutdown(self): """关闭所有舵机(释放脉冲)""" for name, servo in self.servos.items(): servo.angle = None print("机械臂已关闭") if __name__ == '__main__': # 测试舵机控制器 controller = ArmServoController() # 测试各个舵机 controller.move_servo('base', 120) time.sleep(1) controller.move_servo('shoulder', 60) time.sleep(1) controller.gripper_open() time.sleep(1) controller.gripper_close() time.sleep(1) # 返回初始位置 controller.move_to_home()6.2 视觉识别模块创建基于OpenCV的物体识别模块:import cv2 import numpy as np class VisionDetector: def __init__(self): # 初始化摄像头 self.cap = cv2.VideoCapture(0) self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # 颜色定义(HSV) self.colors = { 'red': { 'lower': np.array([0, 120, 70]), 'upper': np.array([10, 255, 255]) }, 'green': { 'lower': np.array([40, 50, 50]), 'upper': np.array([80, 255, 255]) }, 'blue': { 'lower': np.array([100, 100, 50]), 'upper': np.array([130, 255, 255]) } } # 目标物体中心点 self.target_center = None def detect_object(self, color_name='red', show_frame=False): """检测指定颜色的物体 Args: color_name: 颜色名称(red, green, blue) show_frame: 是否显示处理画面 Returns: (x, y): 物体中心坐标 success: 是否检测到物体 """ if not self.cap.isOpened(): return None, False ret, frame = self.cap.read() if not ret: return None, False # 转换为HSV颜色空间 hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) # 获取指定颜色的范围 color = self.colors.get(color_name) if not color: return None, False # 创建颜色掩膜 mask = cv2.inRange(hsv, color['lower'], color['upper']) # 形态学操作 kernel = np.ones((5,5), np.uint8) mask = cv2.erode(mask, kernel, iterations=1) mask = cv2.dilate(mask, kernel, iterations=2) # 查找轮廓 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: # 找到最大的轮廓 largest_contour = max(contours, key=cv2.contourArea) # 计算最小外接矩形 x, y, w, h = cv2.boundingRect(largest_contour) # 计算中心点 center_x = x + w // 2 center_y = y + h // 2 # 在原图上绘制检测框 cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.circle(frame, (center_x, center_y), 5, (0, 0, 255), -1) self.target_center = (center_x, center_y) if show_frame: cv2.imshow(f'{color_name} Detection', frame) return (center_x, center_y), True else: self.target_center = None if show_frame: cv2.imshow(f'{color_name} Detection', frame) return None, False def calibrate_camera(self): """摄像头标定(可选)""" print("开始摄像头标定...") # 使用棋盘格标定 chessboard_size = (9, 6) square_size = 25 # mm # 准备标定点 objp = np.zeros((chessboard_size[0]*chessboard_size[1], 3), np.float32) objp[:,:2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) objp *= square_size objpoints = [] imgpoints = [] cap = self.cap if not cap.isOpened(): print("无法打开摄像头进行标定!") return print("移动棋盘格到摄像头视野内,按'q'键拍摄下一张图片") print("总共需要20张图片") count = 0 while count < 20: ret, frame = cap.read() if not ret: continue gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 寻找棋盘格角点 ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None) if ret: objpoints.append(objp) corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1)) imgpoints.append(corners) # 绘制角点 cv2.drawChessboardCorners(frame, chessboard_size, corners, True) count += 1 print(f"已采集 {count}/20 张图片") cv2.imshow('Camera Calibration', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows() if len(objpoints) > 0: # 计算相机参数 ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None) # 保存标定结果 print("标定完成!") print("相机内参矩阵:") print(mtx) print("畸变系数:") print(dist) # 保存到文件 np.save('camera_calibration.npz', mtx=mtx, dist=dist) return mtx, dist else: print("标定失败!") return None, None def release(self): """释放摄像头资源""" if self.cap.isOpened(): self.cap.release() print("摄像头已释放") if __name__ == '__main__': detector = VisionDetector() # 测试物体检测 print("开始检测红色物体...") while True: center, success = detector.detect_object('red', show_frame=True) if success: print(f"检测到物体!中心点: ({center[0]}, {center[1]})") if cv2.waitKey(1) & 0xFF == ord('q'): break detector.release() cv2.destroyAllWindows()6.3 主控制程序创建主控制程序,整合视觉识别和机械臂控制:import cv2 import numpy as np import time import threading from arm_servo_controller import ArmServoController from vision_detector import VisionDetector class RoboticArmController: def __init__(self): # 初始化视觉识别 self.vision = VisionDetector() # 初始化机械臂 self.arm = ArmServoController() # 目标位置(图像坐标) self.target_position = None # 工作空间边界(图像坐标系) self.workspace = { 'left': 200, 'right': 1080, 'top': 100, 'bottom': 600 } # 抓取序列 self.grab_sequence = [ {'base': 90, 'shoulder': 90, 'elbow': 90, 'wrist': 90, 'wrist_rot': 90, 'gripper': 90}, # 初始位置 {'base': 90, 'shoulder': 45, 'elbow': 45, 'wrist': 90, 'wrist_rot': 90, 'gripper': 90}, # 移动到上方 {'base': 90, 'shoulder': 45, 'elbow': 45, 'wrist': 45, 'wrist_rot': 90, 'gripper': 90}, # 下降 {'base': 90, 'shoulder': 45, 'elbow': 45, 'wrist': 45, 'wrist_rot': 90, 'gripper': 0}, # 打开手爪 {'base': 90, 'shoulder': 45, 'elbow': 45, 'wrist': 45, 'wrist_rot': 90, 'gripper': 90}, # 抓取 {'base': 90, 'shoulder': 45, 'elbow': 45, 'wrist': 45, 'wrist_rot': 90, 'gripper': 90}, # 抬起 {'base': 90, 'shoulder': 90, 'elbow': 90, 'wrist': 90, 'wrist_rot': 90, 'gripper': 90}, # 回到初始位置 ] self.is_running = False self.capture_thread = None def image_to_robot(self, image_point): """将图像坐标转换为机械臂关节角度 Args: image_point: (x, y) 图像坐标 Returns: angles: 舵机角度字典 """ x, y = image_point # 简化的逆运动学(实际应用需要更复杂的计算) # 将图像坐标映射到关节角度 # X轴映射到base和shoulder base_angle = 90 + (x - 640) * 0.1 base_angle = max(0, min(180, base_angle)) # Y轴映射到elbow和wrist elbow_angle = 90 + (y - 360) * 0.1 elbow_angle = max(0, min(180, elbow_angle)) angles = { 'base': int(base_angle), 'shoulder': 90, 'elbow': int(elbow_angle), 'wrist': 90, 'wrist_rot': 90, 'gripper': 90 } return angles def detect_and_grab(self, color='red'): """检测并抓取物体 Args: color: 目标物体颜色 """ print(f"开始检测{color}色物体...") # 1. 检测物体 center, success = self.vision.detect_object(color) if not success: print("未检测到目标物体!") return False print(f"检测到物体!位置: {center}") # 2. 检查是否在工作空间内 x, y = center if not (self.workspace['left']
2026年02月09日
0 阅读
0 评论
0 点赞
2026-02-09
ESP32桌面宠物DIY教程:从零开始打造你的智能桌面伙伴
ESP32桌面宠物DIY教程:从零开始打造你的智能桌面伙伴在这个智能化的时代,桌面宠物已经不再是简单的摆设。结合ESP32的强大功能和创意设计,我们可以打造一个既有趣又实用的桌面宠物。本文将详细介绍如何从零开始DIY一个ESP32桌面宠物,包含完整的硬件清单、接线图、代码实现和调试技巧。一、项目概述1.1 功能特点 表情互动:多种表情显示,通过触摸感应切换 语音对话:集成AI语音助手,支持智能问答 环境感知:温湿度监测,实时环境数据 时间显示:LED点阵显示当前时间 远程控制:支持手机APP远程交互 1.2 所需技能 基础的焊接和电路连接 Arduino IDE或VS Code PlatformIO 基础的C/C++编程知识 3D打印(可选,用于外壳制作) 二、硬件清单2.1 核心部件 名称 型号 数量 用途 主控板 ESP32-WROVER-32 1 核心控制器 显示屏 0.96寸OLED(I2C) 1 显示表情、时间 触摸传感器 TTP223 1 触摸交互 温湿度传感器 DHT22 1 环境监测 扬声器 8欧 0.5W 1 语音播放 麦克风模块 MAX4466 1 语音输入 LED点阵 8x8点阵MAX7219 1 时间显示 2.2 电源和其他 电源模块:18650锂电池 + TP4056充电模块 开关:自锁开关 × 1 杜邦线:公对母、母对母各20根 面包板:可选,用于原型测试 电阻:10kΩ × 2(上拉电阻) 电容:100μF × 1(滤波) 3D打印外壳:STL文件可自行设计或下载 总计成本:约 80-120元三、硬件连接3.1 ESP32引脚分配OLED显示屏(I2C): - SDA → GPIO 21 - SCL → GPIO 22 - VCC → 3.3V - GND → GND 触摸传感器 TTP223: - OUT → GPIO 4 - VCC → 3.3V - GND → GND 温湿度传感器 DHT22: - DATA → GPIO 15 - VCC → 5V - GND → GND LED点阵 MAX7219: - DIN → GPIO 23 - CS → GPIO 5 - CLK → GPIO 18 - VCC → 5V - GND → GND I2S音频模块: - BCLK → GPIO 26 - LRCK → GPIO 25 - DIN → GPIO 22 - MAX4466麦克风 → GPIO 363.2 电源电路18650电池 → TP4056充电模块 → AMS1117稳压模块(5V→3.3V)→ ESP32 ↓ 各传感器模块重要提示: ESP32工作电压为3.3V,部分模块(如DHT22)需要5V供电 务必添加滤波电容,避免电源纹波干扰 电池容量建议2000mAh以上,保证持续工作时间 四、软件安装与配置4.1 开发环境搭建方案一:Arduino IDE 下载安装Arduino IDE官网:https://www.arduino.cc/en/software选择对应系统版本下载安装 配置ESP32开发板支持文件 → 首选项 附加开发板管理器网址: https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 安装ESP32开发板工具 → 开发板 → 开发板管理器 搜索 "ESP32" 安装 "esp32 by Espressif Systems" 安装必需库工具 → 管理库 搜索并安装: - Adafruit SSD1306(OLED驱动) - Adafruit GFX Library(图形库) - DHT sensor library(温湿度传感器) - LedControl(LED点阵控制) - ESP32-audioI2S(I2S音频) 方案二:VS Code + PlatformIO(推荐) 安装VS Code官网下载:https://code.visualstudio.com/ 安装PlatformIO扩展VS Code → 扩展商店 → 搜索 "PlatformIO" 安装 "PlatformIO IDE" 创建新项目File → Open Folder → 选择工作目录 PlatformIO → New Project - Name: ESP32_Desktop_Pet - Board: ESP32 Dev Module - Framework: Arduino 配置依赖库编辑 platformio.ini:[env:esp32dev] platform = espressif32 board = esp32dev framework = arduino lib_deps = adafruit/Adafruit SSD1306 adafruit/Adafruit GFX Library adafruit/DHT sensor library wayoda/LedControl schreibfaul1/ESP32-audioI2S 4.2 WiFi连接配置创建 secrets.h 文件(不要提交到公开仓库):#ifndef SECRETS_H #define SECRETS_H const char* WIFI_SSID = "你的WiFi名称"; const char* WIFI_PASSWORD = "你的WiFi密码"; // 可选:AI服务配置 const char* AI_API_KEY = "你的AI服务密钥"; const char* AI_API_URL = "你的AI服务地址"; #endif五、代码实现5.1 完整代码结构#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <DHT.h> #include <LedControl.h> #include <WiFi.h> #include <WebServer.h> #include "secrets.h" // OLED显示屏配置 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // 温湿度传感器配置 #define DHTPIN 15 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); // LED点阵配置 #define DIN_PIN 23 #define CS_PIN 5 #define CLK_PIN 18 LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, 1); // 触摸传感器配置 #define TOUCH_PIN 4 // 表情数组 const uint8_t happy_face[][8] = { {0x3C,0x42,0xA5,0x81,0xA5,0x99,0x42,0x3C}, // 开心 {0x3C,0x42,0xA5,0x81,0xA5,0x99,0x42,0x3C} }; // 全局变量 int current_emotion = 0; const char* emotion_names[] = {"开心", "生气", "伤心", "惊讶", "眨眼"}; unsigned long last_touch_time = 0; const unsigned long touch_debounce = 200; // 触摸防抖200ms // WiFi和Web服务器 WebServer server(80); void setup() { Serial.begin(115200); while(!Serial); Serial.println("ESP32桌面宠物启动中..."); initOLED(); initDHT(); initLedMatrix(); initTouch(); connectWiFi(); setupWebServer(); Serial.println("初始化完成!"); showStartupAnimation(); } void initOLED() { Wire.begin(21, 22); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED初始化失败!"); while(1); } display.clearDisplay(); display.display(); Serial.println("OLED初始化成功"); } void initDHT() { dht.begin(); Serial.println("DHT22初始化成功"); } void initLedMatrix() { lc.shutdown(0, false); lc.setIntensity(0, 8); lc.clearDisplay(0); Serial.println("LED点阵初始化成功"); } void initTouch() { pinMode(TOUCH_PIN, INPUT); Serial.println("触摸传感器初始化成功"); } void connectWiFi() { Serial.print("连接WiFi..."); WiFi.begin(WIFI_SSID, WIFI_PASSWORD); int attempts = 0; while(WiFi.status() != WL_CONNECTED && attempts < 20) { delay(500); Serial.print("."); attempts++; } if(WiFi.status() == WL_CONNECTED) { Serial.println("连接成功!"); Serial.print("IP地址: "); Serial.println(WiFi.localIP()); displayWiFiStatus(); } else { Serial.println("连接失败!请检查WiFi设置"); } } void loop() { server.handleClient(); if(digitalRead(TOUCH_PIN) == HIGH) { handleTouch(); } updateEnvironmentDisplay(); updateClockDisplay(); delay(100); } void handleTouch() { unsigned long current_time = millis(); if(current_time - last_touch_time < touch_debounce) { return; } last_touch_time = current_time; current_emotion = (current_emotion + 1) % 5; displayEmotion(current_emotion); Serial.print("切换到表情: "); Serial.println(emotion_names[current_emotion]); } void displayEmotion(int emotion) { display.clearDisplay(); switch(emotion) { case 0: // 开心 drawHappyFace(); break; case 1: // 生气 drawAngryFace(); break; case 2: // 伤心 drawSadFace(); break; case 3: // 惊讶 drawSurprisedFace(); break; case 4: // 眨眼 drawWinkFace(); break; } display.display(); } void drawHappyFace() { display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(2); display.setCursor(30, 20); display.println("开心O(∩_∩)O"); display.setTextSize(1); display.setCursor(20, 45); display.println("摸摸我,我会换表情哦~"); display.display(); } void updateEnvironmentDisplay() { static unsigned long last_update = 0; unsigned long current_time = millis(); if(current_time - last_update < 2000) return; last_update = current_time; float humidity = dht.readHumidity(); float temperature = dht.readTemperature(); if(isnan(humidity) || isnan(temperature)) { Serial.println("读取DHT22失败!"); return; } display.fillRect(0, 55, 128, 9, BLACK); display.setTextSize(1); display.setCursor(0, 55); display.print("温度:"); display.print(temperature, 1); display.print("C "); display.print("湿度:"); display.print(humidity, 1); display.print("%"); display.display(); } void displayWiFiStatus() { display.clearDisplay(); display.setTextColor(WHITE); display.setTextSize(1); display.setCursor(0, 10); display.println("WiFi已连接"); display.setCursor(0, 30); display.print("IP: "); display.println(WiFi.localIP()); display.display(); delay(3000); } void showStartupAnimation() { for(int i=0; i
2026年02月09日
1 阅读
0 评论
1 点赞