首页 / 资讯中心 / 文章详情

蜘蛛机器人STM32F103控制程序源码:舵机抖动到步态落地

蜘蛛机器人STM32F103控制程序源码:舵机抖动到步态落地 ★ FEATURED ARTICLE
简介这份STM32F103蜘蛛机器人控制程序源码面向嵌入式开发初学者与机器人控制爱好者用于演示如何用经典Cortex-M3内核芯片驱动多足机器人。源码围绕硬件接口、驱动程序、RTOS任务调度、PID与步进电机控制算法、通信协议、传感器融合、电源管理及故障诊断等模块展开可帮助读者理解从GPIO、ADC到电机驱动的完整控制链路。资源包共188个文件约1.6MB以31个c源文件与34个h头文件为核心配合31个d依赖文件、31个crf编译记录及o、axf、map等构建产物另有uv2工程、sct分散加载与lst列表文件目录结构完整便于直接导入Keil或STM32CubeIDE复现调试。目前已有1384人学习下载适合作为嵌入式课程设计、机器人竞赛或自学STM32控制算法的实践参考。1. 蜘蛛机器人STM32F103控制程序源码从舵机抖动到步态落地的完整拆解如果你正在做多足机器人大概率绕不开一个核心矛盾算法仿真里步态走得稳稳当当烧进板子后机器人却像喝多了——舵机抖动、足端拖地、转向时直接翻车。这套蜘蛛机器人STM32F103控制程序源码解决的正是从「理论步态」到「实物落地」之间那段最磨人的距离。它基于STM32F103系列MCU围绕18路舵机六足各3关节的PWM时序控制、三角步态相位调度、逆运动学解算三条主线展开适合已经点完灯、调通串口想真正把多足平台跑起来的嵌入式开发者。源码结构不复杂但每一处参数都直接决定机器人是走还是爬下面按我实际拆包调试的顺序讲。2. 先看懂这套源码的骨架时钟、PWM与舵机映射拿到一份STM32控制源码最忌讳上来就改步态参数。舵机都没校准改什么都是玄学。这一章先把底层驱动链路理清楚确保18路PWM能独立、稳定地输出。2.1 系统时钟与PWM定时器的分配逻辑STM32F103的定时器资源有限要驱动18路舵机必须做通道复用规划。常见做法是用TIM1/TIM2/TIM3/TIM4四个通用定时器每个定时器出4路PWM共16路再补两个通道或用TIM8凑齐18路。源码里一般会看到这样的初始化结构// 以TIM3为例配置4路PWM输出周期20ms对应50Hz舵机 void Servo_TIM3_Init(uint16_t arr, uint16_t psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); // PB0/PB1 复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_0 | GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period arr; // 自动重装载值 TIM_TimeBaseStructure.TIM_Prescaler psc; // 预分频 TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 1500; // 初始1.5ms中位 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM3, TIM_OCInitStructure); TIM_OC2Init(TIM3, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); TIM_Cmd(TIM3, ENABLE); }这段代码的关键在arr和psc的配合。系统时钟72MHz要得到50Hz的PWM频率周期计数 72M / (psc1) / (arr1) 50。常见配置是psc71arr19999此时计数器每加1代表1微秒比较值直接对应脉宽微秒数调起来最直观。如果你把psc设成719arr1999虽然频率也对但分辨率掉到10微秒一档舵机会出现肉眼可见的台阶感。我一般固定用前者省得后面算脉宽时还要换算。2.2 舵机角度到PWM脉宽的映射表标准舵机控制脉宽是0.5ms到2.5ms对应0到180度但廉价舵机实际死区往往在0.7ms到2.3ms之间。源码里通常会有一个映射函数把逆运动学算出的关节角度转成比较寄存器值// 角度转PWM比较值min_pulse/max_pulse需按实际舵机标定 uint16_t AngleToPulse(float angle, uint16_t min_pulse, uint16_t max_pulse) { if (angle 0.0f) angle 0.0f; if (angle 180.0f) angle 180.0f; // 线性映射0度-min_pulse, 180度-max_pulse return (uint16_t)(min_pulse (max_pulse - min_pulse) * angle / 180.0f); }参数说明min_pulse和max_pulse不是抄手册的0.5ms/2.5ms就完事。我习惯先写个测试程序让每个舵机从1000慢慢加到2000记录它实际开始转动和到达极限的位置把这两个值填进去。18个舵机每个都标一遍虽然枯燥但能省掉后面步态调试时一半的「为什么这条腿不动」的排查时间。2.3 六足关节编号与GPIO映射的对应关系源码里一定会有一张关节映射表把「左中腿胫节」这种逻辑名称对应到具体定时器通道和GPIO引脚。这张表如果乱了步态相位再对也是白搭。常见做法是用一个结构体数组typedef struct { uint8_t leg_id; // 腿编号 0-5 uint8_t joint_id; // 关节编号 0-2 (0髋 1股 2胫) TIM_TypeDef* tim; // 所属定时器 uint8_t channel; // 通道号 uint16_t min_pulse; // 标定下限 uint16_t max_pulse; // 标定上限 float offset; // 机械安装偏差补偿 } ServoMap_t; ServoMap_t servo_map[18] { {0, 0, TIM1, 1, 1100, 1900, 0.0f}, // 右前腿髋关节 {0, 1, TIM1, 2, 1050, 1950, -3.0f}, // 右前腿股关节 // ... 其余15路 };offset这个字段是血泪经验舵机安装时很难保证机械零位和电气零位完全对齐每条腿的偏差还不一样。有了这个补偿值逆运动学算出的角度加上offset再转脉宽机器人站姿才是正的。没有它你会看到机器人站着就是歪的走起来越走越偏。3. 三角步态的实现相位调度与逆运动学解算底层通了接下来是这套源码真正的核心——让六条腿协调地走起来。六足机器人最经典的步态是三角步态把六条腿分成两组每组三条构成一个三角形支撑另一组抬起摆动交替循环。3.1 三角步态的相位分组与占空比设置三角步态的分组方式取决于腿的编号顺序。常见编号是右前、右中、右后、左前、左中、左后。分组A为右前、右后、左中分组B为左前、左后、右中。源码里通常用一个相位数组来定义每条腿在步态周期中的状态// 步态相位定义0支撑相1摆动相 // 一个完整周期分为stance_phase和swing_phase两段 #define GAIT_CYCLE_MS 1000 // 步态周期1秒 #define STANCE_RATIO 0.6f // 支撑相占60% #define SWING_RATIO 0.4f // 摆动相占40% typedef struct { uint8_t group; // 0组A, 1组B float phase_offset; // 相位偏移 0.0-1.0 } LegGait_t; LegGait_t gait_config[6] { {0, 0.0f}, // 右前腿组A相位0 {1, 0.5f}, // 右中腿组B相位0.5 {0, 0.0f}, // 右后腿组A相位0 {1, 0.5f}, // 左前腿组B相位0.5 {0, 0.0f}, // 左中腿组A相位0 {1, 0.5f}, // 左后腿组B相位0.5 };参数说明STANCE_RATIO设0.6意味着任意时刻至少有60%的时间三条腿同时着地稳定性够。如果你把它调到0.5机器人会走得更快但晃动明显调到0.7以上稳是稳了但步幅小、走得慢。我一般从0.6起步根据实际地面摩擦和重心高度微调。phase_offset是组B相对组A的延迟0.5表示半周期错开这是三角步态的标准配置。3.2 足端轨迹规划抬腿高度与落点前移摆动相的腿不是简单地从A点抬到B点而是要走一条弧线避免拖地和磕碰。源码里通常用参数方程生成足端轨迹// 生成摆动相足端位置t为0到1的归一化时间 void SwingTrajectory(float t, float* x, float* y, float* z, float step_length, float lift_height) { // x方向从后往前线性移动 *x -step_length * 0.5f step_length * t; // z方向正弦抬腿t0.5时最高 *z lift_height * sinf(PI * t); // y方向保持不变直行时 *y 0.0f; }逻辑说明step_length是单步步幅lift_height是抬腿高度。抬腿高度设多少合适经验值是足端离地5到10毫米。太低容易蹭地太高则重心晃动大。正弦曲线的好处是起落平滑没有速度突变舵机不会发出咔咔的异响。如果你用梯形速度曲线起落点会有冲击长期跑下来舵机齿轮磨损明显加快。3.3 逆运动学解算从足端坐标到三个关节角这是整套源码里数学味最重的部分。六足单腿通常是三自由度髋关节水平旋转、股关节上下摆动、胫关节上下摆动。给定足端相对身体坐标系的目标位置(x, y, z)需要反解出三个角度。常见做法是分两步先解髋关节的偏航角再在腿平面内解股关节和胫关节的俯仰角。// 单腿逆运动学解算输入足端坐标输出三个关节角度 void InverseKinematics(float x, float y, float z, float* hip_angle, float* femur_angle, float* tibia_angle, float L1, float L2, float L3) { // 第一步髋关节偏航角 *hip_angle atan2f(y, x) * 180.0f / PI; // 第二步投影到腿平面 float r sqrtf(x * x y * y) - L1; // 水平距离减去髋偏移 float d sqrtf(r * r z * z); // 股关节到足端的直线距离 // 余弦定理求股关节角 float cos_femur (L2 * L2 d * d - L3 * L3) / (2 * L2 * d); if (cos_femur 1.0f) cos_femur 1.0f; if (cos_femur -1.0f) cos_femur -1.0f; float alpha acosf(cos_femur); // 余弦定理求胫关节角 float cos_tibia (L2 * L2 L3 * L3 - d * d) / (2 * L2 * L3); if (cos_tibia 1.0f) cos_tibia 1.0f; if (cos_tibia -1.0f) cos_tibia -1.0f; float beta acosf(cos_tibia); *femur_angle (alpha atan2f(z, r)) * 180.0f / PI; *tibia_angle (beta - PI) * 180.0f / PI; // 注意符号取决于关节方向定义 }参数说明L1是髋关节到腿平面的水平偏移L2是股节长度L3是胫节长度单位要统一一般用毫米。这段代码里最容易翻车的是tibia_angle的符号和零点定义。不同机械结构下胫关节的「伸直」可能对应0度也可能对应180度。我一般会先让机器人腿完全伸直读一次角度值作为参考再确定公式里的偏移量。另外acosf的输入必须做限幅否则浮点误差会让它返回NaN舵机直接乱转。3.4 步态调度主循环的时序控制所有计算最终要落到一个定时中断或主循环里按固定周期更新18路PWM。常见做法是用一个1ms的SysTick中断做时基每1ms更新一次步态相位每20ms更新一次PWM输出volatile uint32_t gait_tick 0; void SysTick_Handler(void) { gait_tick; if (gait_tick % 20 0) { // 每20ms更新一次舵机 UpdateGaitPhase(gait_tick % GAIT_CYCLE_MS); UpdateAllServos(); } } void UpdateGaitPhase(uint32_t phase_ms) { float t (float)phase_ms / GAIT_CYCLE_MS; // 归一化周期时间 for (int i 0; i 6; i) { float leg_t t gait_config[i].phase_offset; if (leg_t 1.0f) leg_t - 1.0f; if (leg_t STANCE_RATIO) { // 支撑相足端相对身体后移 SetLegStance(i, leg_t / STANCE_RATIO); } else { // 摆动相足端抬起前移 SetLegSwing(i, (leg_t - STANCE_RATIO) / SWING_RATIO); } } }逻辑说明gait_tick % 20决定舵机更新频率20ms对应50Hz和PWM周期一致。更新太快没必要舵机响应不过来更新太慢比如50ms步态会卡顿。UpdateGaitPhase里把全局时间加上每条腿的相位偏移再对1取模就得到该腿在自身周期中的位置。支撑相和摆动相分别调用不同的足端位置生成函数再走逆运动学转成角度。这套流程跑通后机器人就能迈出第一步了。4. 避坑与排查调试蜘蛛机器人时最容易翻车的五个点源码能编译、能下载不代表机器人能走。下面这五个问题我几乎每次调试都会遇到至少两个。4.1 现象上电后所有舵机同时向一个方向猛打原因PWM初始化时比较寄存器默认值不是1.5ms中位或者定时器启动顺序不对导致上电瞬间输出异常脉宽。解决在TIM_Cmd使能之前先把所有通道的TIM_Pulse设成中位值1500再调用TIM_Cmd。另外电源和信号线要分开走舵机共地但不要共电源否则上电冲击会串到信号线上。4.2 现象机器人站着不动但舵机有微弱嗡嗡声原因逆运动学解算出的角度超出了舵机实际可动范围AngleToPulse限幅后输出恒定值舵机堵转。解决在InverseKinematics输出后加一层范围检查把每个关节角限制在标定过的机械限位内。同时检查L1/L2/L3是否填错腿长参数差10毫米解出的角度可能差十几度。4.3 现象走直线时越走越偏最后原地转圈原因18个舵机的机械零位偏差没有补偿或者左右腿的offset符号搞反了。解决把机器人架起来让所有腿回到理论零位逐个测量实际足端位置把偏差折算成角度填进offset字段。左右对称的腿offset应该数值相近符号相反如果同号说明有一侧的关节方向定义反了。4.4 现象步态周期设成500ms后机器人抖动严重甚至复位原因步态更新频率提高后逆运动学里的sqrtf和acosf计算量增大如果放在中断里且中断优先级配置不当会阻塞其他中断导致电源监控芯片复位。解决把逆运动学计算放到主循环里中断只做PWM更新和相位递增。或者降低步态更新频率到20ms一次中间用插值平滑。STM32F103没有硬件浮点三角函数尽量用查表或定点数替代。4.5 现象更换电池后步态完全变了之前调好的参数全废原因舵机扭矩随电压下降明显原来能抬起的腿现在抬不动足端实际位置和理论位置偏差变大。解决在电源端加一个大电容缓冲或者用稳压模块给舵机供6V。软件上可以在SwingTrajectory里根据电压检测结果动态调整lift_height电压低时适当降低抬腿高度牺牲通过性保稳定。5. 进阶调参用串口示波器把步态「看」出来源码跑通之后真正的功夫在调参。我习惯用串口把每条腿的足端坐标和关节角度实时打出来配合上位机示波器观察波形。具体做法是在UpdateAllServos之后加一段格式化输出// 每50ms通过串口输出一次调试数据 if (gait_tick % 50 0) { printf(LEG0: x%.1f y%.1f z%.1f hip%.1f femur%.1f tibia%.1f\r\n, leg_pos[0].x, leg_pos[0].y, leg_pos[0].z, leg_angle[0].hip, leg_angle[0].femur, leg_angle[0].tibia); }把printf重定向到USART1波特率设115200上位机用任意串口示波器工具就能看到六条腿的相位关系。正常三角步态的足端z轴波形应该是两组交错的正弦半波如果某条腿的波形明显滞后或超前检查它的phase_offset是否被意外修改。如果波形有毛刺说明逆运动学里出现了NaN或者角度跳变重点查acosf的输入限幅。调参顺序我一般固定为先调站立姿态确保六条腿对称且足端共面再调单腿摆动看抬腿和落点是否平滑最后调整机步态从慢到快逐步缩短周期。每次只改一个参数改完立刻用示波器确认波形。这套源码的步态框架是通用的但每条腿的offset、每个舵机的脉宽范围、每组步态的占空比都得在你的实物上重新标一遍。从那以后我每次拿到新的多足平台都强制先跑一遍舵机标定和足端示波器确认底层没问题再动步态参数。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站