STM32下位机与带ROS系统的上位机通信的学习

项目使用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(); //保存串口发送来的数据
posted @ 2018-08-26 16:13  GaoLab  阅读(6148)  评论(0编辑  收藏  举报