项目使用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(); //保存串口发送来的数据