项目使用TX2上位机与下位机STM32进行通信,故对此进行一些研究。之前也用过STM32通过串口与装有ROS的笔记进行通信,使用的是 “基于STM32的rosserial_client的节点开发”,见链接,文章中使用的是STM32F4系列的单片机,本人在F1系列中实现了,但是存在代码复杂和运行效率不高的问题。因此本次直接使用串口与TX2建立通信。
上位机(TX2)与下位机(STM32)通过串口进行通信
参考链接:https://www.ncnynl.com/archives/201703/1417.html
下位机
发送程序
for(i=0;i<21;i++)
{
USART_ClearFlag(USART1,USART_FLAG_TC); //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题
USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); //等待发送结束
}
接收程序
if(USART_RX_STA&0x8000) // 串口1接收函数
{
//接收左右轮速度
for(t=0;t<4;t++)
{
rightdata.data[t]=USART_RX_BUF[t];
leftdata.data[t]=USART_RX_BUF[t+4];
}
//储存左右轮速度
odometry_right=rightdata.d;//单位mm/s
odometry_left=leftdata.d;//单位mm/s
USART_RX_STA=0;//清楚接收标志位
}
串口接收中断程序
void USART1_IRQHandler(void)//串口中断函数
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否接受到数据
{
serial_rec =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(serial_rec==0x0a)
{
if((USART_RX_STA&0x3f)==8)
{
USART_RX_STA|=0x8000; //接收完成了
main_sta|=0x04;
main_sta&=0xF7;
}
else
{
main_sta|=0x08;
main_sta&=0xFB;
USART_RX_STA=0;//接收错误,重新开始
}
}
else
{
main_sta|=0x08;
USART_RX_STA=0;//接收错误,重新开始
}
}
else //还没收到0X0D
{
if(serial_rec==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=serial_rec ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))
{
main_sta|=0x08;
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
}
这之中我们需要规避一个问题,串口接收中断是以/r/n为中止条件,我们需要避免其中的数据中包含了/r(0x0d)的情况,而上述程序并没有规避这一点。
void USART1_IRQHandler(void)//串口中断函数
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //是否接受到数据
{
serial_rec =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(serial_rec==0x0a)
{
if((USART_RX_STA&0x3f)==8)
{
USART_RX_STA|=0x8000; //接收完成了
main_sta|=0x04;
main_sta&=0xF7;
}
else
{
main_sta|=0x08;
main_sta&=0xFB;
USART_RX_STA=0;//接收错误,重新开始
}
}
else
{
main_sta|=0x08;
USART_RX_STA=0;//接收错误,重新开始
}
}
else //还没收到0X0D
{
if(serial_rec==0x0d&&(USART_RX_STA&0x3f)==8)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=serial_rec ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))
{
main_sta|=0x08;
USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
}
上位机
发送代码
void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数
{
string port("/dev/ttyUSB0"); //小车串口号
unsigned long baud = 115200; //小车串口波特率
serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口
angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/s
linear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s
//将转换好的小车速度分量为左右轮速度
left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;
right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;
//存入数据到要发布的左右轮速度消息
left_speed_data.d*=ratio; //放大1000倍,mm/s
right_speed_data.d*=ratio;//放大1000倍,mm/s
for(int i=0;i<4;i++) //将左右轮速度存入数组中发送给串口
{
speed_data[i]=right_speed_data.data[i];
speed_data[i+4]=left_speed_data.data[i];
}
//在写入串口的左右轮速度数据后加入”/r/n“
speed_data[8]=data_terminal0;
speed_data[9]=data_terminal1;
//写入数据到串口
my_serial.write(speed_data,10);
}
接收程序
rec_buffer =my_serial.readline(25,"\n"); //获取串口发送来的数据
const char *receive_data=rec_buffer.data(); //保存串口发送来的数据