资讯动态

蜘蛛机器人STM32F103控制程序:18路舵机三角步态稳定实现

发布时间:2026/10/21 12:24:35 来源:尧图企业网站定制
简介这份蜘蛛机器人STM32F103控制程序源码面向嵌入式开发初学者与机器人控制爱好者基于ARM Cortex-M3内核的经典STM32F103芯片演示如何用单片机驱动多足蜘蛛形态机器人帮助读者理解从硬件接口到运动控制的完整实现链路。资源包共188个文件约1.6MB以c源码与h头文件为核心配合o目标文件、d依赖文件、crf交叉引用记录及uv2、axf等Keil工程产物另含sct分散加载、map映射与lst列表文件便于还原编译与调试过程。源码覆盖GPIO电机驱动、ADC传感器采集、定时器PWM输出、PID与步进电机控制算法并涉及FreeRTOS任务调度、蓝牙或Wi-Fi通信协议栈、传感器融合避障及电池电源管理等知识点可作为多足机器人控制框架的学习范本。目前已有1384人学习下载适合对照工程结构梳理外设初始化、中断处理与任务划分思路快速搭建自己的蜘蛛机器人控制程序。1. 蜘蛛机器人STM32F103控制程序从舵机抖动到步态稳定的完整实现很多人第一次拿到蜘蛛机器人STM32F103控制程序源码时第一反应是“这不就是个多舵机驱动吗”结果烧进去一看机器人要么趴着不动要么六条腿各走各的像喝醉了一样。这个项目解决的就是这类问题它是一套运行在STM32F103上的六足机器人控制程序核心任务是把18路PWM舵机协调成稳定的三角步态让机器人能前进、后退、转向甚至做一些简单的姿态调整。适合谁适合已经玩过STM32最小系统、想从点灯和串口进阶到多轴运动控制的开发者也适合做毕设或课程设计、需要一套能跑起来的完整控制框架的人。源码里包含了舵机驱动、步态调度、串口指令解析这几个关键模块不是那种只给几个头文件的空壳工程。2. 硬件架构与工程目录18路舵机怎么接到STM32F103上2.1 硬件连接方案与定时器分配蜘蛛机器人一般用18个舵机每条腿3个关节髋、膝、踝。STM32F103的定时器资源有限不可能一个定时器管一个舵机常见做法是用TIM1、TIM2、TIM3、TIM4四个定时器每个定时器出4路PWM加起来16路再补两路用TIM5或者软件PWM。这个项目里用的是TIM1到TIM4的16路加TIM5的两路总共18路刚好覆盖。舵机的信号线接在定时器的CH1到CH4上电源线单独走5V或6V的稳压模块地线共地。这里有个血泪经验千万不要用STM32板子上的3.3V给舵机供电舵机启动瞬间的电流能把MCU拉复位。我一般会用一个独立的5V/10A开关电源给舵机STM32只用USB供电两边共地就行。// servo.h 定时器通道映射 #define SERVO_TIM1_CH1 TIM1, 1 #define SERVO_TIM1_CH2 TIM1, 2 // ... 省略中间通道 #define SERVO_TIM5_CH2 TIM5, 2 // 舵机编号到定时器通道的映射表 const ServoMap servo_map[18] { {TIM1, 1}, {TIM1, 2}, {TIM1, 3}, // 右前腿 髋膝踝 {TIM1, 4}, {TIM2, 1}, {TIM2, 2}, // 右中腿 // ... 其余腿 };这段映射表的作用是把“第几条腿的第几个关节”翻译成“哪个定时器的哪个通道”。参数说明ServoMap结构体里存的是定时器外设指针和通道号初始化的时候遍历这个表逐个配置PWM。改机器人腿的顺序时只需要改这个表不用动底层驱动。2.2 工程目录结构与模块划分源码的目录结构大致是这样的SpiderRobot_STM32F103/ ├── Core/ │ ├── Inc/ │ │ ├── servo.h // 舵机驱动接口 │ │ ├── gait.h // 步态生成 │ │ ├── ik.h // 逆运动学解算 │ │ └── cmd_parser.h // 串口指令解析 │ └── Src/ │ ├── main.c // 主循环与初始化 │ ├── servo.c // PWM输出与角度映射 │ ├── gait.c // 三角步态调度 │ ├── ik.c // 足端坐标到关节角度 │ └── cmd_parser.c // 指令解析 ├── Drivers/ │ └── STM32F1xx_HAL_Driver/ └── MDK-ARM/ └── SpiderRobot.uvprojx // Keil工程文件这个划分的好处是舵机驱动只管发PWM步态模块只管决定“什么时候抬哪条腿”逆运动学只管算角度。三者通过一个结构体传递数据耦合度低。常见做法是定义一个RobotState结构体里面存当前足端坐标、关节角度、步态相位各个模块读写这个结构体的不同字段。注意如果你用的是标准库而不是HAL库servo.c里的PWM配置要换成TIM_OCInitTypeDef那套但接口函数名可以保持不变这样上层步态代码不用改。3. 核心模块拆解从PWM到三角步态的完整链路3.1 舵机驱动角度到脉宽的线性映射舵机控制本质就是输出一个周期20ms、高电平0.5ms到2.5ms的PWM。0.5ms对应0度2.5ms对应180度中间线性插值。STM32F103的TIM时钟一般是72MHz预分频72-1得到1MHz计数频率也就是1个计数等于1微秒。自动重装载值设成20000-1就是20ms周期。比较值设成500到2500就是0.5ms到2.5ms。// servo.c 设置某个舵机的角度 void Servo_SetAngle(uint8_t servo_id, float angle) { // 限制角度范围防止舵机堵转 if (angle 0) angle 0; if (angle 180) angle 180; // 线性映射0度-500us, 180度-2500us uint16_t pulse 500 (uint16_t)(angle * (2000.0f / 180.0f)); // 根据映射表找到定时器和通道设置比较值 TIM_TypeDef *tim servo_map[servo_id].tim; uint8_t ch servo_map[servo_id].ch; switch (ch) { case 1: tim-CCR1 pulse; break; case 2: tim-CCR2 pulse; break; // ... 其余通道 } }逻辑说明先做角度限幅避免用户传入超范围值导致舵机打到机械限位。然后做线性映射2000.0f/180.0f是每度对应的微秒数。最后直接写CCR寄存器不用HAL库的延时函数因为步态调度里会频繁调用这个函数用寄存器操作能省不少时间。参数说明servo_id是0到17对应18个舵机angle是浮点数方便逆运动学算出来的小数角度直接传进来。3.2 逆运动学足端坐标怎么变成三个关节角度蜘蛛机器人每条腿可以简化为一个三自由度的连杆机构。给定足端相对于髋关节的坐标(x, y, z)需要算出髋、膝、踝三个舵机的角度。这里用的是几何法不是DH参数法因为几何法在二维平面内更直观。// ik.c 单腿逆运动学解算 void IK_Solve(float x, float y, float z, float *hip, float *knee, float *ankle) { // 髋关节角度足端在水平面的投影角度 *hip atan2f(y, x) * 180.0f / M_PI; // 腿在垂直平面的投影长度 float L sqrtf(x*x y*y) - coxa; // coxa是髋关节到腿根的水平距离 float D sqrtf(L*L z*z); // 腿根到足端的直线距离 // 余弦定理求膝关节角度 float cos_knee (femur*femur tibia*tibia - D*D) / (2*femur*tibia); *knee acosf(cos_knee) * 180.0f / M_PI; // 踝关节角度由几何关系推导 *ankle 180.0f - *knee - atan2f(z, L) * 180.0f / M_PI; }逻辑说明hip角度是足端在水平面内相对于x轴的角度直接atan2算出来。然后算腿根到足端的直线距离D用余弦定理求膝关节的夹角。踝关节角度由三角形内角和推导。参数说明coxa、femur、tibia是三条腿段的长度单位毫米需要根据实际机械结构测量后填入。x、y、z是足端坐标一般以髋关节为原点x向前y向左z向上。提示如果机器人实际运动方向和预期相反先检查hip角度的正方向定义很多翻车都是因为坐标系定义和机械安装对不上。3.3 三角步态调度六条腿怎么分组才不摔三角步态的核心思想是把六条腿分成两组每组三条腿构成一个三角形支撑面。一组抬起向前摆的时候另一组支撑身体向后蹬。这样任意时刻至少有三条腿着地机器人不会摔。// gait.c 三角步态更新 void Gait_Update(RobotState *state) { // 步态相位0到1循环 state-phase state-speed; if (state-phase 1.0f) state-phase - 1.0f; // 分组A右前、左中、右后 // 分组B左前、右中、左后 for (int i 0; i 6; i) { float leg_phase state-phase; if (i % 2 1) { // 分组B相位偏移0.5 leg_phase 0.5f; if (leg_phase 1.0f) leg_phase - 1.0f; } // 抬腿阶段0到0.5腿抬起并前摆 // 支撑阶段0.5到1腿着地并后蹬 if (leg_phase 0.5f) { state-foot[i].z lift_height * sinf(leg_phase * 2 * M_PI); state-foot[i].x stride * (leg_phase * 2 - 0.5f); } else { state-foot[i].z 0; state-foot[i].x stride * (1.5f - leg_phase * 2); } } }逻辑说明phase是全局步态相位speed控制步频。分组B的相位偏移0.5这样两组腿交替抬起。抬腿阶段用正弦函数让足端平滑抬起和落下避免突然离地导致机身晃动。支撑阶段足端x坐标线性后移推动身体前进。参数说明lift_height是抬腿高度一般20到30毫米stride是步幅根据腿长决定太大容易扯到关节。3.4 串口指令解析怎么用上位机控制机器人项目里用串口接收上位机指令格式是简单的ASCII字符串比如“F”前进、“B”后退、“L”左转、“R”右转、“S”停止。解析函数放在主循环里轮询不用中断因为指令频率不高。// cmd_parser.c 指令解析 void CMD_Parse(RobotState *state, uint8_t *buf, uint16_t len) { for (uint16_t i 0; i len; i) { switch (buf[i]) { case F: state-speed 0.02f; state-direction 0; break; case B: state-speed -0.02f; state-direction 0; break; case L: state-direction -0.5f; break; case R: state-direction 0.5f; break; case S: state-speed 0; state-direction 0; break; default: break; } } }逻辑说明遍历接收缓冲区遇到对应字符就修改RobotState里的速度和方向。speed是步态相位的增量正数前进负数后退。direction是转向分量会叠加到足端y坐标上实现差速转向。参数说明buf是串口接收缓冲区len是本次接收到的字节数。常见做法是在主循环里用HAL_UART_Receive轮询接收超时设10ms不阻塞步态更新。4. 编译、烧录与调试让机器人第一次站起来4.1 Keil工程配置与编译选项源码包里的MDK-ARM目录下有现成的uvprojx工程文件用Keil MDK打开就能编译。但有几个地方需要检查一是器件型号要选STM32F103C8T6或者你实际用的型号二是C/C选项卡里的预定义宏要有USE_HAL_DRIVER和STM32F103xB三是下载器选ST-Link还是J-Link要和实际硬件一致。# 如果用命令行编译可以用arm-none-eabi-gcc arm-none-eabi-gcc -mcpucortex-m3 -mthumb \ -DUSE_HAL_DRIVER -DSTM32F103xB \ -ICore/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc \ -c Core/Src/main.c -o build/main.o这段命令的含义指定Cortex-M3内核和Thumb指令集定义两个宏让HAL库知道用哪个芯片包含头文件路径编译main.c。参数说明-mcpu和-mthumb是必须的否则链接会报错-D开头的宏定义要和Keil里保持一致不然HAL库会走错分支。4.2 舵机中位校准与机械安装烧录之前先把所有舵机转到中位再安装腿。中位就是Servo_SetAngle(id, 90)的位置。如果先装腿再上电舵机可能会因为初始角度不对把腿拧断。我一般会写一个校准模式上电后所有舵机慢慢转到90度等5秒再进入正常步态。// main.c 校准模式 void Calibration_Mode(void) { for (int i 0; i 18; i) { Servo_SetAngle(i, 90); // 全部转到中位 } HAL_Delay(5000); // 等5秒让机械安装到位 }逻辑说明这个函数在main初始化之后、进入主循环之前调用。5秒的延时是给安装留时间实际调试时可以改成串口触发。参数说明90是中位角度如果你的舵机中位不是90改成实际值。4.3 串口调试与步态参数整定机器人站起来之后用串口助手发“F”看能不能走。如果走起来像抽搐一般是步态参数不对。先调speed从0.01开始慢慢加找到不摔的最大值。再调lift_height太低会拖地太高会晃。最后调stride太大腿会打架。注意调试的时候把机器人架空让腿悬空先看动作对不对再放到地上。直接放地上调参数摔几次舵机就扫齿了。5. 避坑与常见问题舵机抖动、步态错乱、串口没反应5.1 舵机抖动或不动现象上电后舵机嗡嗡响但不转或者偶尔抽一下。原因PWM周期不对或者比较值超出了500到2500的范围。解决用示波器看PWM波形确认周期是20ms高电平在0.5到2.5ms之间。如果没有示波器把Servo_SetAngle的输入固定成90用万用表测信号线电压应该是1.5V左右平均值。5.2 步态错乱腿的顺序不对现象机器人走起来像螃蟹或者两条腿同时抬。原因servo_map映射表和实际接线对不上或者分组逻辑写反了。解决先写一个测试函数让18个舵机依次从0转到180再转回来记录每个舵机对应的腿和关节。然后对照servo_map改映射表。分组逻辑检查i%2那行如果分组反了把0.5的偏移加到另一组。5.3 串口发送指令没反应现象串口助手显示发送成功但机器人不动。原因串口接收中断没开或者波特率不对。解决检查main里的MX_USART1_UART_Init波特率一般是115200。如果用的是轮询接收确认HAL_UART_Receive的返回值是HAL_OK。常见做法是在接收回调里把数据存到环形缓冲区主循环再从缓冲区取避免阻塞。5.4 机器人走几步就复位现象刚开始正常走几秒后突然重启。原因舵机电流太大导致5V电源跌落STM32的BOR复位。解决给舵机电源并联一个大电容1000uF以上或者换更大电流的电源。STM32的供电和舵机供电分开走线只在电源地处共地。5.5 逆运动学算出来的角度是NaN现象串口打印关节角度有时候是nan。原因余弦定理里cos_knee超出了-1到1的范围一般是D大于femurtibia腿够不着。解决在IK_Solve里加限幅把cos_knee限制在-1到1之间。同时检查输入的足端坐标是不是超出了腿的工作空间。6. 二次开发改步态、加传感器、换主控的实操思路拿到这套源码之后最常改的三个方向是换步态、加传感器、换主控。换步态最简单gait.c里的三角步态改成波形步态或者四足步态只需要改Gait_Update里的相位分配逻辑。比如波形步态是每条腿依次抬相位差1/6改起来就是leg_phase state-phase i * (1.0f/6.0f)。加传感器的话常见的是加MPU6050做姿态反馈把俯仰角和横滚角读出来叠加到足端z坐标上实现坡道自适应。换主控比如换成STM32F4主要改时钟配置和PWM频率上层步态和逆运动学代码基本不用动。// 加MPU6050姿态补偿的示例 void Gait_UpdateWithIMU(RobotState *state, float pitch, float roll) { // 原来的步态更新 Gait_Update(state); // 姿态补偿根据俯仰角调整前后腿的高度 for (int i 0; i 6; i) { float comp pitch * state-foot[i].x * 0.01f; // 补偿系数 state-foot[i].z comp; } }逻辑说明先跑原来的步态得到基础足端坐标然后根据俯仰角对z坐标做线性补偿。x越大的腿前腿补偿越多x为负的后腿补偿相反。参数说明pitch是俯仰角单位度0.01f是补偿系数需要实际调试。这个改动不需要动ik.c和servo.c只在步态层加一个函数。验证方法改完步态之后先把机器人架空用串口打印每条腿的足端坐标和关节角度看波形是不是平滑。然后放到地上低速跑用手机慢动作拍下来逐帧看抬腿和落地的时序。我一般会保留一个“调试模式”串口发“D”进入机器人只做单腿动作方便定位问题。从那以后我每次改步态参数都强制走一遍“架空看波形、低速看落地、高速看稳定性”这三步不再直接上地跑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑