linux ros USB阻塞与非阻塞记录

一、USB口满足可同时读写,符号标识

O_RDWR     : 可读可写
O_NDELAY   :这个程序不关心DCD信号线所处的状态,端口的另一端是否激活或者停止。如果用户不指定了这个标志,则进程将会一直处在睡眠状态,直到DCD信号线被激活。
O_NOCTTY   :表示打开的是一个终端设备,程序不会成为该端口的控制终端。如果不使用此标志,任务一个输入(eg:键盘中止信号等)都将影响进程。
O_NONBLOCK :阻塞与非阻塞方式标识符
阻塞方式-read- 实现:
          在阻塞型驱动程序中,read 实现方式如下:
          如果进程调用 read ,但设备 没有数据 或 数据不足,进程阻塞.
          当新数据到达后,唤醒被阻塞进程.
阻塞方式-write- 实现:
          在阻塞型驱动程序中,write 实现方式如下:
          如果进程调用了 write ,但设备 没有足够的空间供其写入数据,进程阻塞.
          当设备中的数据被读走后,缓冲区中空出部分空间,则唤醒进程.
非阻塞方式的读写操作:
          阻塞方式是文件读写操作的 默认方式,但是应用程序员可通过使用O_NONBLOCK 标志来人为的设置读写操作为 非阻塞方式 .( 该标志定义在 < linux/fcntl.h > 中,在打开文件时指定 ) .
          如果 设置了 O_NONBLOCK 标志,read 和 write 的行为是不同的 ,如果进程没有数据就绪时调用了 read ,或者在缓冲区没有空间时调用了 write ,系统只是 简单的返回 -EAGAIN,而 不会阻塞进程.

有两种方法:

  1.打开时,通过打开参数控制.

        open(COM_DEV_NAME, O_RDWR | O_NONBLOCK);//非阻塞

        open(COM_DEV_NAME, O_RDWR);  //阻塞

  2.打开以后可以通过fcntl()函数进行修改.

        fcntl(socket_descriptor, F_SETFL, flags | O_NONBLOCK); //设为非阻塞

        fcntl(sock_descriptor, F_SETFL, 0); //设为阻塞

二、ROS serial::serial class 非阻塞方式

serial: serial::Serial Class Reference

 整体分为三个线程,读写和处理(另一个线程为pps时间同步线程,可忽略):

#include "serial_port.h"
extern "C"{
#include "ppstest.h"
}

using namespace std;
int main(int argc, char** argv) {
    ros::init(argc, argv, "serial_node");
    ros::NodeHandle node;
    ros::NodeHandle private_nh("~");
    std::string serial_Name;
    bool usb_log;
    ros::param::get("~usb_name",serial_Name);
    ros::param::get("~usb_log",usb_log);
    SerialPub Ser(node, private_nh,serial_Name,usb_log);
    std::thread t1(&Serial_Receive,&Ser);
    std::thread t2(&PPS_Receive,&Ser);
    std::thread t3(&Serial_Send,&Ser);
    t1.detach();
    t2.detach();
    t3.detach();
    Ser.Ser_pub();
}

读写线程实现方式:

#include "serial_port.h"
extern "C"{
#include "ppstest.h"
}

void SerialPub::initialize() {
    pps_bit=false;
    handshake_bit=false;
    revice_bit=false;
    timestamp=0;
    pre_timestamp=0;
    time_dt=0;
    speedv_cnt=0;
    anglev_cnt=0;
    Pre_right_enc=0;
    Pre_left_enc=0;
    odom_X=0;
    odom_Y=0;
    frame_buff[FRAME_LEN] = {0};
    try {
        //设置串口属性,并打开串口
        Date_Ser.setPort(ser_port);
        Date_Ser.setBaudrate(ser_baud);
        //serial::Timeout to = serial::Timeout::simpleTimeout(3);//USB口改为1
        serial::Timeout to = serial::Timeout::simpleTimeout(8);//串口改为50
        Date_Ser.setTimeout(to);
        Date_Ser.open();
        Date_Ser.flush();
    }
    catch (serial::IOException& e) {
        ROS_ERROR_STREAM("Serial port opening exception");
    }
    //检测串口是否已经打开,并给出提示信息
    if(Date_Ser.isOpen()) {
        ROS_INFO_STREAM("Serial port opened successfully");
    }
    else{
        ROS_INFO_STREAM("Unable to open serial port");
    }
}

SerialPub::SerialPub(ros::NodeHandle node, ros::NodeHandle private_nh,std::string serial_name,bool usb_log_) {
    //private_nh.param("ser_port", ser_port, std::string("/dev/serial_px30"));
    std::cout<<"**************************"<<serial_name<<std::endl;
    test_cs=usb_log_;
    my_time=new TIME[1];
    //private_nh.param("ser_port", ser_port, std::string("/dev/ttyACM0"));
    private_nh.param("ser_port", ser_port, serial_name);
    private_nh.param("ser_baud", ser_baud, 115200);
    ros::Rate loop_rate(200);    //设置发送数据的频率为100Hz
    initialize(); 
    CldPotAi_Sub = node.subscribe("/cloud_point_ai",5, &SerialPub::PCA_Callback,this);
    Location_Sub = node.subscribe("/Location_pose",5, &SerialPub::Loc_Callback,this);
    pub_gps_fix = node.advertise<sensor_msgs::NavSatFix>("GPS_fix", 5);
    pub_odom = node.advertise<nav_msgs::Odometry>("Ser_odom", 5);
    pub_imu = node.advertise<sensor_msgs::Imu>("Ser_imu", 5);
}

void Serial_Send(SerialPub *Ser_)
{ 
    std::vector<uint8_t> vec;
    std::cout<<"ai serial send"<<std::endl;
    uint8_t send_date_Head[] = {
    0xA4,0x59,0x43,//begin
    0x04,
    0x01,0x01,
    0x00,0x00,0x00,0x00,//length 6-9
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//time 10-17
    0x00,0x00,0x00,0x00,//state 18-21
    0x00,0x00,0x00,0x00,//error 22-25
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//date 26-37 location
     //34 obs-length uint16_t
    0x0D,0x0A};//38-39 end
    uint32_t send_length=0x01;
    uint32_t out_status=0;
    uint64_t out_time=0;
    uint32_t out_error=0;
    uint8_t aaaaaa=0x00;
    while(ros::ok()){
        vec.clear(); 
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        if(Ser_->handshake_bit)
        { 
            for(int i=0;i<40;i++){
                vec.push_back(send_date_Head[i]);
            }//head
            out_time=std::chrono::duration_cast<std::chrono::microseconds>
                                  (std::chrono::system_clock::now().time_since_epoch()).count();
            //https://blog.csdn.net/ktigerhero3/article/details/108017281;
            ///save number  
            if(Ser_->AiCloud_bit&&Ser_->Location_bit)
            {
               out_status=0x01;
               out_error=0x01;
               send_length=40+Ser_->vec_ai.size();
               for(int i_loc=0;i_loc<12;i_loc++)//gai i=0
               {
                   vec[26+i_loc]=Ser_->vec_loc[i_loc];
               }
               vec.insert(vec.begin()+37,Ser_->vec_ai.begin(),Ser_->vec_ai.end());
               Ser_->AiCloud_bit=false;
               Ser_->Location_bit=false;
            }
            else if(Ser_->Location_bit){ //Loc short package vec_loc
               out_status=0x02;
               out_error=0x02;
               send_length=40;
               for(int i_loc=0;i_loc<12;i_loc++)
               {
                   vec[26+i_loc]=Ser_->vec_loc[i_loc];
               }
               Ser_->Location_bit=false;
            }
            else if (Ser_->AiCloud_bit)
            {
                out_status=0x04;
                out_error=0x04;
                send_length=40;
                vec.insert(vec.begin()+37,Ser_->vec_ai.begin(),Ser_->vec_ai.end());
                Ser_->AiCloud_bit=false;
            }
            else
            {  // AI + Loc big package   vec_loc vec_ai
               out_status=0x08;
               out_error=0x08; 
               send_length=40;                      
            }
  
            vec[6]=(send_length>>24)&0xFF;
            vec[7]=(send_length>>16)&0xFF;
            vec[8]=(send_length>>8)&0xFF;
            vec[9]=send_length;

            vec[10]=out_time;
            vec[11]=(out_time>>8)&0xFF;
            vec[12]=(out_time>>16)&0xFF;
            vec[13]=(out_time>>24)&0xFF;
            vec[14]=(out_time>>32)&0xFF;
            vec[15]=(out_time>>40)&0xFF;
            vec[16]=(out_time>>48)&0xFF;
            vec[17]=(out_time>>54)&0xFF;

            vec[18]=out_status;
            vec[19]=out_status<<8;
            vec[20]=out_status<<16;
            vec[21]=out_status<<24;

            vec[22]=out_error;
            vec[23]=out_error<<8;
            vec[24]=out_error<<16;
            vec[25]=out_error<<24;            
            if(vec[26]==0x00)
              continue;
            if(Ser_->Date_Ser.write(vec)){
                Ser_->test_cs=false;
                if(Ser_->test_cs)
                {
                    //ROS_INFO_STREAM("serial send success");    
                    std::cout<<"length****************"<<vec.size()<<std::endl;
                    for(int i=0;i<45; i++)
                       printf("%02x ", vec[i]);
                   // printf("%02x ", vec[vec.size()-2]);
                   // printf("%02x ", vec[vec.size()-1]);
                    //printf("%02x ", vec[26]);                  
                   // printf("\n");
                }                          
            }
            else{
               ROS_INFO_STREAM("serial send fail");    
            }
            Ser_->Date_Ser.flushOutput();
        }
    }
}

void SerialPub::Loc_Callback(const std_msgs::UInt8MultiArray::ConstPtr &msg){
    vec_loc.clear();
    Location_bit=true;
    for(int i = 0; i < msg->data.size();i++){
        vec_loc.push_back(msg->data[i]);
    }     //for(int i = 0; i < vec.size();i++){printf("%02x ",vec[i]);}printf("\n");  
}

void SerialPub::PCA_Callback(const std_msgs::UInt8MultiArray::ConstPtr &msg){
    vec_ai.clear();
    AiCloud_bit=true;
    for(int i = 0; i < msg->data.size();i++){
        vec_ai.push_back(msg->data[i]);
    }     //for(int i = 0; i < vec.size();i++){printf("%02x ",vec[i]);}printf("\n");   
}

SerialPub::~SerialPub() {
    delete my_time;
    if(Date_Ser.isOpen())
      Date_Ser.close();
}

void SerialPub::listen_ser()
{
    if(test_cs){std::cout<<"run"<<std::endl;}
    if (Date_Ser.waitReadable()) {  //waitReadable会阻塞串口,直到有数据过来
        memset(frame_buff,0,FRAME_LEN);
        if(test_cs)
           ROS_INFO_STREAM("serial receive");
        n_size = Date_Ser.read(frame_buff, FRAME_LEN+80);
        if(test_cs)
        {
            std::cout<<"read_num="<<n_size<<std::endl;
            for(int i=0;i<n_size; i++)
                printf("%02x ", frame_buff[i]);
            printf("\n");
        }
        revice_bit=true;
   }
}

void Serial_Receive(SerialPub *Ser_)
{
    while(ros::ok()){
    Ser_->listen_ser();
    //std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void PPS_Receive(SerialPub *Ser_)
{
    std::cout<<"run1"<<std::endl;
    pps_handle_t handle[4];
    int avail_mode[4];
    int ret;
    std::string pps_str="/dev/pps0";
    char dev_pps[20];
    pps_str.copy(dev_pps, 8, 0);         
    *(dev_pps+9)='\0'; 
    strcpy((dev_pps), pps_str.c_str());
    
    std::cout<<"pps"<<dev_pps<<std::endl;
    ret = find_source(dev_pps, &handle[0], &avail_mode[0]);//check pps source is opened, set /dev/pps0
    if (ret < 0)
	exit(EXIT_FAILURE);
    printf("ok, found %d source(s), now start fetching data...\n",0);
    while(ros::ok()){  
       ret = fetch_source(0, &handle[0], &avail_mode[0]);//support check a lot pps source  block
       if (ret < 0 && errno != ETIMEDOUT)
          exit(EXIT_FAILURE);
       if(ret==0)
       {
          Ser_->pps_bit=true;
       }       
    }
    time_pps_destroy(handle[0]);  /**/  
}



void SerialPub::Ser_pub(){
    char *ret1;
    char *ret2;
    while (ros::ok()) 
    {
        if (revice_bit) {
            revice_bit=false;
            uint32_t yz_len=frame_buff[9]+(frame_buff[8]<<8)+(frame_buff[7]<<16)+(frame_buff[6]<<24);
            if((yz_len==1)&&(handshake_bit==false)){
                std::vector<uint8_t> vec_send;
                for(int i=0;i<sizeof(HandShake);i++){
                    vec_send.push_back(HandShake[i]);
                    printf("%02x ", HandShake[i]);
                }
                printf("test handshake\n");
                Date_Ser.write(vec_send); 
            }
            else if (n_size == yz_len+12) {//验证长度
                handshake_bit=true;
                std::vector<uint8_t> vec_data_rcv(frame_buff, frame_buff + FRAME_LEN);
                ret1 = strstr((char*)frame_buff,(char*)MSG_H);//验证头 遇到00会停止检测,只能验证头
                if(ret1!=NULL)
                {
                    //ret2 = strstr((char*)frame_buff, (char*)MSG_E);
                    if(frame_buff[yz_len+12-1]==0x0A&&frame_buff[yz_len+12-2]==0x0D)//验证尾
                    {		
                        //  qxwz_rtcm_sendGGAWithGGAString(sendbuf);
                        std::vector<uint8_t>::iterator match_TIME_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_TIME, MSG_H_TIME + 3);
                        if(match_TIME_H!=vec_data_rcv.end()){
                            time_del(match_TIME_H);
                        }
                        else{
                            ROS_INFO_STREAM("find time false");
                        }                     
                        std::vector<uint8_t>::iterator match_GPS_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_GPS, MSG_H_GPS + 3);
                        if(match_GPS_H!=vec_data_rcv.end()){
                            gps_del(match_GPS_H);
                        }
                        else{
                            ROS_INFO_STREAM("find rtk false");
                        }                  
                        std::vector<uint8_t>::iterator match_IMU_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_IMU, MSG_H_IMU + 3);
                        if(match_IMU_H!=vec_data_rcv.end()){
                            imu_del(match_IMU_H);
                        }
                        else{
                            ROS_INFO_STREAM("find imu false");
                        }
                        std::vector<uint8_t>::iterator match_ODOM_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_ODOM, MSG_H_ODOM + 3);
                        if((match_ODOM_H!=vec_data_rcv.end())){
                            odom_del(match_ODOM_H);
                        }
                        else{
                            ROS_INFO_STREAM("find odom false");
                        } 
                    }
                    else{
                        ROS_INFO_STREAM("end false");
                    } 
                }
                else{
                    ROS_INFO_STREAM("head false");
                }                   
                vec_data_rcv.clear();
            }
            else{
                ROS_INFO_STREAM("length false");
            }
        }
        else {
            //std::cout<<"????"<<std::endl;
            //Date_Ser.flush();
            //ROS_INFO_STREAM("no data");
        }            
        ros::spinOnce(); 
    }
    if(Date_Ser.isOpen())
      Date_Ser.close();    
}

bool SerialPub::time_del(std::vector<uint8_t>::iterator match_TIME_){
    const TIME_frame_t * Time_frame_p=(const TIME_frame_t *) &*(match_TIME_+3); 
    if(test_cs)  
      printf("%d/%d/%d\n", Time_frame_p->ucYear,Time_frame_p->ucMonth,Time_frame_p->ucDay);
    timestamp= Time_frame_p->MsOneDay;
    time_dt=pre_timestamp-timestamp;
    pre_timestamp=timestamp;
    if(pps_bit){
        my_time->year=Time_frame_p->ucYear;
        my_time->month=Time_frame_p->ucMonth;
        my_time->day=Time_frame_p->ucDay;
        if(my_time->year<2000){
            my_time->year=2021;
            my_time->month=0x0c;
            my_time->day=0x08;
        }
        my_time->hour=Time_frame_p->MsOneDay/1000/60/60;
        my_time->minute=Time_frame_p->MsOneDay/1000/60;
        my_time->second=(Time_frame_p->MsOneDay+500)/1000;                                                                                                                           
        if(!systime.setSystemTime(my_time))
          std::cout<<"settime false"<<std::endl;
        pps_bit=false;
    }
}

bool SerialPub::gps_del(std::vector<uint8_t>::iterator match_GPS_){
    const GPS_frame_t * GPS_frame_p=(const GPS_frame_t *) &*(match_GPS_+3);
    const GPS_frame_t1 * GPS_frame_p1=(const GPS_frame_t1 *) &*(match_GPS_+24);
    float latstd = GPS_frame_p1->lat_std;
    float lonstd = GPS_frame_p1->lon_std;
    int   levela = (int)GPS_frame_p->level;
    //std::cout<<"level="<<levela<<std::endl;
    //std::cout<<"latstd="<<latstd<<std::endl;
    //std::cout<<"lon="<<lonstd<<std::endl;
    float latvar = latstd*latstd;
    float lonvar = lonstd*lonstd;
    
    fix.header.stamp.fromNSec(timestamp);
    fix.status.status=levela;
    fix.altitude=GPS_frame_p->hgt;
    fix.latitude=GPS_frame_p->lat;
    fix.longitude=GPS_frame_p->lon;
    fix.position_covariance={ lonvar, 0, 0,
                                0, latvar, 0,
                                0, 0, 0};
    fix.header.frame_id = "GPS_fix";
    pub_gps_fix.publish(fix);
    return true;
}

bool SerialPub::imu_del(std::vector<uint8_t>::iterator match_IMU_){
    const IMU_frame_t * IMU_frame_p=(const IMU_frame_t *) &*(match_IMU_+3);                       
    imu_data.header.stamp.fromNSec(timestamp);
    imu_data.header.frame_id = "imu_link";
    imu_data.angular_velocity.x = IMU_frame_p->gyro_x;
    imu_data.angular_velocity.y = IMU_frame_p->gyro_y;
    imu_data.angular_velocity.z = IMU_frame_p->gyro_z;

    imu_data.linear_acceleration.x = IMU_frame_p->acc_x;
    imu_data.linear_acceleration.y = IMU_frame_p->acc_y;
    imu_data.linear_acceleration.z = IMU_frame_p->acc_z;
    
    pub_imu.publish(imu_data); 
}

bool SerialPub::odom_del(std::vector<uint8_t>::iterator match_ODOM_){
    const ODOM_frame_t * ODOM_frame_p=(const ODOM_frame_t *) &*(match_ODOM_+3);
    uint32_t right_enc=ODOM_frame_p->right_encode;
    uint32_t left_enc=ODOM_frame_p->left_encode;
    //printf("right_enc=%d", right_enc);
    //printf("left_enc=%d", left_enc);
    //printf("\n");
    int32_t R_encodeCdif=right_enc-Pre_right_enc;
    int32_t L_encodeCdif=left_enc-Pre_left_enc;
    //当编码器启动时,发生跳变时,值为0;3000rpm,线数10000 0.1s=50000线
    if(R_encodeCdif>50000&&R_encodeCdif<-50000&&L_encodeCdif>50000&&L_encodeCdif<-50000)
    {
        R_encodeCdif=0;
        L_encodeCdif=0;
    }
    float distance_sum = 0.5f*(R_encodeCdif+L_encodeCdif);//短时间内,前进距离两侧速度和
    float distance_diff = R_encodeCdif-L_encodeCdif;//短时间内,转弯角度为两侧速度差
        
    float Yaw_Angle_Diff = distance_diff * const_angle;// 采样期间走的角度
    float Yaw_Angle=Yaw_Angle+Yaw_Angle_Diff;//计算里程计方向角
    float Yaw_Angle_1 = Yaw_Angle + 0.5f * Yaw_Angle_Diff;//里程计方向角数据位数变化,用于三角函数计算


    odom_X=odom_X+distance_sum*cos(Yaw_Angle_1)*const_frame;   //距离*Yaw(偏角) 解析X坐标
    odom_Y=odom_Y+distance_sum*sin(Yaw_Angle_1)*const_frame;
    // 当前瞬时线速度  w=th/t
    float SpeedV_Ang=0,SpeedV_V=0;
    if(time_dt!=0)
    {
        SpeedV_Ang=Yaw_Angle_Diff/time_dt;    //角速度				
        SpeedV_V=(distance_sum*const_frame)/time_dt;   //速度=位移/时间; 时间=定时间*Timer 
    }       
    if(speedv_cnt<3)
    {				
        speedvsave[speedv_cnt]=SpeedV_V;
        speedv_cnt++;
    }else
    {
        speedv_cnt=0;
        speedvsave[speedv_cnt]=SpeedV_V;
        speedv_cnt++;
    }		
    float Speedv_send=0;
    for(int speedvplus=0;speedvplus<3;speedvplus++)
    {		
        Speedv_send=Speedv_send+speedvsave[speedvplus];
    }
    Speedv_send=Speedv_send/3;

    if(anglev_cnt<3)
    {				
        anglevsave[anglev_cnt]=SpeedV_Ang;
        anglev_cnt++;
    }else
    {
        anglev_cnt=0;
        anglevsave[anglev_cnt]=SpeedV_Ang;
        anglev_cnt++;
    }		
    float Anglev_send=0;
    for(int anglevplus=0;anglevplus<3;anglevplus++)
    {		
        Anglev_send=Anglev_send+anglevsave[anglevplus];
    }
    Anglev_send=Anglev_send/3;

    if(Yaw_Angle > pi)
    {
        Yaw_Angle -= pi_2_1;//减2pi
    }
    else
    {
        if(Yaw_Angle < -pi)
        {
            Yaw_Angle+=pi_2_1;//加2pi
        }
    }					 
    Pre_right_enc=right_enc;
    Pre_left_enc=left_enc;

    ser_odom.header.stamp.fromNSec(timestamp);
    ser_odom.header.frame_id = "odom";
            
    //set the position
    ser_odom.pose.pose.position.x = odom_X;
    ser_odom.pose.pose.position.y = odom_Y;
    ser_odom.pose.pose.position.z = 0.0;
    geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(Yaw_Angle);//将偏航角转换成四元数

    ser_odom.pose.pose.orientation = odom_quat;

    //set the velocity
    ser_odom.child_frame_id = "base_link";
    ser_odom.twist.twist.linear.x = Speedv_send*cos(Yaw_Angle);//线速度
    ser_odom.twist.twist.linear.y = Speedv_send*sin(Yaw_Angle);//线速度
    ser_odom.twist.twist.angular.z = Anglev_send;//角速度
    //载入covariance矩阵  https://blog.csdn.net/ethan_guo/article/details/79635575
    if ((Speedv_send==0)&&(Anglev_send==0))//机器人静止和动起来
    {
        ser_odom.pose.covariance = ODOM_POSE_COVARIANCE2;
        ser_odom.twist.covariance = ODOM_TWIST_COVARIANCE2;
    }
    else
    {
        ser_odom.pose.covariance = ODOM_POSE_COVARIANCE;
        ser_odom.twist.covariance = ODOM_TWIST_COVARIANCE;
    }
    //publish the message
    pub_odom.publish(ser_odom);  
}

三、阻塞方式实现

串口驱动程序

#include "serial_drive.h"


int open_serial_port(const char * device, uint32_t baud_rate)
{
  int fd = open(device, O_RDWR | O_NOCTTY);
  printf("**********************%d\n",fd);
  if (fd == -1)
  {
    perror(device);
    return -1;
  }
 
  // Flush away any bytes previously read or written.
  int result = tcflush(fd, TCIOFLUSH);
  if (result)
  {
    perror("tcflush failed");  // just a warning, not a fatal error
  }
 
  // Get the current configuration of the serial port.
  struct termios options;
  result = tcgetattr(fd, &options);
  if (result)
  {
    perror("tcgetattr failed");
    close(fd);
    return -1;
  }
 
  // Turn off any options that might interfere with our ability to send and
  // receive raw binary bytes.
  options.c_iflag &= ~(INLCR | IGNCR | ICRNL | IXON | IXOFF);
  options.c_oflag &= ~(ONLCR | OCRNL);
  options.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);

  // Set up timeouts: Calls to read() will return as soon as there is
  // at least one byte available or when 100 ms has passed.
  options.c_cc[VTIME] = 0;  //VTIME与VMIN配合使用,是指限定的传输或等待的最长时间 单位:0.1S
  options.c_cc[VMIN] = 1;//设置非规范模式下的超时时长和最小字符数:阻塞模式起作用

  // This code only supports certain standard baud rates. Supporting
  // non-standard baud rates should be possible but takes more work.
  switch (baud_rate)
  {
  case 4800:   cfsetospeed(&options, B4800);   break;
  case 9600:   cfsetospeed(&options, B9600);   break;
  case 19200:  cfsetospeed(&options, B19200);  break;
  case 38400:  cfsetospeed(&options, B38400);  break;
  case 115200: cfsetospeed(&options, B115200); break;
  case 230400: cfsetospeed(&options, B230400); break;
  default:
    fprintf(stderr, "warning: baud rate %u is not supported, using 9600.\n", baud_rate);
    cfsetospeed(&options, B9600);
    break;
  }
  cfsetispeed(&options, cfgetospeed(&options));
 
  result = tcsetattr(fd, TCSANOW, &options);
  if (result)
  {
    perror("tcsetattr failed");
    close(fd);
    return -1;
  }
 
  return fd;
}
 
// Writes bytes to the serial port, returning 0 on success and -1 on failure.
int write_port(int fd, uint8_t * buffer, size_t size)
{
  ssize_t result = write(fd, buffer, size);
  if (result != (ssize_t)size)
  {
    perror("failed to write to port");
    return -1;
  }
  return 0;
}
 
// Reads bytes from the serial port.
// Returns after all the desired bytes have been read, or if there is a
// timeout or other error.
// Returns the number of bytes successfully read into the buffer, or -1 if
// there was an error reading.
ssize_t read_port(int fd, uint8_t * buffer, size_t size)
{
  size_t received = 0;
  while (received < size)
  {
    ssize_t r = read(fd, buffer + received, size - received);
    if (r < 0)
    {
      perror("failed to read from port");
      return -1;
    }
    if (r == 0)
    {
      printf("\rRCV timeout");
    }
    received += r;
  }
  return received;
}

 整体程序

//serial_port.cpp
#include "serial_port.h"

void SerialPub::initialize() {
    pps_bit=false;
    handshake_bit=false;
    revice_bit=false;
    timestamp=0;
    pre_timestamp=0;
    time_dt=0;
    speedv_cnt=0;
    anglev_cnt=0;
    Pre_right_enc=0;
    Pre_left_enc=0;
    odom_X=0;
    odom_Y=0;
    AiCloud_bit=0;
    Location_bit=0;
    frame_buff[FRAME_LEN] = {0};
    device=open_serial_port("/dev/ttyGS1", 230400);
    std::cout<<"**********************open**************"<<device<<std::endl;
    if (device < 0) 
    {
        ROS_INFO_STREAM("Unable to open serial port");
    }
    else
    {
        ROS_INFO_STREAM("Serial port opened successfully");
    }
}

SerialPub::SerialPub(ros::NodeHandle node, ros::NodeHandle private_nh,std::string serial_name,bool usb_log_) {
    //private_nh.param("ser_port", ser_port, std::string("/dev/serial_px30"));
    std::cout<<"**************************"<<serial_name<<std::endl;
    test_cs=usb_log_;
    my_time=new TIME[1];
    ros::Rate loop_rate(200);    //设置发送数据的频率为100Hz
    initialize(); 
    CldPotAi_Sub = node.subscribe("/cloud_point_ai",5, &SerialPub::PCA_Callback,this);
    Location_Sub = node.subscribe("/Location_pose",5, &SerialPub::Loc_Callback,this);
    pub_gps_fix = node.advertise<sensor_msgs::NavSatFix>("GPS_fix", 5);
    pub_odom = node.advertise<nav_msgs::Odometry>("Ser_odom", 5);
    pub_imu = node.advertise<sensor_msgs::Imu>("Ser_imu", 5);
}

void Serial_Send(SerialPub *Ser_)
{ 
    std::vector<uint8_t> vec;
    std::cout<<"ai serial send"<<std::endl;
    uint8_t send_date_Head[40] = {
    0xA4,0x59,0x43,//begin
    0x04,
    0x01,0x01,
    0x00,0x00,0x00,0x1C,//length 6-9
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//time 10-17
    0x00,0x00,0x00,0x00,//state 18-21
    0x00,0x00,0x00,0x00,//error 22-25
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//date 26-37 location
     //34 obs-length uint16_t
    0x0D,0x0A};//38-39
    uint32_t send_length=0x01;
    uint32_t out_status=0;
    uint64_t out_time=0;
    uint32_t out_error=0;
    uint8_t aaaaaa=0x00;
    while(ros::ok()){
        //vec.clear(); 
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        if(Ser_->handshake_bit)
        {                      
            //https://blog.csdn.net/ktigerhero3/article/details/108017281;
            ///save number
            vec.resize(38);
            if(Ser_->AiCloud_bit&&Ser_->Location_bit&&Ser_->vec_ai.size()>0)
            {
               //vec.resize(Ser_->vec_ai.size()+38);
               out_status=0x01;
               out_error=0x01;
               //send_length=40+Ser_->vec_ai.size();
               for(int i_loc=0;i_loc<12;i_loc++)//gai i=0
               {
                   vec[26+i_loc]=Ser_->vec_loc[i_loc];
               }
               vec.insert(vec.begin()+37,Ser_->vec_ai.begin(),Ser_->vec_ai.end());
               Ser_->AiCloud_bit=false;
               Ser_->Location_bit=false;
            }
            else if(Ser_->Location_bit){ //Loc short package vec_loc
               out_status=0x02;
               out_error=0x02;
               for(int i_loc=0;i_loc<12;i_loc++)//gai i=0
               {
                   vec[26+i_loc]=Ser_->vec_loc[i_loc];
               }
               Ser_->Location_bit=false;
            }
            else if (Ser_->AiCloud_bit&&Ser_->vec_ai.size()>0)
            {
                vec.resize(Ser_->vec_ai.size()+38);
                out_status=0x04;
                out_error=0x04;
                vec.insert(vec.begin()+37,Ser_->vec_ai.begin(),Ser_->vec_ai.end());
                Ser_->AiCloud_bit=false;
            }
            else
           {  // AI + Loc big package   vec_loc vec_ai
               out_status=0x08;
               out_error=0x08;                      
            }

            for(int i=0;i<38;i++){
                vec[i]=send_date_Head[i];
            }//head
            out_time=std::chrono::duration_cast<std::chrono::microseconds>
                                  (std::chrono::system_clock::now().time_since_epoch()).count();
            vec.push_back(send_date_Head[38]);
            vec.push_back(send_date_Head[39]);

            vec[vec.size()-3]=aaaaaa++;
            send_length=vec.size()-12;
            vec[6]=(send_length>>24)&0xFF;
            vec[7]=(send_length>>16)&0xFF;
            vec[8]=(send_length>>8)&0xFF;
            vec[9]=send_length;

            vec[10]=out_time;
            vec[11]=(out_time>>8)&0xFF;
            vec[12]=(out_time>>16)&0xFF;
            vec[13]=(out_time>>24)&0xFF;
            vec[14]=(out_time>>32)&0xFF;
            vec[15]=(out_time>>40)&0xFF;
            vec[16]=(out_time>>48)&0xFF;
            vec[17]=(out_time>>54)&0xFF;

            vec[18]=out_status;
            vec[19]=out_status<<8;
            vec[20]=out_status<<16;
            vec[21]=out_status<<24;

            vec[22]=out_error;
            vec[23]=out_error<<8;
            vec[24]=out_error<<16;
            vec[25]=out_error<<24;            
            ssize_t rtn;
            uint8_t send_buf[vec.size()];
            for(int send_i=0;send_i<vec.size();send_i++)
            {
                send_buf[send_i]=vec[send_i];
            }
            rtn = write_port(Ser_->device, send_buf, sizeof(send_buf));
            if(rtn == 0)
            {
               ROS_INFO_STREAM("serial send success");
            }
        }
    }
}

void SerialPub::Loc_Callback(const std_msgs::UInt8MultiArray::ConstPtr &msg){
    Location_bit=true;
    for(int i = 0; i < msg->data.size();i++){
        vec_loc[i]=msg->data[i];
    }     //for(int i = 0; i < vec.size();i++){printf("%02x ",vec[i]);}printf("\n");  
}

void SerialPub::PCA_Callback(const std_msgs::UInt8MultiArray::ConstPtr &msg){
    vec_ai.clear();
    AiCloud_bit=true;
    for(int i = 0; i < msg->data.size();i++){
        vec_ai.push_back(msg->data[i]);
    }     //for(int i = 0; i < vec.size();i++){printf("%02x ",vec[i]);}printf("\n");   
}

SerialPub::~SerialPub() {
    delete my_time;
    close(device);
}

void SerialPub::listen_ser()
{
    uint8_t frame_buff_[5000];
    ssize_t rtn=0;
    if(handshake_bit)
    { 
        memset(buf_save,0,sizeof(buf_save));
        while(1)
        {
            read(device,buf_save,1);
            if(buf_save[00]==0xA4)
            {
                frame_buff_[0]=0xA4;
                read(device,buf_save,1);
                if(buf_save[00]==0x59)
                {
                    frame_buff_[1]=0x59;
                    read(device,buf_save,1);
                    if(buf_save[00]==0x43)
                    {
                        frame_buff_[2]=0x43;
                        break;                        
                    }
                }
            }
        }
        rtn = read_port(device, buf_save, 7);
        if(rtn>0)
        {        
            for(int buf_i=0;buf_i<7;buf_i++)
            {
                frame_buff_[buf_i+3]=buf_save[buf_i];
                printf("%02x ", frame_buff_[buf_i]);           
            }
            printf("\n");
        }
        n_size=frame_buff_[9]+(frame_buff_[8]<<8)+(frame_buff_[7]<<16)+(frame_buff_[6]<<24);
        std::cout<<n_size <<std::endl;
        printf("\n");
        rtn = read_port(device, buf_save, n_size+2);//read 0d 0a
        for(int buf_i=0;buf_i<n_size+2;buf_i++)// 0d 0a
           frame_buff_[buf_i+10]=buf_save[buf_i];
        ROS_INFO_STREAM("serial recive");
        for(int frame_i=0;frame_i<n_size+12;frame_i++)
        {
            frame_buff[frame_i]=frame_buff_[frame_i];
        }
        //handshake_bit=true;
        revice_bit=true;        
    }
}

void Serial_Receive(SerialPub *Ser_)
{
    while(ros::ok()){
       Ser_->listen_ser();
    }
}

void PPS_Receive(SerialPub *Ser_)
{
    std::cout<<"run1"<<std::endl;
    pps_handle_t handle[4];
    int avail_mode[4];
    int ret;
    std::string pps_str="/dev/pps0";
    char dev_pps[20];
    pps_str.copy(dev_pps, 8, 0);         
    *(dev_pps+9)='\0'; 
    strcpy((dev_pps), pps_str.c_str());
    
    std::cout<<"pps"<<dev_pps<<std::endl;
    ret = find_source(dev_pps, &handle[0], &avail_mode[0]);//check pps source is opened, set /dev/pps0
    if (ret < 0)
	exit(EXIT_FAILURE);
    printf("ok, found %d source(s), now start fetching data...\n",0);
    while(ros::ok()){  
       ret = fetch_source(0, &handle[0], &avail_mode[0]);//support check a lot pps source  block
       if (ret < 0 && errno != ETIMEDOUT)
          exit(EXIT_FAILURE);
       if(ret==0)
       {
          Ser_->pps_bit=true;
       }       
    }
    time_pps_destroy(handle[0]);  /**/  
}



void SerialPub::Ser_pub(){
    char *ret1;
    char *ret2;

    handshake_bit=true;

    uint8_t HandShake[]={0xA4,0x59,0x43,0x04,0x07,0x02,0x00,0x00,0x00,0x01,0x00,0x0D,0x0A};
    while (ros::ok()) 
    {
        if (revice_bit) {  
            revice_bit=false;        
            uint32_t yz_len=frame_buff[9]+(frame_buff[8]<<8)+(frame_buff[7]<<16)+(frame_buff[6]<<24);
            if((yz_len==1)&&(handshake_bit==false)){
                printf("test handshake\n");
                write_port(device, HandShake, sizeof(HandShake));
            }
            else if (n_size == yz_len) {//验证长度
                handshake_bit=true;
                std::vector<uint8_t> vec_data_rcv(frame_buff, frame_buff + FRAME_LEN);
                ret1 = strstr((char*)frame_buff,(char*)MSG_H);//验证头 遇到00会停止检测,只能验证头
                if(ret1!=NULL)
                {
                    //ret2 = strstr((char*)frame_buff, (char*)MSG_E);
                    if(frame_buff[yz_len+12-1]==0x0A&&frame_buff[yz_len+12-2]==0x0D)//验证尾
                    {		
                        //  qxwz_rtcm_sendGGAWithGGAString(sendbuf);
                        std::vector<uint8_t>::iterator match_TIME_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_TIME, MSG_H_TIME + 3);
                        if(match_TIME_H!=vec_data_rcv.end()){
                            time_del(match_TIME_H);
                        }
                        else{
                            ROS_INFO_STREAM("find time false");
                        }                     
                        std::vector<uint8_t>::iterator match_GPS_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_GPS, MSG_H_GPS + 3);
                        if(match_GPS_H!=vec_data_rcv.end()){
                            gps_del(match_GPS_H);
                        }
                        else{
                            ROS_INFO_STREAM("find rtk false");
                        }                  
                        std::vector<uint8_t>::iterator match_IMU_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_IMU, MSG_H_IMU + 3);
                        if(match_IMU_H!=vec_data_rcv.end()){
                            imu_del(match_IMU_H);
                        }
                        else{
                            ROS_INFO_STREAM("find imu false");
                        }
                        std::vector<uint8_t>::iterator match_ODOM_H = std::search(vec_data_rcv.begin(), vec_data_rcv.end(),MSG_H_ODOM, MSG_H_ODOM + 3);
                        if((match_ODOM_H!=vec_data_rcv.end())){
                            odom_del(match_ODOM_H);
                        }
                        else{
                            ROS_INFO_STREAM("find odom false");
                        } 
                    }
                    else{
                        ROS_INFO_STREAM("end false");
                    } 
                }
                else{
                    ROS_INFO_STREAM("head false");
                }                   
                vec_data_rcv.clear();
            }
            else{
                ROS_INFO_STREAM("length false");
            }
        }
        else {
            //ROS_INFO_STREAM("no data");
        }            
        ros::spinOnce(); 
    }
    close(device);  
}

bool SerialPub::time_del(std::vector<uint8_t>::iterator match_TIME_){
    const TIME_frame_t * Time_frame_p=(const TIME_frame_t *) &*(match_TIME_+3); 
    if(test_cs)  
      printf("%d/%d/%d\n", Time_frame_p->ucYear,Time_frame_p->ucMonth,Time_frame_p->ucDay);
    timestamp= Time_frame_p->MsOneDay;
    time_dt=pre_timestamp-timestamp;
    pre_timestamp=timestamp;
    if(pps_bit){
        my_time->year=Time_frame_p->ucYear;
        my_time->month=Time_frame_p->ucMonth;
        my_time->day=Time_frame_p->ucDay;
        if(my_time->year<2000){
            my_time->year=2021;
            my_time->month=0x0c;
            my_time->day=0x08;
        }
        my_time->hour=Time_frame_p->MsOneDay/1000/60/60;
        my_time->minute=Time_frame_p->MsOneDay/1000/60;
        my_time->second=(Time_frame_p->MsOneDay+500)/1000;                                                                                                                           
        if(!systime.setSystemTime(my_time))
          std::cout<<"settime false"<<std::endl;
        pps_bit=false;
    }
}

bool SerialPub::gps_del(std::vector<uint8_t>::iterator match_GPS_){
    const GPS_frame_t * GPS_frame_p=(const GPS_frame_t *) &*(match_GPS_+3);
    const GPS_frame_t1 * GPS_frame_p1=(const GPS_frame_t1 *) &*(match_GPS_+24);
    float latstd = GPS_frame_p1->lat_std;
    float lonstd = GPS_frame_p1->lon_std;
    int   levela = (int)GPS_frame_p->level;
    //std::cout<<"level="<<levela<<std::endl;
    //std::cout<<"latstd="<<latstd<<std::endl;
    //std::cout<<"lon="<<lonstd<<std::endl;
    float latvar = latstd*latstd;
    float lonvar = lonstd*lonstd;
    
    fix.header.stamp.fromNSec(timestamp);
    fix.status.status=levela;
    fix.altitude=GPS_frame_p->hgt;
    fix.latitude=GPS_frame_p->lat;
    fix.longitude=GPS_frame_p->lon;
    fix.position_covariance={ lonvar, 0, 0,
                                0, latvar, 0,
                                0, 0, 0};
    fix.header.frame_id = "GPS_fix";
    pub_gps_fix.publish(fix);
    return true;
}

bool SerialPub::imu_del(std::vector<uint8_t>::iterator match_IMU_){
    const IMU_frame_t * IMU_frame_p=(const IMU_frame_t *) &*(match_IMU_+3);                       
    imu_data.header.stamp.fromNSec(timestamp);
    imu_data.header.frame_id = "imu_link";
    imu_data.angular_velocity.x = IMU_frame_p->gyro_x;
    imu_data.angular_velocity.y = IMU_frame_p->gyro_y;
    imu_data.angular_velocity.z = IMU_frame_p->gyro_z;

    imu_data.linear_acceleration.x = IMU_frame_p->acc_x;
    imu_data.linear_acceleration.y = IMU_frame_p->acc_y;
    imu_data.linear_acceleration.z = IMU_frame_p->acc_z;
    
    pub_imu.publish(imu_data); 
}

bool SerialPub::odom_del(std::vector<uint8_t>::iterator match_ODOM_){
    const ODOM_frame_t * ODOM_frame_p=(const ODOM_frame_t *) &*(match_ODOM_+3);
    uint32_t right_enc=ODOM_frame_p->right_encode;
    uint32_t left_enc=ODOM_frame_p->left_encode;
    //printf("right_enc=%d", right_enc);
    //printf("left_enc=%d", left_enc);
    //printf("\n");
    int32_t R_encodeCdif=right_enc-Pre_right_enc;
    int32_t L_encodeCdif=left_enc-Pre_left_enc;
    //当编码器启动时,发生跳变时,值为0;3000rpm,线数10000 0.1s=50000线
    if(R_encodeCdif>50000&&R_encodeCdif<-50000&&L_encodeCdif>50000&&L_encodeCdif<-50000)
    {
        R_encodeCdif=0;
        L_encodeCdif=0;
    }
    float distance_sum = 0.5f*(R_encodeCdif+L_encodeCdif);//短时间内,前进距离两侧速度和
    float distance_diff = R_encodeCdif-L_encodeCdif;//短时间内,转弯角度为两侧速度差
        
    float Yaw_Angle_Diff = distance_diff * const_angle;// 采样期间走的角度
    float Yaw_Angle=Yaw_Angle+Yaw_Angle_Diff;//计算里程计方向角
    float Yaw_Angle_1 = Yaw_Angle + 0.5f * Yaw_Angle_Diff;//里程计方向角数据位数变化,用于三角函数计算


    odom_X=odom_X+distance_sum*cos(Yaw_Angle_1)*const_frame;   //距离*Yaw(偏角) 解析X坐标
    odom_Y=odom_Y+distance_sum*sin(Yaw_Angle_1)*const_frame;
    // 当前瞬时线速度  w=th/t
    float SpeedV_Ang=0,SpeedV_V=0;
    if(time_dt!=0)
    {
        SpeedV_Ang=Yaw_Angle_Diff/time_dt;    //角速度				
        SpeedV_V=(distance_sum*const_frame)/time_dt;   //速度=位移/时间; 时间=定时间*Timer 
    }       
    if(speedv_cnt<3)
    {				
        speedvsave[speedv_cnt]=SpeedV_V;
        speedv_cnt++;
    }else
    {
        speedv_cnt=0;
        speedvsave[speedv_cnt]=SpeedV_V;
        speedv_cnt++;
    }		
    float Speedv_send=0;
    for(int speedvplus=0;speedvplus<3;speedvplus++)
    {		
        Speedv_send=Speedv_send+speedvsave[speedvplus];
    }
    Speedv_send=Speedv_send/3;

    if(anglev_cnt<3)
    {				
        anglevsave[anglev_cnt]=SpeedV_Ang;
        anglev_cnt++;
    }else
    {
        anglev_cnt=0;
        anglevsave[anglev_cnt]=SpeedV_Ang;
        anglev_cnt++;
    }		
    float Anglev_send=0;
    for(int anglevplus=0;anglevplus<3;anglevplus++)
    {		
        Anglev_send=Anglev_send+anglevsave[anglevplus];
    }
    Anglev_send=Anglev_send/3;

    if(Yaw_Angle > pi)
    {
        Yaw_Angle -= pi_2_1;//减2pi
    }
    else
    {
        if(Yaw_Angle < -pi)
        {
            Yaw_Angle+=pi_2_1;//加2pi
        }
    }					 
    Pre_right_enc=right_enc;
    Pre_left_enc=left_enc;

    ser_odom.header.stamp.fromNSec(timestamp);
    ser_odom.header.frame_id = "odom";
            
    //set the position
    ser_odom.pose.pose.position.x = odom_X;
    ser_odom.pose.pose.position.y = odom_Y;
    ser_odom.pose.pose.position.z = 0.0;
    geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(Yaw_Angle);//将偏航角转换成四元数

    ser_odom.pose.pose.orientation = odom_quat;

    //set the velocity
    ser_odom.child_frame_id = "base_link";
    ser_odom.twist.twist.linear.x = Speedv_send*cos(Yaw_Angle);//线速度
    ser_odom.twist.twist.linear.y = Speedv_send*sin(Yaw_Angle);//线速度
    ser_odom.twist.twist.angular.z = Anglev_send;//角速度
    //载入covariance矩阵  https://blog.csdn.net/ethan_guo/article/details/79635575
    if ((Speedv_send==0)&&(Anglev_send==0))//机器人静止和动起来
    {
        ser_odom.pose.covariance = ODOM_POSE_COVARIANCE2;
        ser_odom.twist.covariance = ODOM_TWIST_COVARIANCE2;
    }
    else
    {
        ser_odom.pose.covariance = ODOM_POSE_COVARIANCE;
        ser_odom.twist.covariance = ODOM_TWIST_COVARIANCE;
    }
    //publish the message
    pub_odom.publish(ser_odom);  
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值