尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

ROS+STM32移动机器人底盘控制:从PID闭环到卡尔曼滤波实战

ROS+STM32移动机器人底盘控制:从PID闭环到卡尔曼滤波实战 简介基于ROS的智能移动机器人底盘控制系统开发项目面向机器人、嵌入式及自动化方向的学生与开发者围绕硬件驱动、数据采集、控制算法和运动学建模形成完整实现可解决底盘控制从零搭建的工程实现问题适合作为课程设计、毕业设计或实战参考。压缩包内共405个文件整体约14.45MB以C语言源文件与头文件、编译中间产物及Keil工程配置为主同时包含TXT、PDF、DOCX等说明与设计文档分类清晰、便于检索。目前已有62人学习下载体量适中便于快速概览与二次开发。项目中实现了L298N电机驱动模块的底盘动力控制、MPU6050六轴姿态传感器的数据采集与处理、PID闭环控制算法实时调节电机参数并通过卡尔曼滤波融合传感器数据以优化底盘运动学模型可学习底层驱动编写、数据融合与闭环控制实现。附赠的设计说明、使用说明和源代码可辅助读者掌握系统搭建流程、参数整定方法与调试思路为后续在ROS框架下扩展更多机器人功能提供基础。1. 从底盘打滑到姿态漂移为什么这套ROS控制框架值得拆开看做移动机器人底盘最头疼的不是电机不转而是转起来之后车走不直。轮子空转、地面摩擦不均、电池电压跌落导致PWM占空比漂移这些问题叠加在一起会让一个简单的直行任务演变成持续修正方向的拉锯战。本项目的价值在于它不是一套只停留在ROS话题层的仿真框架而是把STM32F103C底层的定时器PWM输出、L298N双H桥驱动、MPU6050六轴姿态采集、PID闭环调速和卡尔曼滤波数据融合全部串起来的一套完整落地链路。这套系统的适用人群很明确已经在用ROS跑仿真、但一上真车就发现里程计漂得没法看的人或者手上有STM32开发板但不知道怎么和ROS生态对接的嵌入式工程师。文中所有代码和调参思路都基于实际底盘调试场景读完可以直接改到自己的差速底盘上不需要额外购买昂贵的主控板或驱动模块。2. L298N电机驱动与STM32定时器PWM输出先把力气活干好2.1 为什么选L298N而不是DRV8833或TB6612L298N是意法半导体推出的双路全桥驱动器内部集成了四通道推挽式功率放大器单路持续输出电流可达2A峰值电流3A。相比DRV8833这类低压微步进驱动芯片L298N的优势在于供电范围宽逻辑部分5V电机部分最高46V对于使用12V直流减速电机、堵转电流可能冲到2.5A以上的底盘来说不需要额外加一级电流放大电路。但L298N有一个经常被忽略的损耗问题——它的饱和压降在2A负载下可以达到2V左右。这意味着12V供电时电机端口实际只有10V满占空比下转速会比理论值低约15%。这在开环控制下不是大问题但接上PID闭环之后这个压降会直接影响电机模型的增益标定后面调PID参数时会发现Kp很难调大原因就在这里。2.2 接线方式和使能引脚的硬件逻辑底盘电机一般为两路左电机接OUT1/OUT2右电机接OUT3/OUT4。逻辑输入IN1到IN4连接STM32的GPIOENA和ENB接定时器的PWM输出通道。注意L298N的ENA/ENB是高电平使能低电平直接关断输出所以如果用跳线帽短接到5V就失去了调速能力只能做正反转控制。L298N STM32F103C IN1 PA5 IN2 PA6 IN3 PA7 IN4 PB0 ENA PA0 (TIM2_CH1) ENB PA1 (TIM2_CH2) GND GND (必须共地) 12V 11.1V 锂电池组 5V 悬空或给STM32板供电(可选)接线有三个关键点。第一是STM32和L298N必须共地否则逻辑电平没有参考基准IN引脚状态会随机跳变导致电机乱转。第二是L298N板载的5V稳压输出只能给逻辑电路用如果STM32的传感器模块比如MPU6050从这路取电电机启动瞬间的电流冲击会把5V拉低到4.2VIMU数据直接爆掉。第三是电机电源输入端的100uF电解电容必须保留这是抑制电机换向时反电动势尖峰的关键去掉之后轻则I2C通信偶尔失败重则复位STM32。2.3 STM32定时器PWM的初始化配置电机调速本质上是对PWM占空比的控制但定时器分频系数和重载值直接影响PWM频率。底盘电机一般选择10kHz到20kHz的PWM频率低于5kHz会听到明显的啸叫高于20kHz则驱动芯片的开关损耗上升。void TIM2_PWM_Init(uint16_t freq_khz) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); // PA0和PA1配置为复用推挽输出 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(GPIOA, GPIO_InitStructure); // 72MHz / (711) 1MHz计数频率重载值100-1 10kHz PWM TIM_TimeBaseStructure.TIM_Prescaler 71; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period 100 - 1; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure); // PWM模式1计数值小于CCR时输出高电平 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 0; TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM2, TIM_OCInitStructure); TIM_OC2Init(TIM2, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM2, ENABLE); TIM_Cmd(TIM2, ENABLE); }这段配置里最关键的是预分频值71和重载值100的组合。STM32F103系统时钟72MHz预分频71后计数频率为1MHz周期设为100得到的PWM频率就是1MHz除以100等于10kHz。占空比精度是1%即CCR寄存器写入0到99对应0%到99%占空比。如果觉得1%粒度太粗可以把预分频设小、周期设大代价是PWM频率降低。底盘场景下1%的占空比间隔对应大约3到5转每分钟的转速变化对一般底盘控制足够了。2.4 左右电机转向控制与死区处理L298N的正反转逻辑是IN1高IN2低为正转IN1低IN2高为反转两个引脚同高同低则刹车。方向切换必须在PWM占空比归零后进行否则大电流下瞬间翻转H桥会导致MOS管应力过大。实际调试中还要处理PWM死区——占空比低于12%时电机转矩不足以克服静摩擦这个区间内电机不转PID积分项会持续累积制造超调。void Motor_SetSpeed(int16_t speed_left, int16_t speed_right) { // 输入范围为-1000到10001000对应100%占空比 if (speed_left 0) { IN1_HIGH(); IN2_LOW(); TIM_SetCompare1(TIM2, (uint16_t)(speed_left / 10)); } else if (speed_left 0) { IN1_LOW(); IN2_HIGH(); TIM_SetCompare1(TIM2, (uint16_t)(-speed_left / 10)); } else { IN1_HIGH(); IN2_HIGH(); TIM_SetCompare1(TIM2, 0); } // 右电机逻辑相同使用TIM2_CH2 // 死区补偿小于120的PWM命令直接归零 if (speed_left -120 speed_left 120) { speed_left 0; } }这段代码里有一个底盘的通用处理套路带符号的电机速度命令正负号决定方向引脚电平绝对值决定PWM比较值。死区补偿放在最前面判断避免PID输出的小幅震荡值在电机不转的区间内反复切换正反转这会加速H桥磨损并且产生刺耳噪音。3. MPU6050姿态采集与数据预处理从原始寄存器到可用角度3.1 六轴数据的硬件层面解读MPU6050内部集成了三轴MEMS陀螺仪和三轴MEMS加速度计陀螺仪量程可配置为±250、±500、±1000、±2000度每秒加速度计量程为±2g、±4g、±8g、±16g。底盘控制场景下陀螺仪用±500度每秒足够应对原地旋转加速度计用±2g可以获得最高精度。通过I2C接口读取原始值时需要根据配置的量程换算成物理量。以陀螺仪±500度每秒为例16位ADC输出范围为-32768到32767灵敏度为65.5 LSB/度/秒。加速度计±2g时灵敏度为16384 LSB/g。这个换算系数在姿态解算时直接参与运算写错一个数量级会导致角度输出完全混乱。// MPU6050初始化时的量程配置 uint8_t buf[2]; buf[0] 0x1B; // GYRO_CONFIG寄存器 buf[1] 0x08; // ±500度每秒 IIC_WriteBytes(MPU6050_ADDR, buf, 2); buf[0] 0x1C; // ACCEL_CONFIG寄存器 buf[1] 0x00; // ±2g IIC_WriteBytes(MPU6050_ADDR, buf, 2);3.2 使用DMP硬件解算还是软件解算MPU6050内置的DMPDigital Motion Processor可以直接输出四元数省去在MCU上跑姿态解算算法的算力开销。DMP的移植通常使用InvenSense的libmpl库初始化时调用mpu_init()、mpu_set_sensors()和dmp_enable_feature()最后在循环中通过dmp_read_fifo()取四元数再转换成欧拉角。DMP方案的优势是省事且直接输出融合后的姿态但项目源码中包含了inv_mpu.c和inv_mpu_dmp_motion_driver.c这两个文件这说明它走的是InvenSense官方库路线。这套库有个坑DMP内部的姿态解算更新频率固定为200Hz而底层传感器的原始输出是1kHz如果控制频率是500HzDMP的数据反而是瓶颈。对于底盘控制这种场景更新频率不需要太高200Hz完全够用但用户需要清楚这个频率限制。软件解算一般用Mahony互补滤波或梯度下降法核心思路是加速度计提供长期稳定的姿态基准陀螺仪提供短期快速响应两者通过权重融合。互补滤波实现简单只需要两个参数但动态响应和噪声抑制能力不如卡尔曼滤波细腻。3.3 原始数据的滤波与零漂处理MPU6050的陀螺仪输出存在零偏问题——静止状态下读数不是0而是在某个固定值附近波动。这个零偏直接积分会导致姿态角不断漂移必须做校准。常见的做法是在系统启动时让机器人保持静止采样200到500次求平均将平均值作为零偏值保存。float gyro_offset[3] {0, 0, 0}; #define SAMPLE_NUM 300 void MPU6050_GyroCalibration(void) { int16_t raw[3]; float sum[3] {0, 0, 0}; for (int i 0; i SAMPLE_NUM; i) { MPU6050_ReadRawGyro(raw); sum[0] (float)raw[0] / 65.5f; sum[1] (float)raw[1] / 65.5f; sum[2] (float)raw[2] / 65.5f; delay_ms(2); } gyro_offset[0] sum[0] / SAMPLE_NUM; gyro_offset[1] sum[1] / SAMPLE_NUM; gyro_offset[2] sum[2] / SAMPLE_NUM; }这个校准过程放在电机使能之前执行。注意采样时间不能太短300次采样加上2毫秒延时共耗时约600毫秒太短则平均值不够稳定太长则启动时用户等待感明显。校准完成后每次读取陀螺仪数据都减去零偏值再参与积分运算。3.4 一阶低通滤波在加速度计数据上的应用加速度计的噪声主要来自底盘电机振动特别是齿轮箱啮合产生的几百赫兹的高频振动。对这种高频噪声最简单的办法是一阶低通滤波。float acc_filtered[3] {0, 0, 0}; float acc_raw[3]; float alpha 0.1f; // 滤波系数越小滤波越强延迟越大 void MPU6050_AccFilter(void) { MPU6050_ReadRawAccel(acc_raw); for (int i 0; i 3; i) { acc_filtered[i] alpha * acc_raw[i] (1 - alpha) * acc_filtered[i]; } }这里alpha取0.1意味着新数据只占10%的权重滤波效果强但延迟约20毫秒。底盘运动控制场景下这个延迟是可接受的因为加速度计主要用于低频的姿态修正。但如果机器人高速运动或快速加减速过大的滤波系数会导致加速度计响应滞后。经验做法是把alpha设在0.05到0.2之间再配合后面将要提到的卡尔曼滤波让陀螺仪的快速响应来弥补加速度计的延迟。4. PID闭环控制算法实现底盘稳定运行的核心4.1 位置式PID和增量式PID的选型底盘速度环PID分为位置式和增量式两种实现。位置式PID直接计算当前时刻的完整控制量公式为u(k) Kp*e(k) Ki*sum(e) Kd*(e(k)-e(k-1))它的缺点是积分项是误差的累积和一旦长时间无法消除误差积分饱和会产生很大的控制量。增量式PID计算的是控制量的增量即du(k) Kp*(e(k)-e(k-1)) Ki*e(k) Kd*(e(k)-2*e(k-1)e(k-2))最终输出为u(k) u(k-1) du(k)。增量式PID在底盘控制中的优势在于输出是增量而非全量即使计算错误也不会导致电机瞬间全速运转积分项被隐含在增量计算中不容易出现积分饱和。缺点是它只能输出递增递减的增量如果执行机构需要保持某个固定位置需要额外保存累积值。typedef struct { float target; float actual; float err_now; float err_last; float err_prev; float Kp; float Ki; float Kd; float output; float output_last; float output_max; } PID_TypeDef; void PID_Incremental_Calc(PID_TypeDef *pid) { pid-err_now pid-target - pid-actual; float delta pid-Kp * (pid-err_now - pid-err_last) pid-Ki * pid-err_now pid-Kd * (pid-err_now - 2 * pid-err_last pid-err_prev); pid-output delta; // 输出限幅 if (pid-output pid-output_max) { pid-output pid-output_max; } else if (pid-output -pid-output_max) { pid-output -pid-output_max; } pid-err_prev pid-err_last; pid-err_last pid-err_now; pid-output_last pid-output; }增量式PID结构中输出是不断累加的结果所以初始output_last必须清零。限幅值output_max应该和PWM最大占空比对应本项目中将速度范围映射到-1000到1000因此output_max设为1000。转速死区通过前面章节提到的死区补偿来处理在PID_Incremental_Calc计算完成后、写入电机驱动函数前增加死区判断即可。4.2 编码器反馈与速度测量M法和T法PID闭环需要速度反馈。底盘电机可选配霍尔编码器常见的有13线和11线两种经过倍频后每圈可输出52或44个脉冲。速度测量有两种方法M法测频法统计固定时间窗口内的脉冲数适合高速测量T法测周法统计两个相邻脉冲之间的时间间隔适合低速测量。底盘场景下电机转速一般在每分钟100到1000转之间对应每10毫秒21到210个脉冲使用M法即可获得足够的精度。测量周期设为10毫秒与PID计算周期保持一致。int16_t encoder_left; int16_t speed_left; void TIM3_IRQHandler(void) { if (TIM_GetITStatus(TIM3, TIM_IT_Update) ! RESET) { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); speed_left encoder_left * 1000 / 52; // 每圈52脉冲1秒100次更新 encoder_left 0; } }这个中断处理函数每10毫秒触发一次encoder_left是在另一个编码器接口中断里累加的脉冲计数。速度换算的关键是系数1000除以52每10毫秒更新一次1秒更新100次脉冲数乘以100得到每秒脉冲数再除以每圈脉冲数52得到每秒多少圈再乘以1000换算成用整数表示的速度值。4.3 整定流程先比例后积分再微分PID参数整定是底盘调试中最花时间的环节。经验做法是采用先P后I再D的顺序。第一步把Ki和Kd设为0从小到大增加Kp观察电机对阶跃目标的响应。当Kp增加到系统出现持续振荡时记录此时的Kp值作为临界增益Kc振荡周期记为Tc。第二步根据齐格勒-尼科尔斯经验公式设定初始参数Kp 0.6 * KcKi 2 * Kp / TcKd Kp * Tc / 8。第三步在这个基础上微调一般底盘惯量较小的Kp可以适当加大Ki要克制因为积分项处理的是静态误差太大的Ki会让底盘在不平整地面上产生抖动。实际调试中一个常见问题是左右电机参数不一致。两个电机即使型号相同由于减速箱摩擦差异相同PWM下转速可能偏差5%到10%。解决办法是分别对左右电机做闭环标定记录PID输出相同值时的转速差然后在速度指令层面对差值进行补偿而不是在PID参数层强行拉齐。4.4 级联PID结构速度环和位置环的分工如果底盘需要精确控制位置而不是速度单环PID不够用。级联PID的结构是外环位置环输出目标速度给内环速度环内环速度环输出PWM给电机。位置环响应慢速度环响应快两者带宽需要拉开至少3倍否则会产生共振。// 外环位置PID计算目标速度 PID_TypeDef pos_pid {0, 0, 0, 0, 0, 1.2f, 0, 0, 0, 0, 800}; // 内环速度PID计算PWM PID_TypeDef vel_pid {0, 0, 0, 0, 0, 0.8f, 0.05f, 0.01f, 0, 0, 1000}; // 控制周期主循环 10ms void Control_Loop(void) { pos_pid.actual chassis_position; PID_Incremental_Calc(pos_pid); vel_pid.target pos_pid.output; vel_pid.actual measured_speed; PID_Incremental_Calc(vel_pid); Motor_SetSpeed(vel_pid.output, vel_pid.output); }位置环的output_max设为800是为了限制目标速度上限防止距离误差较大时外环输出一个过高的速度指令。5. 卡尔曼滤波与底盘运动学模型让姿态和位置数据真正可信5.1 卡尔曼滤波在MPU6050数据融合中的角色MPU6050的加速度计在静止时测得的重力向量可以计算出俯仰角和横滚角但动态情况下线性加速度会污染测量值。陀螺仪积分得到的角度在短时间内非常准确但随时间漂移。卡尔曼滤波的基本思想是利用系统的状态方程和观测方程在预测和更新之间找到最优估计。对于底盘的单轴角度估计系统状态只包含两个变量角度和陀螺仪零偏。状态方程可以写成角度(k1) 角度(k) (陀螺仪角速度 - 零偏) * dt 零偏(k1) 零偏(k)观测方程是加速度计计算出的角度。整个过程可以分为预测和更新两步预测阶段用陀螺仪数据递推状态更新阶段用加速度计观测值修正状态。零偏作为状态的一部分被实时估计这意味着卡尔曼滤波可以代替前面讲的静态校准过程在运行中自动跟踪零偏的变化。typedef struct { float angle; float bias; float P[2][2]; // 协方差矩阵 } KalmanState; void Kalman_Init(KalmanState *state) { state-angle 0; state-bias 0; state-P[0][0] 1; state-P[0][1] 0; state-P[1][0] 0; state-P[1][1] 1; } float Kalman_Update(KalmanState *state, float gyro_rate, float acc_angle, float dt) { // 预测阶段使用陀螺仪积分 state-angle (gyro_rate - state-bias) * dt; // 预测协方差Q是过程噪声协方差 float Q_angle 0.001f; float Q_bias 0.003f; state-P[0][0] dt * (dt * state-P[1][1] - state-P[0][1] - state-P[1][0] Q_angle); state-P[0][1] - dt * state-P[1][1]; state-P[1][0] - dt * state-P[1][1]; state-P[1][1] Q_bias * dt; // 更新阶段使用加速度计测量值修正 float R_measure 0.03f; // 测量噪声协方差 float S state-P[0][0] R_measure; float K[2]; // 卡尔曼增益 K[0] state-P[0][0] / S; K[1] state-P[1][0] / S; float y acc_angle - state-angle; state-angle K[0] * y; state-bias K[1] * y; float P00_temp state-P[0][0]; float P01_temp state-P[0][1]; state-P[0][0] - K[0] * P00_temp; state-P[0][1] - K[0] * P01_temp; state-P[1][0] - K[1] * P00_temp; state-P[1][1] - K[1] * P01_temp; return state-angle; }这里的Q_angle是角度噪声方差Q_bias是零偏噪声方差R_measure是加速度计测量噪声方差三个协方差参数共同决定了滤波的平滑程度和响应速度。Q_bias调大滤波会更信任陀螺仪响应快但角度波动大Q_bias调小滤波更信任加速度计姿态平稳但动态滞后明显。底盘场景的经验值是Q_angle0.001、Q_bias0.003、R_measure0.03车辆行进中如果姿态角波动还是偏大优先增大R_measure而不是减小Q_bias。5.2 差速底盘运动学模型的正解与逆解差速底盘的运动学模型描述的是左右轮速度和机器人线速度、角速度之间的关系。正解是根据左右轮速度计算机器人的线速度和角速度逆解是根据目标线速度和角速度计算左右轮速度。这两个方向在底盘控制中都会用到逆解用于执行ROS下发的速度指令正解用于估计机器人的位置。运动学模型的前提假设是左右轮间距为L轮子半径为r机器人运动满足纯滚动无滑移约束。在这些假设下正解公式为线速度 V (V_left V_right) / 2 角速度 W (V_right - V_left) / L 逆解公式为 V_left V - W * L / 2 V_right V W * L / 2这里实际的轮间距需要实测校准。把机器人原地旋转360度对比实际旋转角度和IMU计算角度推导出精确的轮间距。typedef struct { float wheel_base; float wheel_radius; } ChassisModel; void Chassis_InverseKinematics(ChassisModel *model, float linear_vel, float angular_vel, float *v_left, float *v_right) { if (v_left ! NULL) { *v_left (linear_vel - angular_vel * model-wheel_base / 2.0f) / model-wheel_radius; } if (v_right ! NULL) { *v_right (linear_vel angular_vel * model-wheel_base / 2.0f) / model-wheel_radius; } }逆解的输入是ROS的geometry_msgs/Twist消息中的线速度和角速度输出是左右轮的目标角速度经过单位换算后送入PID速度环。这里的输出单位是弧度每秒需要乘以减速比和编码器分辨率换算成PID的目标值。5.3 里程计推演与卡尔曼滤波的结合点差速底盘的里程计推演公式是每次控制周期内根据左右轮速度计算出线速度和角速度然后对姿态角积分更新航向再对线速度分解到X轴和Y轴积分更新位置。void Odometry_Update(float v_left, float v_right, float dt, float *x, float *y, float *theta) { float linear_v (v_left v_right) / 2.0f; float angular_v (v_right - v_left) / wheel_base; *theta angular_v * dt; // 使用IMU姿态角做修正 float avg_theta *theta angular_v * dt / 2.0f; *x linear_v * cosf(avg_theta) * dt; *y linear_v * sinf(avg_theta) * dt; }这段代码中航向角theta的更新是关键。纯靠左右轮编码器推算航向滑移误差会不断累积跑一段距离后航向偏了十度是常事。实际项目中往往把卡尔曼滤波计算出的IMU航向角直接替换掉编码器推算的theta编码器只用来推X和Y位置这样既保留了里程计的位置估计能力又避开了航向漂移问题。这种做法称为航向修正比在完全运动学模型上做全状态卡尔曼滤波简单得多效果也足够稳定。6. 卡尔曼滤波参数敏感性分析与调试技巧卡尔曼滤波在底盘应用中调试的重点不在数学推导而在参数敏感性分析。前面提到的三个噪声协方差参数Q_angle、Q_bias和R_measure它们的相对大小决定了滤波的平滑程度和响应速度。用纯代码仿真可以直观看到参数变化的影响。写一个简单的仿真脚本让加速度计角度在某个时刻从0度阶跃到10度同时叠加高斯噪声然后对比不同R_measure下滤波输出的响应时间和超调量。R_measure偏小时滤波会快速跟踪加速度计的变化代价是噪声抑制能力下降角度输出毛刺增多R_measure偏大时滤波长时间信任陀螺仪积分响应缓慢。实际工况下底盘有颠簸加速度计的振动噪声幅度会迅速上升这时候固定参数的卡尔曼滤波性能会退化。常见做法是自适应调整R_measure的值——用车轮编码器计算的线加速度作为辅助信息当检测到振动剧烈时增大R_measure平静时恢复默认值。另一个容易被忽视的调试点是不平地面上的零偏漂移。底盘的电机换向和地面冲击会让MPU6050的温度变化而MEMS陀螺仪的温度系数一般在0.02到0.05度每秒每摄氏度冬季启动时和运行半小时后的零偏差异可能达到2到3度每秒积分几分钟就能造成明显漂移。卡尔曼滤波将零偏纳入状态估计正是为了应对这种场景但需要确保Q_bias设置得足够大让滤波有追踪零偏变化的能力。如果发现底盘方向角在直行时缓慢变化检查Q_bias是否设置得过小。底盘转向角度和IMU的Yaw角之间的校准也可以用卡尔曼滤波来辅助。将底盘放在转盘上手动旋转已知角度对比里程计推演的角度和卡尔曼滤波输出的角度两者的差值可以标定轮间距的实际值。轮间距误差3毫米原地旋转360度后角度误差能到2度左右这直接影响路径规划的终点精度。本文还有配套的精品资源点击获取
返回列表