ROS机器人DIY教程,编码器数据读取

it2023-10-04  97

简介:         编码器是作为电机反馈的一个重要传感器,可以用于判断电机的转速和运动方向,在ROS机器人中可以为机器人提供一个位置参考。编码器又有增量式编码器、绝对式编码器、混合绝对式编码器等,具体的大家可以百度了解。

本文主要讲解常用的AB相编码器,一般是霍尔或者光电增量式编码器,实现的工具:

starrobot底层开发板、12V 5200ma锂电池、GB37-520减速电机、USB数据线、Keil5

starrobot底层开发板板载了A4950电机驱动器,预留和电机相同线序的XH2.54-6P接口,即插即用。电机转动主要使用到电机线+、电机线-两根线,编码器GND、编码器B相、编码器A相、编码器5V主要用于测速。         STM32的定时器1、2、3、4、5、8是具有编码器模式的,我们只需要按照手册进行配置即可,具体的大家可查阅STM32F4XX中文手册进行了解:

具体代码配置如下:encoder.cpp

void Encoder::init(void) {      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;       TIM_ICInitTypeDef TIM_ICInitStructure;       GPIO_InitTypeDef GPIO_InitStructure;     RCC_APB1PeriphClockCmd(ENCODER_TIM_CLK[this->encoder_], ENABLE);       RCC_AHB1PeriphClockCmd(ENCODER_A_PORT_CLK[this->encoder_]|ENCODER_B_PORT_CLK[this->encoder_], ENABLE);     GPIO_InitStructure.GPIO_Pin = ENCODER_A_PIN[this->encoder_];     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;     GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;     GPIO_Init(ENCODER_A_PORT[this->encoder_], &GPIO_InitStructure);       GPIO_InitStructure.GPIO_Pin = ENCODER_B_PIN[this->encoder_];      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;     GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;     GPIO_Init(ENCODER_B_PORT[this->encoder_], &GPIO_InitStructure);       GPIO_PinAFConfig(ENCODER_A_PORT[this->encoder_],ENCODER_A_GPIO_PinSource[this->encoder_],ENCODER_GPIO_AF_TIM[this->encoder_]);       GPIO_PinAFConfig(ENCODER_B_PORT[this->encoder_],ENCODER_B_GPIO_PinSource[this->encoder_],ENCODER_GPIO_AF_TIM[this->encoder_]);        TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);     TIM_TimeBaseStructure.TIM_Prescaler = 0x0;                 // No prescaling //不分频     TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD;  //设定计数器自动重装值     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //选择时钟分频:不分频     TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数         TIM_TimeBaseInit(ENCODER_TIM[this->encoder_], &TIM_TimeBaseStructure);  //初始化定时器     TIM_EncoderInterfaceConfig(ENCODER_TIM[this->encoder_], TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3 //    TIM_EncoderInterfaceConfig(ENCODER_TIM[this->encoder_], TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);//使用编码器模式3     TIM_ICStructInit(&TIM_ICInitStructure);     TIM_ICInitStructure.TIM_ICFilter = 0;     TIM_ICInit(ENCODER_TIM[this->encoder_], &TIM_ICInitStructure);     TIM_ClearFlag(ENCODER_TIM[this->encoder_], TIM_FLAG_Update);//清除TIM的更新标志位     TIM_ITConfig(ENCODER_TIM[this->encoder_], TIM_IT_Update, ENABLE);     TIM_Cmd(ENCODER_TIM[this->encoder_], ENABLE); }

    配置好编码器驱动后,我们再编写一个定时器的驱动,100ms读取一次编码器的值并把编码器的值转换为rpm值,定时器代码如下:

void BaseBoard_TIM6_Init(u16 arr,u16 psc) {     TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;     NVIC_InitTypeDef NVIC_InitStructure;     //84MHz     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);            TIM_TimeBaseInitStructure.TIM_Period = arr;          TIM_TimeBaseInitStructure.TIM_Prescaler=psc;       TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;      TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;           TIM_TimeBaseInit(TIM6,&TIM_TimeBaseInitStructure);          TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);      TIM_Cmd(TIM6,ENABLE);           NVIC_InitStructure.NVIC_IRQChannel=TIM6_DAC_IRQn;      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01;     NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03;      NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;     NVIC_Init(&NVIC_InitStructure); } void TIM6_DAC_IRQHandler(void) {        int delta_ticks_1;     int delta_ticks_2;     int delta_ticks_3;     int delta_ticks_4;     if(TIM_GetITStatus(TIM6,TIM_IT_Update)==SET)      {         编码器采样周期 100ms             delta_ticks_1= (short)((TIM5 -> CNT) - 0x7fff);         delta_ticks_2= (short)((TIM2 -> CNT) - 0x7fff);         delta_ticks_3= (short)((TIM3 -> CNT) - 0x7fff);         delta_ticks_4= (short)((TIM4 -> CNT) - 0x7fff);                 Motor_Rpm.Current_Rpm1 = ((float)(delta_ticks_1 / Time_counts_per_rev)*600.f);         Motor_Rpm.Current_Rpm2 = ((float)(delta_ticks_2 / Time_counts_per_rev)*600.f);         Motor_Rpm.Current_Rpm3 = ((float)(delta_ticks_3 / Time_counts_per_rev)*600.f);         Motor_Rpm.Current_Rpm4 = ((float)(delta_ticks_4 / Time_counts_per_rev)*600.f);         Motor_Rpm.MotorEncoder1 += ((float)(delta_ticks_1 / Time_counts_per_rev));         Motor_Rpm.MotorEncoder2 += ((float)(delta_ticks_2 / Time_counts_per_rev));         Motor_Rpm.MotorEncoder3 += ((float)(delta_ticks_3 / Time_counts_per_rev));         Motor_Rpm.MotorEncoder4 += ((float)(delta_ticks_4 / Time_counts_per_rev));         TIM2->CNT = 0x7fff;         TIM3->CNT = 0x7fff;         TIM4->CNT = 0x7fff;         TIM5->CNT = 0x7fff;         }     TIM_ClearITPendingBit(TIM6,TIM_IT_Update);   }

Motor_Rpm 是一个全局变量的结构体

typedef struct _Moto_ {     float Current_Rpm1;     float Current_Rpm2;     float Current_Rpm3;     float Current_Rpm4;     float MotorEncoder1;     float MotorEncoder2;     float MotorEncoder3;     float MotorEncoder4; }_Moto_Str;

我们读取这个结构体里面的数据即可得到编码器的数据,为了把编码器的数据通过串口发送给ROS我们还需要定义一个消息类型和节点。

starrobot_msgs::Velocities raw_vel_msg; ros::Publisher raw_vel_pub("raw_vel", &raw_vel_msg); raw_vel_msg.encoder_motor1 = Motor_Rpm.MotorEncoder1*wheel_circumference_s*Direction_encoder1_value; raw_vel_msg.encoder_motor2 = Motor_Rpm.MotorEncoder2*wheel_circumference_s*Direction_encoder2_value; raw_vel_msg.encoder_motor3 = Motor_Rpm.MotorEncoder3*wheel_circumference_s*Direction_encoder3_value; raw_vel_msg.encoder_motor4 = Motor_Rpm.MotorEncoder4*wheel_circumference_s*Direction_encoder4_value; current_vel = kinematics.getVelocities(Motor1_Feedback_,Motor2_Feedback_,Motor3_Feedback_,Motor4_Feedback_); raw_vel_msg.linear_y = current_vel.linear_y; raw_vel_msg.linear_x = current_vel.linear_x; raw_vel_msg.angular_z = current_vel.angular_z; raw_vel_pub.publish(&raw_vel_msg);

然后就可以在上层收到编码器的数据。

3、总结

编码器数据获取主要使用到STM32 定时器的编码器模式,STM32的定时器在实际的应用中有很大作用,大家可以自己多扩展扩展定时器的其他功能,如果你也在自己动手制作ROS机器人小车的话就扫描一下二维码进群把:

最新回复(0)