基于行空板与TB6612的扩展板遥控小车:硬件集成与Python控制实战

📅 2026/7/28 7:06:43
基于行空板与TB6612的扩展板遥控小车:硬件集成与Python控制实战
1. 项目缘起从一块“行空板”到一辆遥控小车最近在捣鼓行空板这块集成了屏幕、Wi-Fi、蓝牙和各种传感器的开发板确实给创客和教育项目带来了不少便利。但玩久了总觉得它“单打独斗”有点可惜。它的GPIO引脚、I2C接口和强大的处理能力完全有能力去控制更复杂的物理世界。于是一个想法冒了出来能不能给它加个“身体”让它动起来遥控小车就成了一个绝佳的选择。它综合了电机控制、无线通信、电源管理和结构设计是一个检验硬件集成和软件逻辑的完美项目。这个“行空板扩展板遥控小车”项目核心就是用行空板作为大脑通过一块自制的扩展板来连接和控制底盘、电机、传感器等外围设备最终实现通过手机或电脑进行无线遥控。听起来简单但里面涉及从电路设计、电源管理、电机驱动选型到无线通信协议、控制逻辑编写再到最后的机械组装和调试每一步都有不少门道。我折腾了大概两周从画原理图到代码调试再到最后下地跑起来踩了不少坑也总结了不少经验。这篇文章我就把这个项目的完整实现过程、核心原理和避坑要点分享出来无论你是想复现一个玩具还是学习硬件集成与嵌入式开发相信都能找到有用的东西。2. 核心架构设计为什么是“扩展板”“主控板”模式在开始动手之前我们先要理清整个系统的架构。为什么不能直接用行空板去接电机呢这里有几个关键原因也决定了我们必须要设计一块扩展板。2.1 行空板的接口与驱动能力局限行空板虽然接口丰富但其GPIO引脚的驱动电流非常有限通常只有几个毫安。而驱动小车电机哪怕是常用的N20减速电机所需的电流瞬间可以达到几百毫安甚至上安培直接连接会烧毁行空板的引脚或芯片。因此我们需要一个“中间人”——电机驱动模块来放大控制信号并提供大电流。其次行空板的电源输出能力也有限。其USB口或电池接口主要为自身和屏幕供电难以再为两个电机和可能的传感器稳定供电。我们需要一个独立的、功率足够的电源系统并为不同电压需求的模块如行空板的5V电机的3-6V进行稳压和分配。最后为了连接的可靠性和项目的整洁性把所有外围设备电机驱动、传感器、LED灯等的线都直接插在行空板上是不现实的会非常杂乱且容易松动。一块扩展板可以将这些连接固定化、标准化。2.2 扩展板的核心功能定义基于以上分析我们为扩展板定义了四大核心功能电源管理与分配接入一个7.4V的2S锂电池组。通过一个DC-DC降压模块如MP1584将其降至稳定的5V为行空板供电。同时电池电压直接供给电机驱动模块确保电机有足够的动力。扩展板上还需要有电源开关和状态指示灯。电机驱动接口集成一个双路H桥电机驱动芯片如TB6612FNG或DRV8833及其必要的外围电路。它接收来自行空板的PWM速度和方向控制信号输出大电流驱动两个直流电机。传感器与外围设备接口引出标准的I2C、UART接口和若干GPIO方便后续扩展超声波测距、巡线传感器、蓝牙/Wi-Fi模块等。例如可以预留一个I2C接口插座方便插拔OLED屏幕或IMU传感器。结构固定与信号连接通过排母与行空板的GPIO排针精准对接实现电气连接。同时扩展板的四角需要设计安装孔以便与小车底盘固定形成一个稳固的整体。这种架构的优势在于行空板专注于高级逻辑处理如网络通信、UI交互、算法而扩展板处理底层的、高电流的硬件驱动职责清晰也便于调试和迭代。3. 硬件选型与电路设计实战确定了架构接下来就是具体的硬件实现。这是项目中最“硬核”的部分也是决定小车性能与可靠性的基础。3.1 核心元器件选型与考量主控行空板本例基于行空板二代。它的Python环境、内置Wi-Fi和图形化编程能力是项目快速上手的保障。电机与车轮我选择了两个TT马达带减速箱和配套的轮子。TT马达价格低廉扭力适中适合在平地行驶。关键参数是工作电压3-6V和空载转速。如果需要更强动力或更精确的控制可以考虑带编码器的直流电机但成本和驱动复杂度会上升。电机驱动芯片TB6612FNG。这是我强烈推荐的型号。相比经典的L298N它的效率更高发热小支持更大的峰值电流1.2A每路而且内置了待机与短路保护。它需要3个控制信号来控制一个电机AIN1/AIN2方向和PWMA速度PWM。选择它能让你后续的代码更简洁性能更稳定。电源一块7.4V、1000mAh以上的2S锂电池。选择带有XT60或T插头的电池方便连接。务必配套一个平衡充电器这是安全使用锂电池的必须品。降压模块MP1584EN可调降压模块。它可以将电池的7.4V降至稳定的5V为行空板供电。其输出电流可达3A完全足够。小车底盘一个亚克力或金属的双层底盘套件。它提供了电机的安装位置、电池仓和扩展板的支撑柱省去了自己打孔定位的麻烦。3.2 扩展板原理图设计与要点使用立创EDALCEDA这类免费工具绘制原理图即可。核心部分如下电源输入与降压电路电池接口J1接入正负极并联一个100uF的电解电容C1进行电源滤波。电池电压通过一个拨动开关SW1控制通断开关后接一个电源指示灯LEDD1串联1kΩ限流电阻R1。电池电压一路VMOT直接连接到TB6612FNG的VM引脚电机电源。另一路接入MP1584模块的VIN其VOUT5V输出作为系统逻辑电压VCC为行空板、TB6612和所有逻辑器件供电。电机驱动电路TB6612FNG的VCC接系统VCC5VGND接系统地。VM接电池电压VMOT。AO1/AO2和BO1/BO2分别接左、右电机的正负极。AIN1/AIN2/BIN1/BIN2和PWMA/PWMB这六个控制引脚通过排针J2引出准备连接到行空板的GPIO。STBY待机引脚接高电平VCC通过一个10kΩ电阻R2上拉确保芯片正常工作。接口扩展将行空板上未使用的GPIO、I2CSDA, SCL、UARTTX, RX等信号线通过排针J3引出。为I2C总线预留两个4.7kΩ的上拉电阻R3, R4到VCC。所有GND网络连接在一起形成“星型”或“单点”接地减少数字噪声对模拟信号的干扰。注意在原理图中务必为电机驱动芯片的电源引脚VM和VCC附近放置去耦电容例如在VM和GND之间加一个100nF的陶瓷电容C2在VCC和GND之间加一个10uF的电解电容C3和一个100nF的陶瓷电容C4。这能有效抑制电机启停时产生的电压尖峰是保证系统稳定的关键细节很多初学者会忽略。3.3 PCB设计与打样原理图检查无误后转入PCB设计。这里有几个实践心得布局电源模块、电机驱动芯片这些发热或大电流的部件要分散放置避免热量集中。电池接口、电机接线端子这些需要经常插拔的部件尽量放在板子边缘。走线电机驱动部分的电源线VMOT到VMAO1/AO2到电机接口要加粗建议使用40mil约1mm以上的线宽。逻辑信号线可以用8-10mil。加粗电源线能减少线路阻抗降低压降和发热。安装孔根据你选择的小车底盘精确设置四个M3螺丝的安装孔位置。可以在立创EDA的“放置”-“焊盘”中设置非金属化孔。丝印清晰标注所有接口的功能如“BAT”、“MOTOR_L”、“SDA”、“5V_OUT”等。这会在焊接和调试时省去大量查图的时间。设计完成后可以将Gerber文件发给PCB打样厂如嘉立创制作通常5块钱就能做10块板子非常划算。4. 焊接、组装与系统集成收到PCB和元器件后就进入动手环节。焊接和组装顺序很重要。4.1 焊接顺序与技巧先矮后高先焊接电阻、电容、芯片底座如果使用、排针等矮小的元件。焊接芯片TB6612FNG是贴片芯片。对于新手可以使用热风枪和焊锡膏或者仔细地用烙铁拖焊。务必注意芯片方向PCB上的白丝印圆点应对准芯片的凹坑或圆点。焊接模块与接口焊接DC-DC降压模块、电源开关、LED、电机接线端子如XT30母座和与行空板对接的排母。排母焊接时要保持与PCB垂直否则可能导致与行空板连接不牢。检查与清理焊接完成后用万用表的蜂鸣档仔细检查所有电源网络VMOTVCCGND是否短路。再用酒精和棉签清理板上的助焊剂。4.2 机械组装步骤安装电机与车轮将TT马达用螺丝固定在小车底盘指定的位置并装上车轮。注意左右轮的对称性。固定扩展板使用尼龙柱和螺丝将焊接好的扩展板固定在小车底盘的上层。连接行空板将行空板通过排针稳稳地插在扩展板的排母上。确保所有引脚对齐且接触良好。连接电机与电源将左右电机的线分别接到扩展板的电机接线端子上。此时先不要接电池。将电池插头接到扩展板的电池接口。整体布线用扎带或理线槽将电池、多余的线材整理好避免缠绕进车轮。4.3 上电前关键检查在接通电池开关前必须进行“望闻问切”望再次目视检查有无焊锡短路、元件焊反特别是LED、电解电容。闻准备上电鼻子靠近板子如有异味立即断电。问用万用表测量电池接口电压是否正常约7.4V-8.4V。测量VCC5V输出对地是否短路。切首次上电时不要安装电机。先打开电池开关观察电源指示灯LED是否亮起。用手触摸TB6612芯片和降压模块是否在几秒内异常发烫。用万用表测量VCC电压是否为稳定的5V左右。如果一切正常关闭电源接上电机准备进行功能测试。5. 软件控制逻辑与代码实现硬件就绪后大脑行空板需要发出正确的指令。我们将通过Python编程来实现遥控功能。这里以使用行空板内置的Wi-Fi和Web服务实现网页遥控为例。5.1 电机驱动底层库封装首先我们需要一个驱动TB6612FNG的Python类将硬件的控制抽象成简单的接口。# motor_driver.py import time from pinpong.board import Board, Pin from pinpong.extension.unihiker import * class DCMotorDriver: def __init__(self, in1_pin, in2_pin, pwm_pin): 初始化一个电机通道 :param in1_pin: 方向引脚1 (如 Pin.P15) :param in2_pin: 方向引脚2 (如 Pin.P16) :param pwm_pin: PWM速度引脚 (如 Pin.P22) Board().begin() self.in1 Pin(in1_pin, Pin.OUT) self.in2 Pin(in2_pin, Pin.OUT) self.pwm Pin(pwm_pin, Pin.PWM) self.speed 0 # 当前速度范围 -100 ~ 100 def _set_direction(self, speed): 根据速度正负设置方向引脚 if speed 0: self.in1.write_digital(1) self.in2.write_digital(0) elif speed 0: self.in1.write_digital(0) self.in2.write_digital(1) else: # 停止 self.in1.write_digital(0) self.in2.write_digital(0) def set_speed(self, speed): 设置电机速度 :param speed: -100 ~ 100负数为反转 # 限制速度范围 speed max(-100, min(100, speed)) self.speed speed # 设置方向 self._set_direction(speed) # 设置PWM占空比 (0-100 映射到 0-1023) pwm_value int(abs(speed) * 10.23) self.pwm.write_analog(pwm_value) def stop(self): 刹车停止 (快速停止) self.in1.write_digital(1) self.in2.write_digital(1) self.pwm.write_analog(0) self.speed 0 time.sleep(0.05) # 保持刹车状态一小段时间 self.in1.write_digital(0) self.in2.write_digital(0) # 全局电机对象根据你的实际接线修改引脚号 motor_left DCMotorDriver(Pin.P15, Pin.P16, Pin.P22) # AIN1, AIN2, PWMA motor_right DCMotorDriver(Pin.P13, Pin.P14, Pin.P21) # BIN1, BIN2, PWMB这个类封装了电机的控制细节。set_speed方法同时处理了方向和速度。stop方法使用了TB6612的“短路刹车”功能能让电机快速停下比单纯设置速度为0响应更快。5.2 网页遥控服务器与交互逻辑接下来我们利用行空板内置的unihiker库和aiohttp来创建一个简单的Web服务器提供一个遥控界面。# remote_car_main.py import uasyncio as asyncio from aiohttp import web import json from motor_driver import motor_left, motor_right # 小车控制逻辑 def car_control(cmd, valueNone): 根据命令控制小车 if cmd stop: motor_left.stop() motor_right.stop() print(Car STOP) elif cmd forward: motor_left.set_speed(70) # 设置一个基础速度 motor_right.set_speed(70) print(Car FORWARD) elif cmd backward: motor_left.set_speed(-70) motor_right.set_speed(-70) print(Car BACKWARD) elif cmd left: # 左转右轮正转左轮慢速正转或反转 motor_left.set_speed(30) motor_right.set_speed(70) print(Car TURN LEFT) elif cmd right: motor_left.set_speed(70) motor_right.set_speed(30) print(Car TURN RIGHT) elif cmd speed: # 动态调整速度value 来自滑杆 if value is not None: base_speed int(value) # 根据当前左右电机的速度比例来调整 left_ratio motor_left.speed / 100 if motor_left.speed ! 0 else 1 right_ratio motor_right.speed / 100 if motor_right.speed ! 0 else 1 motor_left.set_speed(int(base_speed * left_ratio)) motor_right.set_speed(int(base_speed * right_ratio)) print(fSpeed set to: {base_speed}) # 定义HTTP请求处理 async def handle_control(request): data await request.json() cmd data.get(cmd) value data.get(value) car_control(cmd, value) return web.Response(textjson.dumps({status: ok})) async def handle_index(request): # 返回一个简单的HTML遥控页面 html !DOCTYPE html html head title行空板遥控小车/title meta nameviewport contentwidthdevice-width, initial-scale1.0 style body { text-align: center; font-family: Arial; margin: 20px; } .control-panel { margin: 30px auto; width: 300px; } .btn { width: 80px; height: 80px; margin: 5px; font-size: 24px; border: none; border-radius: 10px; background: #4CAF50; color: white; } .btn:active { background: #45a049; } #stopBtn { background: #f44336; } #stopBtn:active { background: #d32f2f; } .slider-container { margin-top: 20px; } #speedValue { font-weight: bold; } /style /head body h2行空板遥控小车控制台/h2 div classcontrol-panel div button classbtn idforwardBtn ontouchstartsendCmd(forward) ontouchendsendCmd(stop)↑/button /div div button classbtn idleftBtn ontouchstartsendCmd(left) ontouchendsendCmd(stop)←/button button classbtn idstopBtn onclicksendCmd(stop)停/button button classbtn idrightBtn ontouchstartsendCmd(right) ontouchendsendCmd(stop)→/button /div div button classbtn idbackwardBtn ontouchstartsendCmd(backward) ontouchendsendCmd(stop)↓/button /div div classslider-container p速度调节: span idspeedValue70/span%/p input typerange min30 max100 value70 classslider idspeedSlider oninputupdateSpeed(this.value) /div /div script function sendCmd(cmd, valuenull) { fetch(/control, { method: POST, headers: {Content-Type: application/json}, body: JSON.stringify({cmd: cmd, value: value}) }); } function updateSpeed(val) { document.getElementById(speedValue).textContent val; sendCmd(speed, val); } // 键盘控制支持 document.addEventListener(keydown, (e) { switch(e.key) { case ArrowUp: sendCmd(forward); break; case ArrowDown: sendCmd(backward); break; case ArrowLeft: sendCmd(left); break; case ArrowRight: sendCmd(right); break; case : sendCmd(stop); break; } }); document.addEventListener(keyup, (e) { if([ArrowUp,ArrowDown,ArrowLeft,ArrowRight].includes(e.key)) { sendCmd(stop); } }); /script /body /html return web.Response(texthtml, content_typetext/html) # 创建并运行Web服务器 async def main(): app web.Application() app.router.add_get(/, handle_index) app.router.add_post(/control, handle_control) runner web.AppRunner(app) await runner.setup() site web.TCPSite(runner, 0.0.0.0, 80) # 监听所有IP端口80 print(遥控服务器已启动) print(请在浏览器访问行空板的IP地址例如: http://192.168.x.x) await site.start() while True: await asyncio.sleep(3600) # 永久运行 # 启动 try: asyncio.run(main()) except KeyboardInterrupt: motor_left.stop() motor_right.stop() print(程序退出小车已停止。)这段代码创建了一个Web服务器。当你用手机或电脑连接到行空板的热点或同一局域网后在浏览器输入行空板的IP地址就能看到一个带有方向按钮和速度滑杆的控制界面。按下按钮发送指令松开或按停止键发送停止指令实现了基本的遥控功能。6. 调试、优化与进阶玩法代码跑起来小车能动只是第一步。要让小车跑得稳、跑得聪明还需要一番调试和优化。6.1 常见问题排查与调试电机不转或只单向转检查接线首先确认电机线是否接牢正负极是否接反。可以调换电机线测试。检查控制信号用万用表测量行空板GPIO在控制时是否有电压变化方向引脚应为0V或3.3VPWM引脚应有平均电压变化。或者用行空板自带的“引脚状态”可视化工具查看。检查电源测量电机驱动芯片的VM引脚是否有电池电压~7.4VVCC是否有5V。电机堵转时电流很大可能导致电压被拉低。检查代码引脚定义确保motor_driver.py中初始化DCMotorDriver的引脚号与实际物理连接完全一致。这是最容易出错的地方。小车跑偏这是几乎必然会出现的问题。因为两个电机的性能不可能完全一致。软件校准在代码中为左右电机设置一个速度补偿系数。例如如果小车总是右偏可以尝试motor_left.set_speed(70 * 1.05)motor_right.set_speed(70 * 0.95)通过微调系数来平衡。供电影响电池电量不足时左右电机电压可能不平衡加剧跑偏。保持电池电量充足。网页控制延迟或卡顿确保遥控设备和行空板处于良好的Wi-Fi信号范围内。检查行空板是否运行了过多其他程序占用了CPU和网络资源。优化前端代码避免频繁发送请求。上面的代码使用了“按下发送指令松开发送停止”的方式已经比持续轮询要好。6.2 性能与功能优化PID速度控制上述代码是开环控制电机速度受电池电压、负载影响大。可以尝试为电机增加编码器需选择带编码器的电机通过测量实际转速使用PID算法来闭环控制速度让小车行驶更精准。摇杆控制将网页上的方向按钮替换为虚拟摇杆可以使用nipplejs等库实现更平滑、更符合直觉的比例控制即摇杆偏移量对应电机速度。视频图传利用行空板的USB接口连接一个USB摄像头通过MJPG-streamer等工具实现实时视频流传输在网页控制台上就能看到小车前方的画面实现第一人称视角FPV驾驶。自动避障在扩展板上接入一个HC-SR04超声波模块编写代码让小车在前进时持续测距遇到障碍物自动转向或停止。手机APP控制不使用网页而是用MIT App Inventor或Kivy等工具开发一个简单的手机APP通过蓝牙或Wi-Fi与行空板通信体验更原生。6.3 电源管理与安全建议电池安全锂电池切忌过充过放。使用平衡充电器充电长时间不用时请将电池储存电压保持在3.8V左右单片。小车不用时务必关闭扩展板上的电源开关。电压监测可以在扩展板上增加一个电阻分压电路将电池电压分压后接入行空板的ADC引脚编写代码监测电池电压并在电量低时通过屏幕或网页发出警告。保险丝在电池正极输入到扩展板的主干路上串联一个5A或10A的自恢复保险丝可以在电机堵转等意外短路时保护电池和电路板。折腾完这个项目最大的体会是硬件项目就是一个不断“发现问题-解决问题”的循环。从原理图上一个电容的遗漏到代码里一个引脚号的笔误再到组装时一颗螺丝的松动都可能让小车“趴窝”。但正是这个过程让你对电流怎么走、信号怎么传、代码如何驱动硬件有了切身的理解。当看到自己设计焊接的板子搭载着行空板乖乖地听从网页指令前进后退时那种成就感是纯软件项目无法比拟的。这个扩展板小车项目就像一个基础平台上面提到的避障、图传、PID控制等进阶玩法都可以在此基础上一步步添加乐趣无穷。