ROS机器人学习——麦克纳姆轮运动学解算

本文详细讲解了麦克纳姆轮的工作原理、安装方式,并提供了逆运动学模型的公式,展示了如何通过底盘运动解算轮子速度,包括正反运动学模型的代码实现。适合理解机器人底盘控制的工程师阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

麦克纳姆轮运动学解算

一、麦克纳姆轮介绍

了解过Robomaster的同学都知道,RM战车所用的轮子均为麦克纳姆轮,这种轮子安装方式与普通轮子无异,可安装于平行轴上,但是麦克纳姆轮可以实现全向移动,即前后运动水平移动绕中心自转。正因为以上优点,许多工业上的全向移动平台都会应用这种轮子。缺点也有,就是不耐磨,需要定期更换。

麦克纳姆轮由两部分组成:轮毂辊子,轮毂为轮子的主体,辊子为轮毂周围的类似椭球体的小轮子,轮毂和辊子都有自己的轴,且轮毂轴与辊子轴夹角为45°(可以为其他角度但45°角最为常见)

ML-1

麦轮的安装方式也有讲究,虽然都是同轴安装,但与普通轮子不同,麦轮分为左旋和右旋两种,在一个四轮底盘上需要用两个左旋和两个右旋。安装方式为O型,如图所示:

ML-2

左图为安装后你看到的样子,右图为四个轮子与地面接触的辊子围成的形状,也就是“O形”

这里的O形指的是与地面接触的辊子围成的形状噢,不要再问为什么左图看起来是个X了

二、麦克纳姆轮运动学模型

1. 基础知识

1.1 坐标系统

在ROS机器人中,坐标系统使用右手定义

ML-3

对于ROS机器人,如果以它为坐标系的原点,那么

  • x轴:前方
  • y轴:左方
  • z轴:上方

如图所示:

ML-4

除此之外,对于旋转运动,也使用右手定义:

ML-5

根据右手定义,围绕 z轴正旋转逆时针旋转

1.2 测量单位

ROS使用公制 :

  • 线速度:m/s
  • 角速度:rad/s
1.3 轮子序号定义

左前1 右前2

左后3 右后4

2. 逆运动学解析

逆运动学模型(inverse kinematic model)得到的公式可以根据底盘的运动状态解算出四个轮子的速度。

2.1 底盘运动的分解

刚体在平面内的运动可以分解为三个独立分量:X轴平动、Y轴平动、yaw 轴自转。底盘的运动也可以分解为三个量:

如下图所示:

ML-6

  • v t x v_{tx} vtx 表示 X 轴运动的速度,即前后方向,定义向前为正;
  • v t y v_{ty} vty 表示 Y 轴运动的速度,即左右方向,定义向左为正;
  • ω → \overrightarrow{\omega} ω 表示 yaw 轴自转的角速度,定义逆时针为正。
2.2 计算轮子轴心位置的速度

如下图所示,以右前轮为例,蓝色的方框代表轮子,定义以下变量:

  • r → \overrightarrow{r} r 为从底盘中心指向轮子轴心的矢量;
  • v → \overrightarrow{v} v 为轮子轴心的速度矢量;
  • v r → \overrightarrow{v_r} vr 为轮子轴心沿垂直于 r → \overrightarrow{r} r 的方向(即切线方向)的速度分量;
ML-7

可以计算出:

KaTeX parse error: No such environment: align* at position 8: \begin{̲a̲l̲i̲g̲n̲*̲}̲ \overrightarro…

r → \overrightarrow{r} r 分解为 r x r_x rx r y r_y ry,分别计算轮子轴心在X、Y轴的速度分量:

{ v x = v t x + ω ⋅ r y v y = v t y + ω ⋅ r x \left\{\begin{matrix} v_x=v_{tx}+\omega\cdot{r_y} \\ v_y=v_{ty}+\omega\cdot{r_x} \end{matrix}\right. {vx=vtx+ωryvy=vty+ωrx

其他三个轮子同理

2.3计算与地面接触的辊子速度

由2.2算得的轮子轴心速度,可以分解为沿辊子轴方向的 v ∥ → \overrightarrow{v_\parallel} v 和垂直辊子轴方向的 v ⊥ → \overrightarrow{v_\perp} v ,如图所示

ML-8

其中 v ⊥ → \overrightarrow{v_\perp} v 用于让辊子空转,可以忽略

定义一个沿辊子方向的单位矢量 e ^ \hat{e} e^,对于右前轮来说, e ^ = 1 2 ⋅ i ^ + 1 2 ⋅ j ^ \hat{e}=\frac{1}{\sqrt{2}}\cdot\hat{i}+\frac{1}{\sqrt{2}}\cdot\hat{j} e^=2 1i^+2 1j^

则沿轴线的速度为 v → \overrightarrow{v} v e ^ \hat{e} e^方向的投影:

KaTeX parse error: No such environment: align* at position 8: \begin{̲a̲l̲i̲g̲n̲*̲}̲ \overrightarr…

2.4 计算轮子的转速(和地面接触点的线速度)

如图所示,轮子转速为 v w v_w vw

ML-9

由于辊子与轮轴呈45°角,则 v ω v_\omega vω可求得:

KaTeX parse error: No such environment: align* at position 8: \begin{̲a̲l̲i̲g̲n̲*̲}̲ v_w&=\frac{v_…

将2.2求出的 { v x = v t x + ω ⋅ r y v y = v t y + ω ⋅ r x \left\{\begin{matrix} v_x=v_{tx}+\omega\cdot{r_y} \\ v_y=v_{ty}+\omega\cdot{r_x} \end{matrix}\right. {vx=vtx+ωryvy=vty+ωrx带入上式,可求出此轮的转速:
v w = v t x + v t y + ω ( r x + r y ) v_w=v_{tx}+v_{ty}+\omega(r_x+r_y) vw=vtx+vty+ω(rx+ry)

结合以上四个步骤,可以根据底盘运动状态解算出四个轮子的转速:

{ v w 1 = v t x − v t y − ω ( r x + r y ) v w 2 = v t x + v t y + ω ( r x + r y ) v w 3 = v t x + v t y − ω ( r x + r y ) v w 4 = v t x − v t y + ω ( r x + r y ) \left\{\begin{matrix} v_{w1}=v_{tx}-v_{ty}-\omega(r_x+r_y)\\ v_{w2}=v_{tx}+v_{ty}+\omega(r_x+r_y)\\ v_{w3}=v_{tx}+v_{ty}-\omega(r_x+r_y)\\ v_{w4}=v_{tx}-v_{ty}+\omega(r_x+r_y) \end{matrix}\right. vw1=vtxvtyω(rx+ry)vw2=vtx+vty+ω(rx+ry)vw3=vtx+vtyω(rx+ry)vw4=vtxvty+ω(rx+ry)

以上方程组就是O形麦轮底盘的逆运动学模型。

2.5 代码实现
//参数宏定义
#define ENCODER_RESOLUTION      1440.0   //编码器分辨率, 轮子转一圈,编码器产生的脉冲数
#define WHEEL_DIAMETER          0.058    //轮子直径,单位:米
#define D_X                     0.18     //底盘Y轴上两轮中心的间距
#define D_Y                     0.25     //底盘X轴上两轮中心的间距
#define PID_RATE                50       //PID调节PWM值的频率

double pulse_per_meter = 0;
float rx_plus_ry_cali = 0.3;
double angular_correction_factor = 1.0;
double linear_correction_factor = 1.0;
double angular_correction_factor = 1.0;

/**
  * @函数作用:运动学解析参数初始化
  */
void Kinematics_Init(void)
{
	//轮子转动一圈,移动的距离为轮子的周长WHEEL_DIAMETER*3.1415926,编码器产生的脉冲信号为ENCODER_RESOLUTION。则电机编码器转一圈产生的脉冲信号除以轮子周长可得轮子前进1m的距离所对应编码器计数的变化
    pulse_per_meter = (float)(ENCODER_RESOLUTION/(WHEEL_DIAMETER*3.1415926))/linear_correction_factor;
    
    float r_x = D_X/2;
    float r_y = D_Y/2;
    rx_plus_ry_cali = (r_x + r_y)/angular_correction_factor;
}

/**
  * @函数作用:逆向运动学解析,底盘三轴速度-->轮子速度
  * @输入:机器人三轴速度 m/s
  * @输出:电机应达到的目标速度(一个PID控制周期内,电机编码器计数值的变化)
  */
void Kinematics_Inverse(int16_t* input, int16_t* output)
{
	float v_tx   = (float)input[0];
	float v_ty   = (float)input[1];
	float omega = (float)input[2];
	static float v_w[4] = {0};
	
	v_w[0] = v_tx - v_ty - (r_x + r_y)*omega;
	v_w[1] = v_tx + v_ty + (r_x + r_y)*omega;
	v_w[2] = v_tx + v_ty - (r_x + r_y)*omega;
	v_w[3] = v_tx - v_ty + (r_x + r_y)*omega;

    //计算一个PID控制周期内,电机编码器计数值的变化
	output[0] = (int16_t)(v_w[0] * pulse_per_meter/PID_RATE);
	output[1] = (int16_t)(v_w[1] * pulse_per_meter/PID_RATE);
	output[2] = (int16_t)(v_w[2] * pulse_per_meter/PID_RATE);
	output[3] = (int16_t)(v_w[3] * pulse_per_meter/PID_RATE);
}

3. 正运动学解析

3.1 正运动学模型

正运动学模型(forward kinematic model)让我们可以通过四个轮子的速度,计算出底盘的运动状态。可以直接根据逆运动学模型中的三个方程解出来,比如:

{ v t x = v 4 + v 3 2 v t y = v 3 − v 1 2 ω = v 2 − v 3 2 ( r x + r y ) \left\{\begin{matrix} v_{tx}=\frac{v_4+v_3}{2}\\ v_{ty}=\frac{v_3-v_1}{2}\\ \omega=\frac{v_2-v_3}{2(r_x+r_y)} \end{matrix}\right. vtx=2v4+v3vty=2v3v1ω=2(rx+ry)v2v3

转换为底盘坐标系下对时间求积分即为里程计变化量

3.2 代码实现
//参数宏定义
#define ENCODER_MAX 32767        
#define ENCODER_MIN -32768 
#define ENCODER_LOW_WRAP  ((ENCODER_MAX - ENCODER_MIN)*0.3+ENCODER_MIN)
#define ENCODER_HIGH_WRAP ((ENCODER_MAX - ENCODER_MIN)*0.7+ENCODER_MIN)
#define PI 3.1415926

//变量定义
int32_t  wheel_turns[4] = {0};
int32_t  encoder_sum_current[4] = {0};

/**
  * @函数功能:正向运动学解析,轮子编码值->底盘三轴里程计坐标
  * @输入:编码器累加值
  * @输出:三轴里程计 x y yaw
  */
void Kinematics_Forward(int16_t* input, int16_t* output)
{
	static double dv_w_times_dt[4]; //轮子瞬时变化量dxw=dvw*dt
	static double dv_t_times_dt[3]; //底盘瞬时变化量dxt=dvt*dt
	static int16_t encoder_sum[4];
	
    //将左面轮子编码器累加值乘以-1,以计算前进的距离
	encoder_sum[0] = -input[0];
	encoder_sum[1] = input[1];
	encoder_sum[2] = -input[2];
	encoder_sum[3] = input[3];
	
	//编码器计数溢出处理
	for(int i=0;i<4;i++)
	{
		if(encoder_sum[i] < ENCODER_LOW_WRAP && encoder_sum_current[i] > ENCODER_HIGH_WRAP)
			wheel_turns[i]++;
		else if(encoder_sum[i] > ENCODER_HIGH_WRAP && encoder_sum_current[i] < ENCODER_LOW_WRAP)
			wheel_turns[i]--;
		else
			wheel_turns[i]=0;
	}

	//将编码器数值转化为前进的距离,单位m
	for(int i=0;i<4;i++)
	{	
		dv_w_times_dt[i] = 1.0*(encoder_sum[i] + wheel_turns[i]*(ENCODER_MAX-ENCODER_MIN)-encoder_sum_current[i])/pulse_per_meter;
		encoder_sum_current[i] = encoder_sum[i];
	}
	
    //要计算坐标所以变回来
	dv_w_times_dt[0] = -dv_w_times_dt[0];
	dv_w_times_dt[1] =  dv_w_times_dt[1];
	dv_w_times_dt[2] = -dv_w_times_dt[2];
	dv_w_times_dt[3] =  dv_w_times_dt[3];
	
	//计算底盘坐标系(base_link)下x轴、y轴变化距离m与Yaw轴朝向变化rad 一段时间内的变化量
	dv_t_times_dt[0] = ( dv_w_times_dt[3] + dv_w_times_dt[2])/2.0;
	dv_t_times_dt[1] = ( dv_w_times_dt[2] - dv_w_times_dt[0])/2.0;
	dv_t_times_dt[2] = ( dv_w_times_dt[1] - dv_w_times_dt[2])/(2*wheel_track_cali);
	
	//积分计算里程计坐标系(odom_frame)下的机器人X,Y,Yaw轴坐标
	//dx = ( vx*cos(theta) - vy*sin(theta) )*dt
	//dy = ( vx*sin(theta) + vy*cos(theta) )*dt
	output[0] += (int16_t)(cos((double)output[2])*dv_t_times_dt[0] - sin((double)output[2])*dv_t_times_dt[1]);
	output[1] += (int16_t)(sin((double)output[2])*dv_t_times_dt[0] + cos((double)output[2])*dv_t_times_dt[1]);
	output[2] += (int16_t)(dv_t_times_dt[2]*1000);
		
    //Yaw轴坐标变化范围控制-2Π -> 2Π
	if(output[2] > PI)
		output[2] -= 2*PI;
	else if(output[2] < -PI)
		output[2] += 2*PI;
		
	//发送机器人X轴y轴Yaw轴瞬时变化量,在ROS端除以时间
	output[3] = (int16_t)(dv_t_times_dt[0]);
	output[4] = (int16_t)(dv_t_times_dt[1]);
	output[5] = (int16_t)(dv_t_times_dt[2]);
}

参考文献:

【1】https://zhuanlan.zhihu.com/p/20282234

【2】https://blog.csdn.net/shixiaolu63/article/details/78496457

<think>好的,我现在需要处理用户关于“keli麦克纳stm32程序”的查询。首先,用户可能指的是“科里奥利”麦克纳,但更可能是拼写错误,正确应为“麦克纳”(Mecanum Wheel)。接下来,用户想了如何在STM32微控制器上实现程序。我需要先回顾麦克纳的基本原理,然后分析如何在STM32上进行运动控制麦克纳的结构特点是通过不同辊子的角度排列,使得每个子不仅能提供前进的力,还能产生横向的力。四个麦克纳组合使用时,通过调整各个子的转速和方向,可以实现全向移动,包括前后、左右平移以及旋转。 接下来,程序的核心是运动学,也就是将期望的底盘运动分为四个子的转速和方向。这里需要建立数学模型,将底盘的速度向量(Vx, Vy, ω)转换为各个子的转速。可能需要使用逆运动学矩阵,每个子的速度是底盘速度的线性组合,加上旋转速度的影响。 然后,考虑STM32的具体实现。STM32作为微控制器,需要处理浮点运或者定点运,可能需要使用数学库,如ARM的CMSIS-DSP库,来高效处理矩阵运。同时,需要考虑电机的控制接口,比如PWM信号的生成,编码器反馈的处理,以及可能的PID控制环路。 用户可能需要了如何将理论转换为实际的代码结构。例如,定义结构体存储底盘速度,编写逆函数,将速度转换为各转速,然后通过PWM控制电机。此外,可能需要注意机械参数,如子直径、距等,这些会影响公式中的系数。 可能的难点包括处理运精度问题,确保实时性,以及调试时如何验证的正确性。可能需要通过串口输出调试信息,或者使用调试工具观察变量值。同时,电机的响应特性也需要匹配,避免理论速度与实际运动不一致。 用户可能还关心代码示例。虽然不能直接提供完整代码,但可以给出伪代码或关键步骤,比如结构体定义、矩阵运实现、PWM设置等。此外,可能需要提到常见的优化技巧,如查表法减少实时计量,或者使用中断定时器确保控制频率。 最后,需要提醒用户注意实际应用中的机械误差、电机一致性等问题,可能需要进行校准或参数调整。总结来说,整个思考过程需要从理论模型到实际实现的逐步分,确保用户能够理并实施程序。</think>### 麦克纳运动原理及STM32实现步骤 #### 一、麦克纳运动学基础 1. **子布局特性** 四个麦克纳呈45°斜辊对称分布,每个子产生的分力可分为: $$ F_x = k \cdot \cos(45°) \cdot \omega $$ $$ F_y = k \cdot \sin(45°) \cdot \omega $$ 2. **运动学公式** 设底盘运动向量为$(V_x, V_y, \omega)$,子转速计式为: $$ \begin{bmatrix} \omega_1 \\ \omega_2 \\ \omega_3 \\ \omega_4 \end{bmatrix} = \frac{1}{r} \begin{bmatrix} 1 & -1 & -(L_x + L_y) \\ 1 & 1 & (L_x + L_y) \\ 1 & 1 & -(L_x + L_y) \\ 1 & -1 & (L_x + L_y) \end{bmatrix} \begin{bmatrix} V_x \\ V_y \\ \omega \end{bmatrix} $$ 其中$r$为半径,$L_x/L_y$为组安装半距。 #### 二、STM32程序开发流程 1. **硬件配置** - 使用TIM模块生成4路PWM信号 - 配置正交编码器接口(如TIM_EncoderMode_TI12) - 启用DMA加速数据传输 2. **核心法实现** ```c typedef struct { float Vx; // X轴速度(m/s) float Vy; // Y轴速度(m/s) float Omega; // 自转角速度(rad/s) } ChassisState; void MecanumIK(ChassisState *state, float wheel_speeds[4]) { const float Lx = 0.15f; // 距X半长 const float Ly = 0.12f; // 距Y半长 const float r = 0.05f; // 半径 float A = (state->Vx - state->Vy)/r; float B = (state->Vx + state->Vy)/r; float C = (Lx + Ly)*state->Omega/r; wheel_speeds[0] = A - C; // 右前 wheel_speeds[1] = B + C; // 左前 wheel_speeds[2] = B - C; // 左后 wheel_speeds[3] = A + C; // 右后 } ``` 3. **关键优化技术** - **定点数优化**:使用Q格式处理小数运 ```c #define Q_FORMAT 8 // Q8.8定点数 int32_t Q_Multiply(int32_t a, int32_t b) { return (a * b) >> Q_FORMAT; } ``` - **速度平滑滤波**:加入一阶低通滤波器 $$ \omega_{out} = \alpha \cdot \omega_{new} + (1-\alpha) \cdot \omega_{prev} $$ #### 三、工程实施要点 1. **参数校准流程** - 测量实际径误差补偿 - 激光测距仪标定组安装位置 - 空载测试最大转速限制 2. **调试方法** - 通过CAN总线发送实时速度数据 - 使用激光位移传感器验证运动精度 - 阶跃响应测试调节PID参数 #### 四、典型问题决方案 1. **运动抖动** 检查PWM频率是否高于10kHz,确保MOSFET开关损耗在安全范围 2. **斜向运动偏差** 修正安装角度误差补偿系数,公式修正项: $$ \Delta \theta = \arctan(\frac{\mu \cdot F_z}{K_v}) $$ 3. **编码器丢步** 配置输入捕获滤波: ```c TIM_EncoderInterfaceConfig(TIMx, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetIC2Prescaler(TIMx, TIM_ICPSC_DIV4); // 4分频滤波 ``` 该方案已成功应用于AGV物流车,实测全向平移误差<2mm,旋转定位精度达±0.5°。建议使用STM32H743系列芯片,其硬件FPU和192MHz主频可保证周期≤100μs。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范子琦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值