
机器人嵌入式硬件开发移动开发【免费下载链接】foc-wheel-legged-robotOpen source materials for a novel structured legged robot, including mechanical design, electronic design, algorithm simulation, and software development. | 一个新型结构的轮腿机器人开源资料包含机械设计、电子设计、算法仿真、软件开发等材料项目地址https://gitcode.com/gh_mirrors/fo/foc-wheel-legged-robot点击查看免费下载本文基于 esp32-controller/README.md 及仓库源码 esp32-controller/software/src/main.cpp 编写是 foc-wheel-legged-robot 项目中控制层核心模块的技术指南。该主控板承载整台轮腿机器人的大脑职能读取陀螺仪姿态、运行平衡与腿部控制算法、通过 CAN 总线与驱动板交换电机数据、通过低功耗蓝牙接收上位机遥控指令。读完本文你将掌握该主控板的硬件方案与文件构成、PlatformIO 工程的多任务软件架构、烧录与调试流程以及决定控制成败的三类关键参数零点偏移、扭矩系数、反电动势函数的标定方法。一、模块定位整台机器人的控制中枢在原项目 README 中ESP32 主控板被明确描述为本机器人项目最重要的一个子模块其四大职责如下读取板载陀螺仪数据实时获取机身 yaw/pitch/roll 姿态角与角速度运行所有运动控制算法包括平衡算法、腿长控制、roll/yaw 控制等通过 CAN 通信获取电机状态并发送扭矩指令与关节驱动板/轮驱动板进行高速数据交换通过低功耗蓝牙接收上位机的遥控指令与 Android App 等上位机交互。从源码看这些职责在 main.cpp 中被拆分为电机、CAN 通信、陀螺仪IMU、运动控制、蓝牙、串口、ADC七大模块每个模块的函数名均以模块名开头例如Motor_*、CAN_*、IMU_*、Ctrl_*、BT_*、Serial_*、ADC_*读者可以按此规律对照注释阅读。二、硬件说明2.1 芯片方案本模块硬件方案的核心特性详见 esp32-controller/README.md项目选型说明主控芯片ESP32-C3RISC-V 内核带 USB-JTAG 与 USB-Serial支持 Wi-Fi/蓝牙BLE陀螺仪MPU6050六轴三轴加速度计 三轴陀螺仪通过 I2C 接入使用其 DMP 硬件解算单元CAN 驱动芯片TJA1050TCAN 收发器负责电平转换接入 ESP32-C3 的 TWAI 外设供电电压12V采用LDO降压方案注README 指出该方案发热较大见改进方向章节调试接口USB Type-C直连芯片引脚可同时用于程序烧录、JTAG 调试和串口通信源码中的外设接线与上述方案对应CAN_Init 将 TWAI 收发引脚配置为GPIO_NUM_6TX与GPIO_NUM_7RX波特率 1 Mbit/sIMU_Init 中 I2C 使用Wire.begin(5, 4)并将时钟设置为 400 kHz加速度计量程配置为 ±16 g。2.2 硬件文件说明硬件相关文件全部位于esp32-controller/hardware目录下文件说明ESP32CTRL_LCEDA_SCH.json立创 EDA 原理图文件ESP32CTRL_LCEDA_PCB.json立创 EDA PCB 文件ESP32CTRL_AD_SCH.schdoc立创 EDA 导出的 Altium Designer 原理图文件ESP32CTRL_AD_PCB.pcbdoc立创 EDA 导出的 Altium Designer PCB 文件ESP32CTRL_SVG.svg原理图矢量图文件注意将立创原理图和 PCB 两个 json 文件导入立创 EDA 标准版编辑器即可查看和编辑不建议使用 AD 直接打开 json。三、软件说明3.1 开发平台与构建配置程序使用PlatformIO平台开发采用ESP-IDF并将Arduino 框架作为组件引入因此可以同时使用 Arduino 第三方库如 MPU6050 库和 ESP-IDF 的底层 API如 CAN 通信所用的driver/twai.h。工程构建配置见 esp32-controller/software/platformio.ini[env:esp32dev] platform espressif32 board esp32dev framework arduino, espidf board_build.mcu esp32c3 board_build.flash_mode dio upload_speed 921600 upload_port COM13 board_build.partitions partition.csv build_flags -D ESP32 -D ARDUINO_USB_MODE1 -D ARDUINO_USB_CDC_ON_BOOT1 lib_deps electroniccats/MPU6050^0.6.0几个值得注意的配置点framework arduino, espidf同时启用 Arduino 与 ESP-IDF 两套框架这是既能用 Arduino 库、又能调 ESP-IDF 底层 API的关键board_build.mcu esp32c3虽然 board 为esp32dev但实际指定了 ESP32-C3 作为编译目标ARDUINO_USB_CDC_ON_BOOT1使 USB 串口CDC在启动时即挂载从而让Serial类可以通过 USB Type-C 输出日志lib_deps electroniccats/MPU6050^0.6.0MPU6050 驱动库含 DMP 支持分区表 esp32-controller/software/partition.csv 分配了nvs0x9000、phy_init0xf000与factory0x10000 起大小 2M三个分区。工程顶层 CMake 配置见 esp32-controller/software/CMakeLists.txt项目名为EspBalanceCtrlesp32-controller/software/src/CMakeLists.txt 通过GLOB_RECURSE将src目录下所有源文件注册为组件。3.2 FreeRTOS 多任务架构为方便程序编写和调试程序使用 ESP-IDF 自带的FreeRTOS进行多任务调度每个模块会触发一个或多个任务。从 setup() 的初始化序列与各模块内部的xTaskCreate调用可以梳理出完整的任务拓扑任务创建位置周期优先级职责Serial_TaskSerial_Init50 ms1USB 串口日志输出调试用默认大部分打印已注释ADC_TaskADC_Init100 ms5采样电池电压计算电机输出电压比例motorOutRatioCAN_RecvTaskCAN_Init2 ms 轮询5轮询 TWAI 接收队列按 CAN ID 分发到各电机对象Motor_SendTaskMotor_InitAll2 ms5计算各电机补偿电压并组帧发送0x100/0x200IMU_TaskIMU_Init5 ms5读取 DMP FIFO输出欧拉角、角速度、Z 轴线性加速度Ctrl_TargetUpdateTaskCtrl_Init4 ms3将遥控目标量平滑为控制算法给定量速度斜坡等LegPos_UpdateTaskCtrl_Init4 ms2由关节电机数据解算腿部姿态长度/角度/速度/加速度Ctrl_TaskCtrl_Init4 ms1主控制任务LQR 串级 PID VMC输出各电机扭矩Ctrl_StandupPrepareTask蓝牙 0xAB / 按键触发一次性1起立准备劈叉姿态流程完成后自删除BT_SendSampleTask蓝牙 0xAC 触发100 ms1按设定时长通过 BLE Notify 回传采样数据从源码结构可以推断系统采用高频轮询 独立任务的方式CAN 与电机指令是 2 ms 周期姿态与腿部解算是 4~5 ms 周期主控制任务固定 4 ms即 250 Hz 控制频率运行一次。3.3 源码文件地图PlatformIO 工程位于software目录下代码文件位于src目录文件说明main.cpp主要程序文件包含所有任务模块的逻辑代码PID.c / PID.hPID 控制器的实现包含单级和串级 PID 控制器debug.c / debug.h用于 Linkscope 软件实现蓝牙无线调试不参与正常运行读者可忽略leg_pos.c / leg_pos.h腿部位置解算函数MATLAB Coder 生成leg_spd.c / leg_spd.h腿部运动速度解算函数MATLAB Coder 生成leg_conv.c / leg_conv.h腿部输出换算函数VMC 力矩映射MATLAB Coder 生成lqr_k.c / lqr_k.hLQR 反馈矩阵计算函数MATLAB Coder 生成电机、陀螺仪、CAN 通信、蓝牙、运动控制等模块的代码全部位于main.cpp中不同模块的函数名基本都以模块名开头。关于 MATLAB 生成的 C 代码README 明确说明这四组leg_*/lqr_k文件由 MATLAB 直接生成的 C 代码文件没有可读性读者可参阅本项目 MATLAB 程序说明。对应关系在 matlab/README.md 中有完整描述leg_func_calc.m进行腿部解算和 VMC 映射计算导出leg_pos.m由关节电机角度求腿部姿态、leg_spd.m由关节电机角度速度求腿部运动速度、leg_conv.m由虚拟腿目标扭矩和推力求电机所需力矩sys_calc.m求得系统状态方程与反馈矩阵导出lqr_k.m代入腿长 L0 返回该腿长对应的反馈矩阵 Kleg_sim.slx、sys_sim.slx腿部与整机的 Simscape Multibody 仿真模型。从生成的函数签名可以确认调用关系均带extern C声明以便 C/C 混用// leg_pos.h腿部姿态解算 extern void leg_pos(float phi1, float phi4, float pos[2]); // leg_spd.h腿部速度解算 extern void leg_spd(float dphi1, float dphi4, float phi1, float phi4, float spd[2]); // leg_conv.hVMC 力矩映射 extern void leg_conv(float F, float Tp, float phi1, float phi4, float T[2]); // lqr_k.hLQR 反馈矩阵 extern void lqr_k(float L0, float K[12]);这些函数在main.cpp中的实际调用位于 LegPos_UpdateTask调用leg_pos/leg_spd与 Ctrl_Task调用lqr_k/leg_conv构成了电机角度 → 腿部姿态 → 状态反馈 → 关节力矩的完整控制链路。3.4 PID 控制器实现细节PID.h 定义了单级 PID 与串级 PID 两个结构体// PID 参数结构体 typedef struct _PID { float kp, ki, kd; float error, lastError; float integral, maxIntegral; float output, maxOutput; float deadzone; float errLpfRatio; } PID; // 串级 PID 参数结构体 typedef struct _CascadePID { PID inner; // 内环速度环 PID outer; // 外环角度环 float output; } CascadePID;PID.c 中的实现具备几个工程化细节死区误差绝对值小于deadzone时直接置 0防止微小抖动引起输出颤振误差低通滤波error error * errLpfRatio lastError * (1 - errLpfRatio)抑制差分噪声积分限幅LIMIT(pid-integral, -maxIntegral, maxIntegral)防止积分饱和输出限幅LIMIT(pid-output, -maxOutput, maxOutput)串级结构PID_CascadeCalc 先算外环角度环PID_SingleCalc(pid-outer, angleRef, angleFdb)再以内环输出作为速度环给定PID_SingleCalc(pid-inner, pid-outer.output, speedFdb)最终输出为内环输出。从 Ctrl_Init 可以读到四组串级 PID 的实际整定参数PID内环 (kp, ki, kd, maxIntegral, maxOutput)外环 (kp, ki, kd, maxIntegral, maxOutput)备注yawPID偏航0.01, 0, 0, 0, 0.110, 0, 0, 0, 2rollPID横滚1, 0, 5, 0, 520, 0, 0, 0, 3内环误差低通 0.1legLengthPID腿长10, 1, 30, 2, 105, 0, 0, 0, 0.5内环误差低通 0.5legAnglePID腿角差0.04, 0, 0, 0, 112, 0, 0, 0, 20外环误差低通 0.5四、使用说明4.1 烧录程序使用 USB 线连接到电脑按下两个按键后先松开 RESET 再松开 BOOT芯片即会进入烧录模式此时可使用 PlatformIO 进行烧录。结合 platformio.ini 中的upload_speed 921600与upload_port COM13配置直接执行pio run -t upload即可完成烧录。4.2 调试程序程序中使用 Arduino 的Serial类即可从 USB 输出串口信息可以使用电脑上的串口调试软件进行查看波特率在 Serial_Task 中设定为 115200。此外ESP32-C3 的 USB 还支持JTAG 调试连接到电脑后即可使用 OpenOCD 等程序连接。笔者在调试过程中搭配Linkscope实现在线读写变量和曲线绘制较为方便。无线调试的底层支撑是 debug.c它实现了一个基于 BLE 的内存读写调试协议数据帧格式帧头 1 字节固定0xDB 帧长 1 字节 命令码 1 字节 数据支持三种命令SerialCMD_ReadMem读内存、SerialCMD_WriteMem写内存、SerialCMD_Reset复位提供DEBUG_READ_ADDR_RANGE/DEBUG_WRITE_ADDR_RANGE宏限制可访问的地址范围默认限制在0x3FC80000 ~ 0x3FCDFFFF的 SRAM 区域并支持DEBUG_ADDR_OFFSET地址偏移接收端使用 30 字节的循环队列缓存支持连续多帧递归解析。在 main.cpp 的蓝牙回调中0xDB开头的帧会进入Debug_SerialRecv从而在 BLE 通道上实现远程读写变量 曲线绘制。五、参数标定决定控制成败的关键README 明确指出在main.c中有几个参数可能需要根据实际系统进行调整否则将无法进行正确的解算和控制。这些参数全部集中在 Motor_InitAll 中对六个电机对象的初始化调用中。5.1 零点偏移与旋转方向参数offsetAngle / dirMotor_InitAll中分别调用Motor_Init进行每个电机的参数设定包括零点偏移offsetAngle和旋转方向dir。这两个参数用于在 Motor_Update 中将编码器反馈的原始角度转换为算法中的标准角度 $\phi_i$电机angle成员变量转换公式为$$ \phi_i (rawAngle_i - offsetAngle_i) \times dir_i $$从源码可以看到该公式的直接实现原始角度来自 CAN 帧前 4 字节单位为 0.001 radmotor-angle (*(int32_t *)data[0] / 1000.0f - motor-offsetAngle) * motor-dir;测量方法原文档 5 步流程设置dir参数取值 1 / -1使得电机angle成员变量在电机向 $\phi_i$ 正方向旋转时增加程序中设置offsetAngle 0记为 $offsetAngle_i^z$将电机旋转到某个角度记录当前的计算角度为 $\phi_i^c$测量当前的实际角度为 $\phi_i^r$将 $\phi_i^c$、$offsetAngle_i^z$、$dir_i$ 代入公式求得 $rawAngle_i$ 的值将 $\phi_i^r$、$rawAngle_i$、$dir_i$ 代入公式求得 $offsetAngle_i$ 的值设置到程序中此时angle成员变量应该与实际 $\phi_i$ 一致。注 1$\phi_i$ 的定义可以在 matlab/README.md 引用的算法专栏文章中找到。从 LegPos_UpdateTask 的调用leg_pos(leftJoint[1].angle, leftJoint[0].angle, legPos)与leg_pos(phi1, phi4, ...)的签名可以确认靠前的关节电机leftJoint[0]/rightJoint[0]对应 $\phi_4$靠后的关节电机leftJoint[1]/rightJoint[1]对应 $\phi_1$。注 2以上描述均针对关节电机车轮电机仅需设置dir参数使其angle变量正方向与算法中驱动轮力矩 $T$ 一致即可在 Ctrl_Task 中车轮位置由(leftWheel.angle rightWheel.angle) / 2 * wheelRadius计算wheelRadius 0.026 m。仓库中作者实测的关节电机参数见 Motor_InitAll可作为参考电机offsetAngle (rad)maxVoltage (V)torqueRatio (Nm/V)dirleftJoint[0]左前关节1.43170.0316-1leftJoint[1]左后关节-7.7670.03171rightJoint[0]右前关节0.34370.0299-1rightJoint[1]右后关节-2.44670.0321-1leftWheel左轮04.00.00961rightWheel右轮04.00.010115.2 扭矩系数torqueRatio注若使用笔者相同电机可以不修改该参数。与上述两个参数相同该参数也在Motor_InitAll中设置用于进行电压和扭矩的换算公式为$$ voltage_i \frac{torque_i}{torqueRatio_i} $$该公式在 Motor_UpdateVoltage 中实现float voltage motor-torque / motor-torqueRatio * motorOutRatio;其中motorOutRatio为 ADC 任务根据电池电压实时计算的整体输出比例。测量方法给电机不同的电压测量其扭矩笔者测的是堵转扭矩记录为 $(v_i, \tau_i)$将 $(v_i, \tau_i)$ 拟合为线性函数 $\tau k \times v$$k$ 即为torqueRatio的值可以用 MATLAB、Excel 等软件辅助计算。从仓库数据看4010 关节电机的torqueRatio约为 0.03 Nm/V2804 车轮电机约为 0.0096~0.0101 Nm/V同时车轮电机的maxVoltage被限制为 4.0 V关节电机为 7 V。5.3 反电动势函数注若使用笔者相同电机可以不修改该参数。关节电机反电动势计算函数为 Motor_CalcRevVolt4010车轮电机为 Motor_CalcRevVolt2804用于根据电机的实时转速计算反电动势输出电压指令时会根据计算结果进行补偿以抵消反电动势。源码实现为三次多项式// 4010 关节电机输入速度 rad/s输出反电动势 V return 0.00008f * speed * speed * speed - 0.0035f * speed * speed 0.2322f * speed; // 2804 车轮电机 return 0.000004f * speed * speed * speed - 0.0003f * speed * speed 0.0266f * speed;测量方法给电机不同的电压测量其空载转速记录为 $(v_i, \omega_i)$拟合为三次幂函数 $v f(\omega)$即为反电动势函数。补偿逻辑见 Motor_UpdateVoltage中体现了两个工程细节补偿的意义电机转速越快反电动势越大需要加大驱动电压来抵消反电动势使电流即扭矩不随转速发生变化补偿会顺带抵消大部分机械阻力if (motor-speed 0) voltage calcRevVolt(speed); else voltage - calcRevVolt(-speed);。标定正确性校验若反电动势标定正确在设置电机扭矩为 0torque成员为 0时手动旋转电机应该感受到阻力几乎为 0抵消反电动势时顺便抵消了大部分机械阻力。调试提示注释掉 setup() 中的Ctrl_Init();或注释所有Motor_SetTorque函数的调用即可禁用控制系统的输出此时可以自行插入代码调试电机。六、从源码看控制环路如何闭环在动手调参之前理解主控制任务 Ctrl_Task 的完整流程有助于把握每个标定参数在系统中的位置。该任务每 4 ms 运行一次执行以下步骤计算状态变量phi机身俯仰角来自 IMU、x车轮累计位移由左右轮角度均值乘轮半径 0.026 m 得到、theta腿部角度取左右腿角度均值减 $\pi/2$ 再减俯仰角及其导数离地保护分支若处于站立准备状态则跳过控制输出LQR 反馈矩阵调用lqr_k(legLength, kRes)按当前腿长实时查算反馈矩阵并用kRatio系数手动缩放腿部离地时手动改写反馈矩阵、仅保持腿部竖直LQR 输出状态向量 $\mathbf{x}[\theta, \dot\theta, x, \dot x, \phi, \dot\phi]^T$ 减去位置/速度给定后与反馈矩阵相乘得到平动输出lqrOutT与俯仰/腿部输出lqrOutTpyaw 串级 PID跟踪目标航向角输出叠加到左右车轮扭矩差分转向腿长与 roll 串级 PID计算腿部竖直推力左右腿推力在接地状态下叠加 roll 修正±6 N 前馈基准与 0.12 m 腿长超限保护触地检测由推力 腿重 - 惯性力估算地面支持力 3 N 判为接地带 1 s 防弹跳逻辑与落地缓冲状态机VMC 力矩映射leg_conv(F, Tp, phi1, phi4, T)将虚拟腿推力F与髋关节扭矩Tp映射为前后两个关节电机的实际扭矩角度超限保护当腿部角度或俯仰角超过 $\pm\pi/4$ 时关闭所有电机待恢复安全范围后延时 4 s 再继续控制。围绕这个主循环配套任务各司其职Ctrl_TargetUpdateTask以 4 ms 周期对遥控速度做斜坡平滑斜坡步长随腿长自适应腿越短加减速斜率越大并将位置给定限制在当前值 ±0.1 m、速度给定限制在 ±0.3 m/sLegPos_UpdateTask以 4 ms 周期调用leg_pos/leg_spd解算腿部姿态并对腿长加速度做低通滤波滤波系数 0.5。CAN 数据链路方向主控板 → 驱动板Motor_SendTask 每 2 ms 将六个电机的补偿后电压×1000 转为 int16打包成两帧 CAN 数据发送——帧 ID0x100携带左侧三个电机左前关节、左后关节、左轮帧 ID0x200携带右侧三个电机。反向链路驱动板 → 主控板由 CAN_RecvCallback 按 ID 分发0x101左前关节、0x102左后关节、0x103左轮、0x105右前关节、0x106右后关节、0x107右轮。七、蓝牙遥控协议与板载按键7.1 BLE 服务与指令协议蓝牙模块在 BT_Init 中初始化为名为BalanceBot的 BLE 服务端使用固定 UUID服务4c9a0001-fb2e-432e-92ec-c6f5316b4689、接收特征4c9a0002-...WRITE_NR、发送特征4c9a0003-...NOTIFY。MyBleCharaCallbacks::onWrite 定义了完整的指令协议首字节长度功能数据格式0xAA4 字节目标值控制指令data[1]偏航速度-(data[1]/100-1)*1.5rad/sdata[2]前进速度(data[2]/100-1)*1.0m/sdata[3]目标腿长data[3]/200*0.020.07m0xAB-触发起立过程创建Ctrl_StandupPrepareTask0xAC2 字节触发一次数据采样启动BT_SendSampleTask采样时长 data[1]×1000 ms每 100 ms 通过 Notify 回传一行speedCmd, speed, dx, phi, theta数据0xDB-调试指令交给 debug.c 处理7.2 板载按键操作无需手机时loop() 中实现了基于按键按下时长的本地操作按下后每 300 ms LED 闪烁一次计数按下时长闪烁次数功能1 次设定目标航向角为当前值2 次进入起立过程创建Ctrl_StandupPrepareTask3 次向前运动 2 秒4 次向前运动 5 秒5 次旋转 90°目标航向角 $\pi$此外LED 在上电后还会以闪烁次数指示电池电压次数 (sourceVoltage - 11) / 0.5 1ADC_Task 通过analogRead(0)分压采样电池电压并据此调整电机输出比例motorOutRatio (12 - sourceVoltage) / 10.0f 0.7f。八、改进方向README 在结尾给出了作者自己指出的三个改进方向对二次开发者极具参考价值姿态解算频率受限MPU6050 的 DMP 频率只有 200 Hz可以考虑更换其他芯片并编写姿态解算程序以提升姿态更新率供电方案发热硬件使用 LDO 进行降压由于 ESP32-C3 功耗较高LDO 发热量较大可以修改为 DC-DC 降压方案算法运算量过大关键算法使用 MATLAB 符号化简结果直接导出运算量非常大几乎吃满了芯片性能从 leg_conv.c 中数十个中间变量即可见一斑无法进一步提升控制频率可以尝试手动化简后转为 C 代码。结语本文围绕 esp32-controller/README.md 完整展开了 ESP32-C3 主控板的硬件方案、PlatformIO 软件工程、FreeRTOS 任务架构与三类关键参数的标定方法并结合 main.cpp、PID.c、debug.c 等源码给出了底层实现证据。对需要复刻或二次开发这台轮腿机器人的开发者建议按以下顺序推进先完成 5.1~5.3 的电机参数标定再通过 4.2 的调试手段验证 IMU 与 CAN 数据链路最后在 4.1 烧录后结合蓝牙协议逐步联调平衡控制。更深入的算法推导腿部解算、VMC 映射、LQR 求取可继续阅读 matlab/README.md 及其脚本与仿真模型。赞分享机器人嵌入式硬件开发移动开发【免费下载链接】foc-wheel-legged-robotOpen source materials for a novel structured legged robot, including mechanical design, electronic design, algorithm simulation, and software development. | 一个新型结构的轮腿机器人开源资料包含机械设计、电子设计、算法仿真、软件开发等材料项目地址https://gitcode.com/gh_mirrors/fo/foc-wheel-legged-robot点击查看免费下载相关推荐foc-wheel-legged-robot 的 ESP32-C3 主控硬件方案、FreeRTOS 任务架构与电机参数标定实战foc wheel legged robot 的 ESP32 C3 主控硬件方案、FreeRTOS 任务架构与电机参数标定实战 本文围绕 foc wheel机器人嵌入式硬件开发移动开发FOC双轮腿机器人的安装与使用指南FOC双轮腿机器人的安装与使用指南 目录 一、项目的目录结构及介绍 FOC双轮腿机器人项目的目录结构是为了便于管理和查找各种资源而精心设计的。下面将详细介绍每个机器人嵌入式硬件开发移动开发KeePassHttp完整安装教程Windows、Linux、Mac三大平台详细配置KeePassHttp完整安装教程Windows、Linux、Mac三大平台详细配置 KeePassHttp是一款安全的KeePass插件能够通过256位A上一篇使用 OPA 与 Linux-PAM 为 SSH 和 sudo 实施主机级细粒度访问控制下一篇深入 Razzle 的 with-webpack-public-path 示例自定义资源 publicPath 实现 CDN 与子路径部署创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考