
1. 项目概述从钓鱼佬的痛点到一个硬核DIY项目作为一个喜欢折腾电子和机械的玩家我经常琢磨怎么把技术用到生活里。这次的项目灵感就来自一个看似不搭界的场景——钓鱼。很多钓鱼爱好者尤其是玩“打窝”的都有个共同的烦恼想把诱饵精准、省力地投到远处的窝点手动抛投要么不准要么累人。市面上有专门的“打窝船”但价格不菲功能也未必完全符合个人需求。于是一个想法冒了出来能不能自己动手做一台低成本、可遥控、还能根据需求调整投喂模式的智能喂鱼打窝小车这个想法很快落地成了一个具体的项目一台基于ESP32微控制器的遥控两速全轮驱动车。它不仅仅是个玩具车更是一个集成了无线控制、动力分配、投饵机构于一体的移动平台。核心是利用ESP32强大的Wi-Fi和蓝牙功能实现手机或遥控器的灵活控制通过双电机差速实现转向并设计了两档速度以适应不同地形最终通过一个舵机控制的翻斗或螺旋推进器完成饵料的精准投放。整个车体结构可以通过3D打印定制让每个部件都严丝合缝。这不仅仅解决了钓鱼的痛点更是一个绝佳的嵌入式系统、无线通信、电机控制和3D建模的综合性实践项目。2. 核心设计思路与方案选型2.1 为什么是ESP32在众多微控制器中选择ESP32作为主控是经过深思熟虑的。首先项目核心需求是无线遥控ESP32集成了双模蓝牙和Wi-Fi这意味着你可以有非常灵活的控制方案选择既可以用经典的蓝牙手柄或手机APP通过蓝牙连接实现低延迟、一对一的直接控制也可以让小车接入本地Wi-Fi网络通过网页或MQTT协议进行控制这样控制距离可以更远取决于Wi-Fi路由器的覆盖范围甚至可以实现简单的编队或多设备管理。其次ESP32拥有双核处理器主频高达240MHz性能远超普通的Arduino Uno可以轻松处理电机PWM控制、舵机信号生成、传感器数据读取如后续想加装超声波避障或摄像头图传以及无线通信协议栈确保系统运行流畅不卡顿。最后其丰富的GPIO、ADC、PWM等外设接口足以驱动两个直流电机、一个舵机以及若干状态指示灯无需额外的扩展板简化了硬件设计。注意ESP32的GPIO并非全部都可以直接使用有些引脚在启动时有特殊功能如GPIO0、GPIO2等用于启动模式判断。在分配电机驱动、舵机等关键功能引脚时务必查阅官方引脚定义图避开这些“敏感”引脚通常选择GPIO12、13、14、25、26、27等作为PWM输出是相对安全的选择。2.2 两速全轮驱动的实现逻辑“两速全轮驱动”听起来很专业其实原理很直观。这里的“全轮驱动”指的是两个后轮分别由独立的电机驱动通过差速实现转向即坦克式的差速转向而非使用前轮转向机构。这样做的好处是结构简单、转向灵活、越障能力强非常适合在草地、滩涂等非铺装路面行驶。“两速”则是指电机有两种速度模式。这并不是通过复杂的机械变速箱实现的而是通过软件控制电机的PWM占空比来实现的。我们可以定义两个档位低速档PWM占空比设置在30%-50%。适用于精细操作比如靠近水边准备投饵时需要缓慢移动以精确定位避免冲过头掉水里。高速档PWM占空比设置在70%-100%。适用于长距离空载行驶快速从岸边抵达预设的窝点节省时间和电量。在软件中只需映射两个不同的按钮或摇杆区间到不同的PWM值即可。同时为了提升低速下的扭矩让小车更有劲建议搭配使用减速电机。我选用的是TT马达自带减速箱它在低PWM下也能提供不错的启动扭矩。2.3 投饵机构的设计权衡投饵机构是整个项目的“执行末端”直接关系到功能成败。我主要评估了两种主流方案翻斗式在车体上方安装一个由舵机控制的翻斗。到达点位后舵机旋转一定角度将斗内的饵料倒出。优点是结构简单、易于3D建模和打印动作可靠。缺点是投饵量固定且可能因为车身晃动导致散布不够集中。螺旋推进式利用一个微型直流电机驱动螺旋杆将存放在料仓中的饵料定量推出。优点是可以实现相对精准的定量投喂甚至通过控制电机转动时间来控制投饵量。缺点是结构稍复杂需要设计密封性较好的料仓和出料口防止饵料受潮结块卡住螺旋杆。考虑到首版原型机的可靠性和制作难度我选择了翻斗式。使用一个9g或20kg.cm的舵机具体扭力根据翻斗大小和饵料重量决定来控制翻斗的翻转动作。通过3D打印一个带有合页结构的翻斗和底座确保转动顺滑。2.4 车体与电源系统规划车体是整个设备的骨架。使用3D打印来制作底盘、电机座、电池仓和翻斗支架可以实现高度定制化。设计时需重点考虑重心电池通常是18650锂电池组应放置在底盘中部偏低的位置以降低重心防止翻车。防水与防尘虽然不要求完全潜水但需要应对水边溅水和灰尘。可以在电子仓部分设计盖板并预留出线孔后期用热熔胶或硅胶进行密封。电机轴和舵机转轴处是防水的难点。离地间隙根据预定的行驶环境草地、沙石设置足够的离地间隙。电源方面驱动两个TT电机和一个ESP32需要足够的电流。建议使用2节或3节18650锂电池串联7.4V或11.1V供电。需要注意的是ESP32和舵机的工作电压通常是5V或3.3V而电机直接使用电池电压。因此需要一个双路输出的电源模块一路DC-DC降压模块将电池电压降至5V给ESP32和舵机供电另一路直接或通过电机驱动板给电机供电。务必确保电源模块的持续输出电流能满足所有设备峰值需求建议留有余量。3. 硬件搭建与核心电路解析3.1 物料清单与工具准备在开始动手前请准备好以下核心物料和工具电子部分ESP32开发板如NodeMCU-32S或ESP32-DevKitC x1TT减速电机带车轮 x2电机驱动模块如L298N、TB6612FNG或DRV8833 x19g或更大扭力的舵机 x118650锂电池带保护板及电池盒 x2-3节DC-DC降压模块输出5V电流至少2A x1开关 x1杜邦线公对公、公对母若干可能需要的传感器如超声波模块HC-SR04用于避障此为可选升级项结构部分3D打印的底盘、电机支架、电池仓、舵机支架、翻斗组件需自行设计或寻找开源模型螺丝、螺母、扎带等紧固件工具电烙铁及焊锡螺丝刀套装剥线钳万用表电脑用于编程和3D建模3.2 电机驱动电路连接详解电机驱动模块是连接ESP32弱电控制信号和TT电机强电动力的桥梁。这里以常用的TB6612FNG模块为例因为它体积小、效率高、发热低。电源连接将锂电池组的正负极VM连接到TB6612的VM和GND端子为电机提供动力电源例如7.4V。将DC-DC降压模块输出的5VVCC和GND连接到TB6612的VCC和GND端子为驱动芯片本身提供逻辑电源。务必确保两个电源的GND是共地的用万用表测量确认。控制信号连接每个电机需要三个控制信号AIN1/AIN2或BIN1/BIN2控制转向PWMA/PWMB控制速度。将ESP32的GPIO引脚例如GPIO12, GPIO13连接到电机的AIN1和AIN2将另一个GPIO例如GPIO14连接到PWMA。同理连接另一个电机的BIN1、BIN2和PWMB到ESP32的另外三个GPIO例如GPIO25, GPIO26, GPIO27。TB6612的STBY待机引脚需要接高电平如直接接5V电机才能工作。电机输出连接将两个TT电机分别连接到TB6612的A01/A02和B01/B02输出端子。如果电机转动方向与预期相反只需交换这两个端子的接线即可。实操心得在焊接电机线到驱动板端子前最好先用电工胶布或热缩管处理好线头防止后续短路。另外建议在电池电源入口处加一个开关并在开关后、驱动板前并联一个470uF或更大的电解电容可以吸收电机启停时产生的电压尖峰让系统更稳定。3.3 ESP32最小系统与舵机连接ESP32的开发板通常已经集成了USB转串口芯片和复位电路我们只需关注其供电和信号引脚。供电使用DC-DC降压模块提供的5V和GND连接到ESP32开发板的VIN或5V和GND引脚。切勿将高于5V的电压直接接入ESP32的3.3V引脚舵机连接舵机有三根线电源红接5V、地线棕/黑接GND、信号线橙/白。信号线连接到ESP32的一个GPIO引脚例如GPIO15。ESP32的硬件PWM功能可以很好地驱动舵机。3.4 3D打印结构件设计与装配要点车体设计是机械部分的灵魂。使用Fusion 360或SolidWorks等软件进行建模时需注意预留安装孔为ESP32开发板、电机驱动板、电池仓、舵机等所有电子部件设计准确的安装孔和卡槽。可以先将这些元件的尺寸量好在软件中建立简单的实体模型再进行布尔运算或绘制定位孔。考虑打印工艺3D打印FDM有其局限性如悬垂部分需要支撑受力部分打印方向影响强度。对于底盘这类承重件建议设置较高的填充率如30%-40%并确保其底面与打印平台接触的面是最大平面以增加附着力。电机座与底盘的连接处可以设计加强筋。装配顺序建议的装配顺序是先将TT电机用螺丝固定在电机支架上然后将支架安装到底盘。接着安装电池仓和主要电路板。最后安装舵机和翻斗组件。在拧紧螺丝前确保所有线缆都预留了足够的长度和走线空间。4. 软件编程与核心逻辑实现4.1 开发环境搭建与库文件准备我们使用Arduino IDE进行开发因为它对ESP32的支持已经非常成熟且库生态丰富。安装Arduino IDE从官网下载并安装最新版。添加ESP32开发板支持打开文件-首选项在“附加开发板管理器网址”中输入https://espressif.github.io/arduino-esp32/package_esp32_index.json。然后打开工具-开发板-开发板管理器搜索“esp32”安装“Espressif Systems”提供的包。安装所需库本项目主要需要两个库ESP32Servo用于更稳定地控制舵机。可以通过库管理器搜索安装。对于遥控部分如果使用蓝牙可能需要BluetoothSerial库通常已内置如果使用Wi-Fi网页控制则需要WebServer和WiFi库也已内置。4.2 蓝牙遥控与电机控制程序剖析这里以蓝牙串口遥控为例因为它简单直接延迟低。我们假设使用一个普通的蓝牙串口APP当按下按钮时APP会发送特定的字符如‘F’代表前进‘L’代表左转。#include BluetoothSerial.h #include ESP32Servo.h // 电机驱动引脚定义 #define MOTOR_A_IN1 12 #define MOTOR_A_IN2 13 #define MOTOR_A_PWM 14 #define MOTOR_B_IN1 25 #define MOTOR_B_IN2 26 #define MOTOR_B_PWM 27 // 舵机引脚定义 #define SERVO_PIN 15 // 速度档位定义 (PWM值范围0-255) #define LOW_SPEED 100 #define HIGH_SPEED 200 BluetoothSerial SerialBT; Servo myServo; // 创建舵机对象 char currentSpeedMode L; // 默认低速模式 L, 高速模式 H int currentSpeed LOW_SPEED; void setup() { Serial.begin(115200); // 初始化电机控制引脚为输出 pinMode(MOTOR_A_IN1, OUTPUT); pinMode(MOTOR_A_IN2, OUTPUT); pinMode(MOTOR_A_PWM, OUTPUT); pinMode(MOTOR_B_IN1, OUTPUT); pinMode(MOTOR_B_IN2, OUTPUT); pinMode(MOTOR_B_PWM, OUTPUT); // 停止所有电机 stopMotors(); // 初始化舵机 myServo.attach(SERVO_PIN); myServo.write(0); // 初始位置翻斗收起 delay(1000); // 初始化蓝牙 SerialBT.begin(ESP32_FishFeeder); // 蓝牙设备名称 Serial.println(蓝牙已启动等待连接...); } void loop() { if (SerialBT.available()) { char command SerialBT.read(); Serial.write(command); // 在串口监视器回显 switch(command) { case F: // 前进 setMotor(MOTOR_A_IN1, MOTOR_A_IN2, MOTOR_A_PWM, currentSpeed); setMotor(MOTOR_B_IN1, MOTOR_B_IN2, MOTOR_B_PWM, currentSpeed); break; case B: // 后退 setMotor(MOTOR_A_IN1, MOTOR_A_IN2, MOTOR_A_PWM, -currentSpeed); setMotor(MOTOR_B_IN1, MOTOR_B_IN2, MOTOR_B_PWM, -currentSpeed); break; case L: // 左转 setMotor(MOTOR_A_IN1, MOTOR_A_IN2, MOTOR_A_PWM, -currentSpeed); setMotor(MOTOR_B_IN1, MOTOR_B_IN2, MOTOR_B_PWM, currentSpeed); break; case R: // 右转 setMotor(MOTOR_A_IN1, MOTOR_A_IN2, MOTOR_A_PWM, currentSpeed); setMotor(MOTOR_B_IN1, MOTOR_B_IN2, MOTOR_B_PWM, -currentSpeed); break; case S: // 停止 stopMotors(); break; case H: // 切换高速模式 currentSpeedMode H; currentSpeed HIGH_SPEED; SerialBT.println(High Speed Mode); break; case L: // 切换低速模式 currentSpeedMode L; currentSpeed LOW_SPEED; SerialBT.println(Low Speed Mode); break; case D: // 翻斗动作投饵 myServo.write(90); // 翻转90度 delay(1000); // 保持1秒确保倒完 myServo.write(0); // 复位 break; default: break; } } } // 设置单个电机速度和方向的函数 void setMotor(int in1, int in2, int pwmPin, int speed) { if(speed 0) { digitalWrite(in1, HIGH); digitalWrite(in2, LOW); analogWrite(pwmPin, abs(speed)); } else if(speed 0) { digitalWrite(in1, LOW); digitalWrite(in2, HIGH); analogWrite(pwmPin, abs(speed)); } else { digitalWrite(in1, LOW); digitalWrite(in2, LOW); analogWrite(pwmPin, 0); } } // 停止所有电机 void stopMotors() { setMotor(MOTOR_A_IN1, MOTOR_A_IN2, MOTOR_A_PWM, 0); setMotor(MOTOR_B_IN1, MOTOR_B_IN2, MOTOR_B_PWM, 0); }代码逻辑解析setup()函数中初始化了所有硬件并将蓝牙名称设为“ESP32_FishFeeder”。loop()函数不断检查蓝牙是否有数据到来。根据接收到的字符命令调用setMotor函数控制两个电机正转、反转或差速转动实现前进、后退、左右转和停止。setMotor函数是核心它根据传入的speed正负值决定电机转向并通过analogWrite输出PWM值控制速度。analogWrite在ESP32上可以产生0-255范围的PWM信号。命令‘H’和‘L’用于切换全局速度变量currentSpeed从而实现两档调速。命令‘D’控制舵机执行一次翻转-复位的动作完成投饵。4.3 Wi-Fi网页控制方案拓展如果你希望控制距离更远或者想在手机浏览器上用一个更美观的界面来控制Wi-Fi网页方案是更好的选择。其核心是让ESP32作为一个Web服务器手机连接同一个Wi-Fi后通过浏览器访问ESP32的IP地址得到一个带有控制按钮的网页。#include WiFi.h #include WebServer.h const char* ssid 你的Wi-Fi名称; const char* password 你的Wi-Fi密码; WebServer server(80); // 在80端口创建服务器 void handleRoot() { // 返回一个简单的HTML控制页面 String html !DOCTYPE htmlhtmlheadmeta name\viewport\ content\widthdevice-width, initial-scale1\; html stylebutton {margin:10px; padding:20px; font-size:20px;}/style/headbody; html h1智能喂鱼车控制/h1; html button onclick\sendCmd(F)\前进/buttonbr; html button onclick\sendCmd(L)\左转/button; html button onclick\sendCmd(S)\停止/button; html button onclick\sendCmd(R)\右转/buttonbr; html button onclick\sendCmd(B)\后退/buttonbr; html button onclick\sendCmd(H)\高速/button; html button onclick\sendCmd(LOW)\低速/buttonbr; // 注意这里用LOW避免和左转冲突 html button onclick\sendCmd(D)\投饵/button; html scriptfunction sendCmd(cmd) { fetch(/cmd?value cmd); }/script; html /body/html; server.send(200, text/html, html); } void handleCmd() { String cmdValue server.arg(value); // 这里可以调用之前蓝牙控制部分相同的电机和舵机控制函数 // 例如if(cmdValue \F\) { ... } server.send(200, text/plain, OK: cmdValue); } void setup() { // ... 初始化电机、舵机等硬件同前 WiFi.begin(ssid, password); while (WiFi.status() ! WL_CONNECTED) { delay(500); Serial.print(.); } Serial.println(); Serial.print(已连接IP地址: ); Serial.println(WiFi.localIP()); server.on(/, handleRoot); server.on(/cmd, handleCmd); server.begin(); } void loop() { server.handleClient(); // 处理客户端请求 // 原有的控制逻辑可以整合到这里根据从网页接收的命令行动 }这个示例提供了一个基础框架。你需要将之前蓝牙控制代码中的电机和舵机控制逻辑整合进来在handleCmd函数中根据cmdValue执行相应动作。网页控制的好处是界面可以自定义得非常丰富甚至可以加入实时视频流需额外摄像头模块或GPS定位显示。5. 系统调试、问题排查与优化心得5.1 上电调试流程与常见故障组装完成后不要急于把所有东西装进车里。建议分步上电调试最小系统测试仅连接ESP32和电源通过串口监视器查看启动日志确认其能正常启动并连接Wi-Fi或蓝牙。电机单独测试将一个电机连接到驱动板编写一个简单的测试程序让电机正转、反转、调速。确认接线正确电机响应正常。舵机测试单独测试舵机确认它能平滑地转动到指定角度。集成遥控测试将所有部件连接好但先不固定到车架上。运行完整的控制程序通过手机APP或网页发送指令观察电机和舵机是否按预期动作。整车路试将电子设备固定到3D打印的车架上进行实地行驶和投饵测试。注意在平坦、安全的地面进行。常见问题与排查现象可能原因排查步骤电机不转1. 电源未接通或电压不足。2. 电机驱动板逻辑电源未接或使能端STBY未拉高。3. ESP32控制引脚定义错误或未设置为输出模式。4. 程序PWM值始终为0。1. 用万用表测量电机驱动板VM和VCC电压。2. 检查STBY引脚接线。3. 检查pinMode设置和digitalWrite/analogWrite调用。4. 在串口监视器打印调试信息确认收到控制命令。电机只朝一个方向转电机驱动板的IN1/IN2控制逻辑接反或程序逻辑错误。检查setMotor函数中speed0和speed0时IN1和IN2的电平设置是否正确。可以交换IN1和IN2的接线测试。舵机抖动或不转1. 电源功率不足特别是多个舵机或电机同时工作时。2. 信号线接触不良。3. 舵机扭矩不够被机械结构卡住。1. 单独给舵机供电测试。2. 检查接线尝试更换信号线引脚。3. 手动转动舵机臂检查是否有阻碍考虑更换更大扭矩舵机。蓝牙/Wi-Fi连接不稳定1. 距离过远或有遮挡。2. 2.4GHz频段干扰如很多Wi-Fi设备。3. ESP32天线位置不佳或被金属屏蔽。1. 靠近测试。2. 尝试更换Wi-Fi信道或使用蓝牙。3. 确保ESP32板载天线区域未被金属件覆盖。小车跑偏两个电机的实际转速不一致即使PWM值相同。这是TT马达的通病。可以在软件中为两个电机设置微调系数。例如如果小车右偏可以略微调低右侧电机的PWM值或调高左侧的PWM值直到直线行驶。5.2 功耗优化与续航提升技巧对于移动设备续航是关键。静态功耗在代码中当小车长时间不动时可以让ESP32进入轻睡眠模式仅通过外部中断如蓝牙信号唤醒来激活。这需要更复杂的程序设计。动态功耗选择高效率的DC-DC降压模块如同步整流型。在电机不转动时确保程序确实将电机驱动板的输入引脚设置为低电平或高阻态避免电机驱动芯片产生静态功耗。电池选择使用高品质、高容量的18650电池如三星35E、松下NCR18650B。如果空间允许可以考虑并联一组电池来增加容量。机械阻力确保车轮转动顺滑传动轴没有卡滞。过大的机械阻力会白白消耗电量。5.3 防水防潮处理经验水边环境潮湿必须做好防护。电子仓3D打印的壳体本身不防水。可以在内部关键电路板如ESP32、驱动板上喷涂三防漆这是一种绝缘的涂层能有效防潮、防腐蚀。注意避开连接器和按钮。接口与开孔所有线缆进出外壳的位置使用防水格兰头或打上硅胶密封。舵机转轴处可以套上小的热缩管或涂抹润滑脂非导电性来阻隔水汽。电机TT电机本身不是防水的。一个折中的办法是用气球或避孕套套住电机用扎带扎紧口部能提供一定程度的防护。更专业的做法是购买防水型的直流减速电机。终极方案可以为整个电子仓设计一个O型圈密封的盖子制作一个真正防水的舱体。5.4 功能扩展思路基础功能实现后这个平台还有巨大的扩展潜力自动巡航与定点投喂加装GPS模块如Neo-6M结合电子罗盘可以记录航点。实现“一键自动”航行到预设的经纬度点并投饵。避障功能在车头加装超声波传感器HC-SR04或TOF激光测距在程序中加入简单的逻辑遇到障碍物自动停止或绕行。状态回传通过Wi-Fi将小车的电池电压、实时位置、行驶状态等信息发送回手机APP或服务器实现状态监控。图传系统加装一个ESP32-CAM模块通过Wi-Fi实时传输第一视角画面让你在岸边就能看清窝点情况。这个项目从构思到实现充满了动手的乐趣和解决问题的成就感。它不仅仅是一个“钓鱼神器”更是一个涵盖了电子、编程、机械、3D打印的微型工程实践。当你看到自己制作的小车按照指令在水边驰骋并完成投饵时那种满足感远超购买一件成品。最重要的是在这个过程中积累的经验和解决问题的能力是任何现成产品都无法给予的。