超简单!!!搭建阿克曼ROS小车

0、前言

本篇文章仅是对常见阿克曼ROS小车的极简分析,并提供代码。主要是方便读者自己搭建阿克曼小车时理解使用。

这里仅针对《舵机控制前轮转向+后轮主动差速》的方式,如下图所示:

图片来源:百度图片

舵机转向机构简单示意图

舵机完成前轮的转向控制,简单示意图如下:

图片来源:Pinterest

1、整体设计

若要能实现阿克曼小车的搭建,需要明确小车的控制方式和控制数据的层级关系;如下图所示:

2、STM32底层控制部分

2.1、后轮差速控制

后轮电机差速控制和差速小车的控制方式一样,都是采用光电\霍尔编码器测速+PID闭环控制的方式,如下图所示,这里就不赘述了。

需要了解的朋友可以看之前的文章,链接如下:

2.2、前轮舵机角度控制

2.2.1、舵机选型

这里主要使用如下两种模拟舵机,常见模拟舵机都可以。

图片来源:百度图片

2.2.2、舵机控制原理

舵机是一种位置伺服驱动器,是一种带有输出轴的小装置。当我们向伺服器发送一个控制信号时,输出轴就可以转到特定的位置。只要在控制信号持续不变,伺服机构就会保持相对的角度位置不变。如果控制信号发生变化,输出轴的位置也会相应发生变化。舵机的控制大部分都是通过PWM信号控制的。

2.2.3、单片机控制舵机

模拟舵机控制一般需要20ms左右时基脉冲, 该脉冲高电平部分一般为0.5ms-2.5ms范围内角度控制脉冲部分, 总间隔为2ms。 以180度角度伺服为例, 对应控制关系如下 :

控制示意图如下:

图片来源:ArduinoGetSarted.com

2.2.4、阿克曼小车舵机控制代码:

主函数初始化:

Steer_PWM_Init(60000-1, 24-1);  //=====初始化PWM 50HZ,用于驱动舵机

PWM配置部分代码(STM32):

/**************************************************************************
函数功能:控制转向舵机的PWM初始化
入口参数:无 PB0 -> TIM1
返回  值:无
**************************************************************************/
void Steer_PWM_Init(u16 arr,u16 psc)
{GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);GPIO_PinRemapConfig(GPIO_PartialRemap_TIM1, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;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 = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;// * TIM1_CH2// TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;// TIM_OCInitStructure.TIM_Pulse = 0;// TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;// * TIM1_CH2NTIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;TIM_OC2Init(TIM1, &TIM_OCInitStructure);              //TIM_OC2 TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM1, ENABLE);                   //使能TIMx在ARR上的预装载寄存器TIM_CtrlPWMOutputs(TIM1, ENABLE);                   //MOE 主输出使能   高级定时器使用TIM_Cmd(TIM1, ENABLE);
}

前轮转向控制角度和PWM的转换函数:

//舵机PWM变量,初始安装为90度,注意机械安装时,要先转到90度再安装舵盘
int motorFrontSteer = 4500; // (60000 / 20ms) * 1.5ms = 4500 90度//舵机控制角度的设定值
int frontAngleSet = 0;// 物理结构限幅,舵机角度限幅
#define MAX_FRONT_ANGLE_SET (50)/**************************************************************************
函数功能:舵机角度控制处理(SG90)角度线性变化
入口参数:ros端设定转向角度,需要给舵机的pwm,此处可根据不同的舵机自行更改
分辨率:1度 --> ((2.5ms - 0.5ms) / 180度) * (60000 / 20ms) = 33.3
0.5ms ------------------ 0度
1.5ms ------------------ 90度
2.5ms ------------------ 180度
返回  值:无
**************************************************************************/
void Steer_Ctrl(int frontAngleSet,int *motorFrontSteer)
{// 物理结构限幅if(frontAngleSet > MAX_FRONT_ANGLE_SET){frontAngleSet = MAX_FRONT_ANGLE_SET;}if(frontAngleSet < -MAX_FRONT_ANGLE_SET){frontAngleSet = -MAX_FRONT_ANGLE_SET;}// 正常计算角度if(frontAngleSet == 0) //默认初始角度 90度{*motorFrontSteer = 4500; // (60000 / 20ms) * 1.5ms = 4500 }else if(frontAngleSet > 0) // left{*motorFrontSteer = 4500 - (int)(myabs(frontAngleSet) * 33.3 + 0.5);}else                       //right{*motorFrontSteer = 4500 + (int)(myabs(frontAngleSet) * 33.3 + 0.5);}
}

通过上面转换函数 Steer_Ctrl,我们可以将前轮转向角度转换为具体的PWM数值,剩下的部分就是PWM设置的问题了,大家这么聪明,肯定不用我多说了。

大家是不是觉得阿克曼小车的底层控制部分 So Easy.

3、极简版阿克曼结构运动学模型

3.1、模型示意图介绍:

阿克曼底盘的运动学模型是一个全驱动模型,简化模型示意图如下:

图片来源:CSDN:Jason.Li_0012

3.2、模型假设:

相对于理想的阿克曼底盘模型,这里为了简化模型,做了如下假设:

  • 不考虑车辆在Z轴方向的运动,只考虑XY水平面的运动。
  • 左右侧车轮转角一致,这样可将左右侧轮胎合并为一个轮胎,以便于搭建单车模型。
  • 车辆行驶速度变化缓慢,忽略前后轴载荷的转移。

3.3、模型已知条件:

  • 小车前后轴之间的距离:lll
  • 小车后轮之间的距离:$ 2d$
  • 小车前轮的转向角度:θ\thetaθ
  • 小车左侧后轮线速度:vLv_{L}vL​
  • 小车右侧后轮线速度:vRv_{R}vR​
  • 小车线速度:vvv
  • 小车角速度:www

3.4、阿克曼小车后轮正逆运动学模型:

之前讲差速小车运动学模型的文章中,已经明确:差分模型的机器人始终做的是以R为半径的圆弧运动,这里阿克曼也可以安装同样的方式计算。
v=w∗R(公式1)v=w*R (公式1) v=w∗R(公式1)

VL=w∗(R−d)=w∗R−wd=v−wd(公式2)V_{L} = w * (R-d)=w*R - wd = v -wd (公式2) VL​=w∗(R−d)=w∗R−wd=v−wd(公式2)

VR=w∗(R+d)=w∗R+wd=v+wd(公式3)V_{R} = w * (R+d)=w*R + wd = v +wd (公式3) VR​=w∗(R+d)=w∗R+wd=v+wd(公式3)

由(公式1)(公式1)(公式1)、(公式2)(公式2)(公式2)、(公式3)(公式3)(公式3)推导得到如下结果:
v=(VL+VR)/2(公式4)v = (V_{L} + V_{R} )/ 2 (公式4) v=(VL​+VR​)/2(公式4)

w=(VR−VL)/2d(公式5)w = (V_{R} - V_{L})/ 2d (公式5) w=(VR​−VL​)/2d(公式5)

3.5、阿克曼小车前轮转向角度计算:

这里使用两前轮中间的角度θ\thetaθ 来近似控制角,所以得到如下公式:
l/R=tanθ(公式6)l/R = tan\theta (公式6) l/R=tanθ(公式6)

R=v/w(公式7)R=v/w(公式7) R=v/w(公式7)

由(公式6)(公式6)(公式6)、(公式7)(公式7)(公式7) 推导得到如下公式:
θ=arctan(l∗w/v)(公式8)\theta = arctan(l*w/v)(公式8) θ=arctan(l∗w/v)(公式8)

3.6、ROS层阿克曼模型计算代码分享:

#define PI           (3.1415926)
#define ROBOT_RADIUS (0.0675)   //m
#define ROBOT_TRACK  (0.135)    //m
#define ROBOT_LENGTH (0.15)     //m
double RobotV_  = 0;
double YawRate_ = 0;// 速度控制消息的回调函数
void cmdCallback(const geometry_msgs::Twist& msg)
{RobotV_  = msg.linear.x;  //m/sYawRate_ = msg.angular.z; //rad/s
}void Mbot::ackerCar(const double RobotV,const double YawRate)
{double r = RobotV / YawRate; // mif(RobotV == 0)       // ackermann car can't trun rotation{sendLeftSpeed_  = 0;sendRightSpeed_ = 0;sendFrontAngle_ = 0;}else if(YawRate == 0) // Pure forward/backward motion{sendLeftSpeed_  = (short)(RobotV * 1000.0);//mm/ssendRightSpeed_ = (short)(RobotV * 1000.0);sendFrontAngle_ = 0;}else            // Rotation about a point in space{sendLeftSpeed_  = (short)(YawRate * 1000.0 * (r - ROBOT_RADIUS));//mm/ssendRightSpeed_ = (short)(YawRate * 1000.0 * (r + ROBOT_RADIUS));// 阿克曼约束一:后左右车轮转动需同向if(RobotV > 0){if(sendLeftSpeed_ < 0) {sendLeftSpeed_ = 0;}if(sendRightSpeed_ < 0) {sendRightSpeed_ = 0;}}else if(RobotV < 0){if(sendLeftSpeed_ > 0) {sendLeftSpeed_ = 0;}if(sendRightSpeed_ > 0) {sendRightSpeed_ = 0;}            }sendFrontAngle_ = atan(ROBOT_LENGTH * YawRate / RobotV ) * (180.0 / PI); // Deg}
}

4、总结

如果你已经仔细的看到这里,那么恭喜你,你心中一定有了搭建阿克曼小车的控制思路了。

如果还没有理解,一定多看两遍。

偷偷的告诉大家,近期,我准备开源一整套,完整的ROS小车方案,包含差速小车和阿克曼小车,届时将给大家提供完整上位机和下位机的代码,整套方案成本极低,千元以内。

下面是底层硬件方案,提前透露给大家。

此处省略一点点细节…


全套方案开源:开源! ROS2阿克曼开发平台方案

5、参考:

[1] https://zhuanlan.zhihu.com/p/499251426

[2] https://blog.csdn.net/weixin_45929038/article/details/122632369?spm=1001.2014.3001.5502

[3] https://blog.csdn.net/weixin_47012067/article/details/121090584

超简单!!!搭建阿克曼ROS小车相关推荐

  1. 正式压力测试:locust进阶,超简单搭建生产级locust集群

    locust进阶,搭建生产级locust集群 本教程基于k8s集群搭建,使用helm作为包管理工具 通过helm安装locust

  2. 开源!手把手教你搭建Arduino+英伟达Jetson的ROS小车(上)

    1 引言 今年6月,我们应小伙伴儿的需求,写了两篇如何通过购买零件从零搭建一台ROS实体车的推文<开源!手把手教你搭建Arduino+树莓派的ROS小车(上)>.<开源!手把手教你搭 ...

  3. 基础ROS小车软件结构到底是什么样子的?

    ROS小车的软件结构 0.前言 想必大多数读者,在刚开始搭建ROS小车的时候,都会遇到下面这样的问题.单片机底层PWM.测速.速度PID.MPU6050数据获取等等,而且还要与ROS层通信,ROS层还 ...

  4. 【大一立项】如何亲手搭建ROS小车:硬件和软件介绍

    本次博客将详细介绍上篇博客中提到的ROS小车的硬件和软件部分. 由于十一实验室不开门,所以部分代码还没有上传到Github. 下位机 下位机使用Arduino(因为大一上刚学完用Arduino做循迹小 ...

  5. 超简单的内网邮件服务器搭建(CentOS7 postfix+dovecot)

    为什么说是超简单呢,因为在这之前肯定查看教程看大佬们是怎样搭建的,于是我开始各种查阅,大佬们一般上来先讲原理,解释各种名词(我至今还没记清),然后准备前菜域名解析,我弄了好几天的域名解析但最终还是以失 ...

  6. 用python建云盘_实用的Python(3)超简单!基于Python搭建个人“云盘”

    1 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码,而笔者最近发现的一个基于Python的工具updog,可以帮助我们在服务器上搭建类似 ...

  7. 搭建React项目,超简单教程

    步骤 前言 一.安装create-react-app 二.使用步骤 1.创建项目 2.运行项目 3.文件目录 总结 前言 最近公司闲的无聊,刚好之前学的React,至今还未搭建过一个React项目,借 ...

  8. python云盘搭建教程_超简单!基于Python搭建个人“云盘”,目前最好用的个人云盘...

    超简单!基于Python搭建个人"云盘",目前最好用的个人云盘 1. 简介 当我们想要从本地向云服务器上传文件时,比较常用的有pscp等工具,但避免不了每次上传都要写若干重复的代码 ...

  9. 【超简单】之基于PaddleSpeech搭建个人语音听写服务

    一.[超简单]之基于PaddleSpeech搭建个人语音听写服务 1.需求分析 亲们,你们要写会议纪要嘛? 亲们,你们要写会议纪要嘛? 亲们,你们要写会议纪要嘛? 当您面对成吨的会议录音,着急写会议纪 ...

最新文章

  1. 翻译:CREATE DATABASE语句
  2. 8天玩转并行开发——第四天 同步机制(上)
  3. AI:《Why is DevOps for Machine Learning so Different?—为什么机器学习的 DevOps 如此不同?》翻译与解读
  4. sql 获取本周周一和周日
  5. 设计模式--装饰者(Decorator)模式
  6. 函数-模块化程序设计
  7. Direct2D (35) : 通过 DirectWrite 获取字体列表
  8. BugkuCTF-MISC题闪的好快
  9. 判断三角形是否是直角三角形
  10. OpenCV-python学习笔记(一)——image basics输入输出,像素处理和绘制图形
  11. 草图大师SketchUp2016下载和安装教程
  12. Python修改图片分辨率来改变图片大小
  13. 小程序跳转至企业微信客服wx.openCustomerServiceChat
  14. 从深圳地铁看-------以损害乘客利益为目标的营运方式
  15. mui 图片预览(3)
  16. 荣耀笔记本pro linux版本,荣耀MagicBook Pro锐龙版发布:首发锐龙7 3750H、还有Linux版...
  17. C语言链表实现商品库存管理系统
  18. 5.7 将图层样式转换为普通图层 [原创Ps教程]
  19. Visual Studio Code插件-前端工程师开发必备
  20. 数据库身份证号加密密码加密_使用基于密码的加密保护会议室数据库

热门文章

  1. matlab 自动控制函数,matlab自动控制仿真常见函数应用.doc
  2. 2021年制冷与空调设备运行操作免费试题及制冷与空调设备运行操作考试试卷
  3. 微信再次改版!这个功能终于要下线
  4. c语言中要求对象只能为整数的运算符是,以下正确的叙述是( ) 答案:在C程序中, %是只能用于整数运算 的运算符...
  5. 日本儒学的特色与日本文化
  6. android 9 预装可卸载的app,只安装一次
  7. 图像处理 手写体英文字母的目标检测与识别 实验报告
  8. armadillo matlab,Armadillo之计算矩阵的行列式(determinant)
  9. LeeCode 1626 DP
  10. 怎样在线将视频生成二维码?二维码在线制作工具使用教程