阿克曼小车仿真运动控制设计方案

发布时间:2024-06-24  

一、主要内容

结合阿克曼运动需求,本团队设计了阿克曼运动系统框图如图


主要包括阿克曼小车仿真设计和阿克曼小车实物实现。

bb7a90d8-8703-11ed-bfe3-dac502259ad0.png

图 1 阿克曼运动系统框图

1.1 阿克曼小车仿真设计

本节先介绍阿克曼小车模型,小车仿真设计包括SolidWorks和gazebo三维建模。

1.1.1 阿克曼小车

阿克曼小车是一款经典的车模,小车模型后轮是通过电机直驱,前轮通过舵机控制前轮转向角,前轮部分则是在模型中添加一个竖直的关节,使前轮能围绕此关节转动

1.1.2 SolidWorks三维模型

采用SolidWorks (2016版)设计软件搭建阿克曼小车三维模型如图 2图 3图 4,主体分为底板、电池、控制器、带编码电机的后轮、激光雷达、深度摄像头、阿克曼前轮转向7个部分如图 5。

各部分零件都定义了材料属性,选择取小车底盘中心为模型的原点,配置了小车JRDF文件见附件3。

目前可以导入到gazebo环境中,可以实现小车的前进与后退,但转向无法实现,原因分析由于阿克曼转向结构属于空间四连杆结构 (并联结构不支持)如图 6。

bb99ce58-8703-11ed-bfe3-dac502259ad0.png

图2正等测

bbb54bba-8703-11ed-bfe3-dac502259ad0.png

图3前视图

bbdc7a82-8703-11ed-bfe3-dac502259ad0.png

图4俯视图

bbeb29ba-8703-11ed-bfe3-dac502259ad0.png

图5爆炸视图

bbfb3fa8-8703-11ed-bfe3-dac502259ad0.png

图6模型导入gazebo效果

1.1.3 gazebo三维建模

为了简化小车的运动,直接调入用阿克曼模型,简化小车的前后轮运动关系,搭配了里程计和摄像头,可以实现小车的转向、直行和后退。

小车分别导入到gazebo和rviz效果分别如图 7图 8建模过程见附件1文档

bc0cc7d2-8703-11ed-bfe3-dac502259ad0.png

图 7 加载到gazebo

bc302ee8-8703-11ed-bfe3-dac502259ad0.png

图8 加载到rvzi

1.2 阿克曼小车实物实现

小车底层搭载STM32F103系列单片机,运动控制算法采用阿克曼算法,解析后分别驱动舵机和编码电机,可以通过审口通讯实现上下位机的人机交互,方便调试我们设计了PS2手柄控制模式。

实现小车的实物制作如图 9。

bc471040-8703-11ed-bfe3-dac502259ad0.png

图9小车实物

1.2.1控制器

小车控制器采用意法半导体STM32F103C6,是一款 ARM 32位 Cortex-M3 微控制器,2MHz 32B 闪存,10KB SRAM,PLL,嵌入式内部 RC 8MHz和 32KHz,实时时钟,嵌套中断控制器,省电式。

JTAG和SWD,2同步,具有输入捕捉、输出比和PWM的16位定时器、16位6通道高级定时器、2个16位看门狗定时器、SysTick定时器、SP112C、2个USART、USB2.0全速接口、CAN2.0B激活、2个12位10通道D转换器

快速 /0 端口如图 10整体资源满足小车求,10使用情况详细说明,STM32核心板和底板原理图见附件1。

bc520fe0-8703-11ed-bfe3-dac502259ad0.png

图 10 STM32F103引脚定义图

1.2.2 阿克曼运动算法

阿克曼转向是一种现代汽车的转向方式,在汽车转弯的时候,内外轮转过的角度不一样,内侧轮胎转弯半径小于外侧轮胎。理想的阿克曼转向如图 11,而本车模型采用反向的阿克曼模型。

bc60902e-8703-11ed-bfe3-dac502259ad0.png

图 11 理想的阿克曼转向

根据阿克曼转向几何设计转向机构,在车辆沿着弯道转弯时,利用四连杆的相等曲柄,可以使内侧轮的转向角比外侧轮大大约 2~4度,使四个轮子路径的圆心大致上交会于后轴的延长线上瞬时转向中心,从而让车辆可以顺畅的转弯。

阿克曼核心公式如下;

bc6f300c-8703-11ed-bfe3-dac502259ad0.png

式中:B一汽车前外轮转角,a 一汽车前内轮转角,K一两主销中心距,L一轴距如图 12。

具体实现见附件2中control.c中Kinematic Analysis函数。

bc7e89d0-8703-11ed-bfe3-dac502259ad0.png

图 12 阿克曼数学模型


control.c


#include "control.h"  



//#define T 0.245f

//#define L 0.29f

//#define K 14.00f

#define T 0.156f

#define L 0.1445f

#define K 622.8f

u8 Flag_Target,Flag_Change;  //相关标志位

//float Voltage_Temp,Voltage_Count,Voltage_All;  //电压采样相关变量

int j,sum;

/**************************************************************************

函数功能:小车运动数学模型

入口参数:速度和转角

返回  值:无

**************************************************************************/

void Kinematic_Analysis(float velocity,float angle)

{

    Target_A=velocity*(1+T*tan(angle)/2/L); 

    Target_B=velocity*(1-T*tan(angle)/2/L);      //后轮差速

    Servo=SERVO_INIT+angle*K;                    //舵机转向   

}

/**************************************************************************

函数功能:所有的控制代码都在这里面

         定时中断触发

         严格保证采样和数据处理的时间同步         

**************************************************************************/

void Control(void)

{

  oled_show();               //显示屏打开

  Encoder_Left=Read_Encoder(2);                                      

  Encoder_Right=-Read_Encoder(3);      //读取左右编码器   

  delay_ms(50);                  //=====延时等待稳定  

  if(Turn_Off(Voltage)==0&&Flag_Way==0)

   {   

      jiexi();

      Kinematic_Analysis(Velocity,Angle);                                   //小车运动学分析

      Motor_A=Target_A*20;                                                     //===计算电机A最终PWM

      Motor_B=Target_B*20;                                                    //===计算电机B最终PWM 

      Xianfu_Pwm();                                                      //===PWM限幅

      Set_Pwm(Motor_A,Motor_B,Servo);                                    //===赋值给PWM寄存器  

    

   }       

  else if(Turn_Off(Voltage)==0&&Flag_Way==1)                                  //===如果不存在异常

    {

      Get_RC();

      Kinematic_Analysis(Velocity,Angle);                                   //小车运动学分析 

      Motor_A=Incremental_PI_Left(Encoder_Left,Target_A);                   //===速度闭环控制计算电机A最终PWM

      Motor_B=Incremental_PI_Right(Encoder_Right,Target_B);                  //===速度闭环控制计算电机B最终PWM 

      Xianfu_Pwm();                                                      //===PWM限幅

      Set_Pwm(Motor_A,Motor_B,Servo);                                    //===赋值给PWM寄存器  

    }

  else Set_Pwm(0,0,SERVO_INIT);  //===赋值给PWM寄存器    

  Voltage_Temp=Get_battery_volt();                                     //=====读取电池电压    

  Voltage_Count++;                                                     //=====平均值计数器

  Voltage_All+=Voltage_Temp;                                           //=====多次采样累积

  if(Voltage_Count==10) Voltage=Voltage_All/10,Voltage_All=0,Voltage_Count=0;//=====求平均值                                       

  if(Flag_Show==0)        Led_Flash(100);

  else if(Flag_Show==1)  Led_Flash(0);  //led闪烁

  Key();    //===扫描按键状态 单击双击可以改变小车运行状态



}


/**************************************************************************

函数功能:赋值给PWM寄存器

入口参数:PWM

返回  值:无

**************************************************************************/

void Set_Pwm(int motor_a,int motor_b,int servo)

{

      if(motor_a<0)      PWMA2=7200,PWMA1=7200+motor_a;

      else               PWMA1=7200,PWMA2=7200-motor_a;

    

      if(motor_b<0)      PWMB1=7200,PWMB2=7200+motor_b;

      else               PWMB2=7200,PWMB1=7200-motor_b;

     SERVO=servo;  

}

/**************************************************************************

函数功能:限制PWM赋值 

入口参数:幅值

返回  值:无

**************************************************************************/

void Xianfu_Pwm(void)

{  

    int Amplitude=6900;    //===PWM满幅是7200 限制在6900

    if(Motor_A<-Amplitude) Motor_A=-Amplitude;  

    if(Motor_A>Amplitude)  Motor_A=Amplitude;  

    if(Motor_B<-Amplitude) Motor_B=-Amplitude;  

    if(Motor_B>Amplitude)  Motor_B=Amplitude;    

    if(Servo<(SERVO_INIT-500))     Servo=SERVO_INIT-500;    //舵机限幅

    if(Servo>(SERVO_INIT+500))     Servo=SERVO_INIT+500;      //舵机限幅

}

/************************************************************************

函数功能:按键修改小车运行状态 

入口参数:无

返回  值:无

**************************************************************************/

void Key(void)

{  

  u8 tmp,tmp2;

  tmp=click(); 

//  tmp=click_N_Double(50); //双击,双击等待时间500ms

  if(tmp==1)Flag_Stop=!Flag_Stop;//单击控制小车的启停

  //if(tmp==2)Flag_Show=!Flag_Show;//双击控制小车的显示状态

  tmp2=Long_Press();  //长按        

  if(tmp2==1)Flag_Show=!Flag_Show;//控制小车的显示状态                 

}

/**************************************************************************

函数功能:异常关闭电机

入口参数:电压

返回  值:1:异常  0:正常

**************************************************************************/

u8 Turn_Off( int voltage)

{

      u8 temp;

      if(voltage<740||Flag_Stop==1)//电池电压低于11.1V关闭电机

      {                                                  

      temp=1;  

      PWMA1=0; //电机控制位清零                                           

      PWMB1=0; //电机控制位清零

      PWMA2=0; //电机控制位清零

      PWMB2=0; //电机控制位清零            

      }

      else

      temp=0;

      return temp;    

}



/**************************************************************************

函数功能:绝对值函数

入口参数:int

返回  值:unsigned int

**************************************************************************/

int myabs(int a)

{        

    int temp;

    if(a<0)  temp=-a;  

    else temp=a;

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>