锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

无人小巴自动循迹和雷达避障程序全解析(参加秋招用)

时间:2023-04-20 21:37:00 gmc功率变送器sineax

简介:无人小巴的整体功能分为自动跟踪、雷达避障和APP控制启停
一、自动跟踪
一是入口函数main.c创建了7个线程

void Start_Threads_Process() { 
         int ret;  #ifndef NavTestMode        ret = pthread_create(&RecvFromCAN_tid, NULL, RecvFromCAN_pthread,NULL);  if(ret!=0)  { 
          printf("Create thread to recv can msg failed\n");  }    ret = pthread_create(&RecvFromPL_tid, NULL, RecvFromPL_pthread, NULL);  if(ret!=0)  { 
          printf("Create thread to recv PLdata msg failed\n");  }     ret = pthread_create(&Process_tid,NULL,Process_pthread,NULL);  if(ret!=0)  { 
          printf("Create thread to track failed\n");  }     ret = pthread_create(&SendToCAN_tid, NULL, SendToCAN_pthread, NULL);  if (ret != 0)  { 
          printf("Create thread to send can msg failed\n");
	}
#endif
    
	ret = pthread_create(&RecvFromIMU_tid, NULL, RecvFromIMU_pthread, NULL);
	if (ret != 0)
	{ 
       
		printf("Create thread RecvFromIMU_pthread failed\n");
	}
	ret = pthread_create(&AnalysisIMU_tid, NULL, AnalysisIMU_pthread, NULL);
	if (ret != 0)
	{ 
       
		printf("Create thread AnalysisIMU_pthread failed\n");
	}

	ret = pthread_create(&SendCarState_tid, NULL, SendCarState_pthread, NULL);
	if (ret != 0)
	{ 
       
		printf("Create thread SendCarState_pthread failed\n");
	}

}

2.首先是RecvFromCAN_pthread(从CAN口接收数据线程)
这里面有车辆状态结构体vcu_vstate1_st,形式如下:

struct vcu_vstate1_st{ 
       
    //1
    unsigned char autopilot:2;
    unsigned char door:1;
    unsigned char daytime_driving_light:1;
    unsigned char left_blinker:1;
    unsigned char right_blinker:1;
    unsigned char warning_light:1;
    unsigned char clearance_light:1;
    
    //2
    unsigned char front_foglight:2;
    unsigned char rear_foglight:1;
    unsigned char left_foglight:1;
    unsigned char right_foglight:1;
    unsigned char interior_light:1;
    unsigned char ambient_light:1;
    unsigned char reserved1:1;
    
    //3
    unsigned char speed;  //车速

    //4
    unsigned char SOC;

    //5
    unsigned char system_power:2;//智能系统电源指令
    unsigned char charge_status:2;//充电状态
    unsigned char charger_connection_status:2;//充电连接指示
    unsigned char failure_level:2;//整车故障级别

    //6~7
    unsigned short reserved2;
    //8
    unsigned char heartbeat;
};

接下来就是提取从CAN口里面上传的车辆数据,存放在vcu_vstate1_st结构体中。
(1)首先定义一个结构体对象

struct vcu_vstate1_st g_vcu_vstate1;

(2)接下来经历CAN口初始化和CAN口接收

/*CAN通信初始化 */
int can_init()
{ 
       
	struct sockaddr_can addr;//CAN地址对象
	struct can_frame frame;//存放CAN口上传数据的结构体
	struct ifreq ifr;
	fd_set readSet; 
	const char *ifname = "can0";
	struct can_filter filter[3];
	int enable = 1;
	int s = -1;
	if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
	{ 
       
		perror("Error while opening socket");
		return -1;
	}
	setsockopt(
		s,
		SOL_CAN_RAW,
		CAN_RAW_FD_FRAMES,
		&enable,
		sizeof(enable)
	);
	strcpy(ifr.ifr_name, ifname);
	ioctl(s, SIOCGIFINDEX, &ifr);
	addr.can_family = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;
	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
	{ 
       
		perror("Error in socket bind");
		return -2;
	}
	return s;
}
当接收到id号为VCU_VEHICLE_STATE1的数据帧头的时候,就把frame也就是CAN口上传的数据存放在g_vcu_vstate1中
/*接收CAN数据 */
void *can_recv()
{ 
       
	int s = can_init();//CAN口初始化,返回CAN口标志位
	fd_set readSet;
	int nbytes;
	struct can_frame frame;
	while (1)
	{ 
       
		FD_ZERO(&readSet);
		FD_SET(s, &readSet);
		if (select((s + 1), &readSet, NULL, NULL, NULL) > 0)
		{ 
       
			if (FD_ISSET(s, &readSet))
			{ 
       
				nbytes = read(s, &frame, sizeof(struct can_frame));//把s指向地址里面的数据放入frame
				unsigned int id;
				id = frame.can_id & CAN_EFF_MASK;
				if (id == VCU_VEHICLE_STATE1)//当接收到id号为VCU_VEHICLE_STATE1的数据帧头的时候,就把frame也就是CAN口上传的数据存放在g_vcu_vstate1中
				{ 
       
					//printf("VCU_VEHICLE_STATE1收到了---------------%d\n", nbytes);
					pthread_mutex_lock(&Mutex_CAN_DATA);
					memcpy(&g_vcu_vstate1, frame.data, frame.can_dlc * sizeof(char));
					pthread_cond_signal(&Cond_CAN_DATA);
					pthread_mutex_unlock(&Mutex_CAN_DATA);
				}
				// else if(id == VCU_DRIVE_STATE)
				// { 
       
				// printf("VCU_DRIVE_STATE收到了---------------%d\n",nbytes);
				// memcpy(&g_vcu_dstate, frame.data, frame.can_dlc * sizeof(char));
				// }
				else
				{ 
       
					/*暂不解析 */
				}
			}
		}
	}
}

2.然后是RecvFromIMU_pthread(接收IMU数据线程)
因为我们这边采用的是全星SV2的惯导设备,里面集成GPS和IMU,里面传出来的数据格式中可以提取经纬度、速度以及转向角信息,比如:GPRMC和GNHDT
总体思路:先打开串口,然后把串口里面的数据读取出来,存放在一个数组中,最后解析这个数组中数据,把当中有用的信息提取出来。

void *RecvFromIMU_pthread(void *args)
{ 
       
    memset(g_RecvDataFromRTK,0,sizeof(g_RecvDataFromRTK));//初始化g_RecvDataFromRTK数组里面的内容,将其清空
    pfile=fopen("LOG.txt","a");
    if(pfile==NULL){ 
       
        printf("打开文件写LOG失败\n");
    }
    if(IsInit==false)//刚开始IsInit==false
    { 
       
        if(initialize()<0)//初始化中主要功能是打开串口、设置波特率和设置标志位
        { 
       
            printf("MC: 打开串口配置参数失败\n");
            return 0;
        }
        IsInit=true;
        printf("MC: 打开串口配置参数成功\n");
    }
	int nBytes_0 = 0;
	int nBytes_1 = 0;
    while(1)
    { 
       
        usleep(60000);
        memset(&g_RecvDataFromRTK_1, 0, sizeof(g_RecvDataFromRTK_1));

		nBytes_1 = read(g_fd, g_RecvDataFromRTK_1, 200);//将g_fd指向地址里面的数据读到g_RecvDataFromRTK_1中去
		
        //printf("g_RecvDataFromRTK_1:%s\n",g_RecvDataFromRTK_1);
        
		//printf("nBytes0=%d,nBytes=%d\n", nBytes_0, nBytes_1);
        
		if (g_RecvDataFromRTK_1[0] == '$')//分别判断gprmc和grhdt两个数据格式的数据位
		{ 
                              
			char *ret;
            int i;
            int gps_num = 0;
            for(i = 0;i < 200;i++)
            { 
       
                
                if(g_RecvDataFromRTK_1[i] == '*')
                { 
       
                    gps_num++;
                }
                if(gps_num == 2)
                { 
       
                    break;
                }                  
            }
            if(i != 200&&i > 80)
            { 
       
                process_len = i;
                //printf("g_RecvDataFromRTK_1:%s\n",g_RecvDataFromRTK_1);
                for(int j=0;j<i;j++)
                { 
       
                    g_DataCombine[j] = g_RecvDataFromRTK_1[j];
                }
                pthread_mutex_lock(&gMutex_SC_data);
				memcpy(g_ProcDataFromSCBuf, g_DataCombine, DATALEN);
				pthread_cond_signal(&gCond_SC_data);
				pthread_mutex_unlock(&gMutex_SC_data);
            }							
		}
    }
    return 0;
}

void *AnalysisIMU_pthread(void *args)
{ 
       
    char localproc_SCData[200] = { 
       0};
    int localproc_len=0;
    int num_rmc = 0;
    int num_gga=0;
    int num_dht=0;
	memset(&g_IMUdata, 0, sizeof(IMUdata));
    while(1)
    { 
       
       
        pthread_mutex_lock(&gMutex_SC_data); 
        pthread_cond_wait(&gCond_SC_data,&gMutex_SC_data);
        memcpy(localproc_SCData,g_ProcDataFromSCBuf,process_len) ;
        localproc_len=process_len;
        num_rmc = 0;
        num_gga=0;
        num_dht=0;
        //printf("接收到%d个字节\n",localproc_len);
        pthread_mutex_unlock(&gMutex_SC_data);

        double g_Lattitude_tmp = 0;
        double g_Longitude_tmp = 0;
        //double g_Speed_tmp = 0;
        double g_Heading_tmp = 0;
        char rtk_num[1] = { 
       0};
        char *p_gprmc = strstr(localproc_SCData,"GPRMC");
        char *p_gpdht = strstr(localproc_SCData,"GNHDT");
        if(p_gprmc == NULL || p_gpdht == NULL)
          continue;
        int gprmc_len = 80;
        int gpdht_len = 20;

        for(int i = 0;i < gprmc_len;i++)
        { 
       
            if(p_gprmc[i] == 0x2c)
            { 
       
                num_rmc++;
                if(num_rmc == 3)
                { 
       
                    for(int j=i+1;;j++)
                    { 
       
                        if(p_gprmc[j]==0x2c)
                        { 
       
                            break;
                        }
                        else if(p_gprmc[j]!=0x2e)
                        { 
       
                            g_Lattitude_tmp*=10;
                            g_Lattitude_tmp+=(p_gprmc[j]-48);
                        }
                    }
                    //
                }
                else if(num_rmc == 5)
                { 
       
                    for(int j=i+1;;j++)
                    { 
       
                        if(p_gprmc[j]==0x2c)
                        { 
       
                            break;
                        }
                        else if(p_gprmc[j]!=0x2e)
                        { 
       
                            g_Longitude_tmp*=10;
                            g_Longitude_tmp+=(p_gprmc[j]-48);
                        }
                    }
                    break;
                    //
                }
                /*else if(num_rmc == 7) { for(int j=i+1;;j++) { if(p_gprmc[j]==0x2c) { break; } else if(p_gprmc[j]!=0x2e) { g_Speed_tmp*=10; g_Speed_tmp+=(p_gprmc[j]-48); } } }*/
                /*else if(num_rmc == 10) { rtk_num[0] = p_gprmc[i+1]; break; }*/
            }
        }
        for(int i=0;i<gpdht_len;i++)
        { 
       
            if(p_gpdht[i]==0x2c)
            { 
       
                num_dht++;
                if(num_dht == 1)
                { 
       
                    for(int j=i+1;;j++)
                    { 
       
                        if(p_gpdht[j]==0x2c)
                        { 
       
                            break;
                        }
                        else if(p_gpdht[j]!=0x2e)
                        { 
       
                            g_Heading_tmp*=10;
                            g_Heading_tmp+=(p_gpdht[j]-48);
                        }
                    }
                    //
                    break;
                }                                   
            }
        }
        g_Lattitude_tmp/=10000000000;
        g_Longitude_tmp/=10000000000;
        g_Heading_tmp/=10000;

        double lat_int,lat_fraction;
        double lon_int,lon_fraction;
        lat_fraction = modf(g_Lattitude_tmp,&lat_int);
        lon_fraction = modf(g_Longitude_tmp,&lon_int);
        g_Lattitude = lat_int+lat_fraction/60*100;
        g_Longitude = lon_int+lon_fraction/60*100;
        g_Heading = g_Heading_tmp;
        //printf("g_Lattitude: %lf \n",g_Lattitude);
        //printf("g_Longitude: %lf \n",g_Longitude);
        //printf("g_Heading: %lf \n",g_Heading);
        //printf("g_Speed_tmp: %lf \n",g_Speed_tmp); 
    }
    return 0;
}

3.接下来是关键信息发送线程(SendCarState_pthread),发送到PL模块去
把IMU接收过来的经纬度,转向角数据存放在导航信息结构体gMC_NAV,通过与路径规划PL模块建立UDP通信,广播状态信息

/*导航信息 */
typedef struct tagWRC_MC_NAV_INFO
{ 
       
	UINT16 Head;           //数据帧头 固定值 0x0824
	UINT8 Group;           //车辆组号
	UINT8 ALV_ID;          //车辆编号
	UINT32 FrameID; 
	WRC_IP_TIME synTime;     //时刻
	UINT8 GPS_Status;        //GPS状态
	UINT8 NAV_Status;        //惯导状态 见上“惯导组合状态 ”
	
	UINT8 IS_NAV_Err;        //导航数据是否有错: 0-无错,非零-有错
	UINT32 navID;            //导航信息编号(从0开始)
	//位姿
	double Latitude_degree;  //单位:度
	double Longitude_degree; //单位:度 
	
	double Altitude_m;       //单位:米
	double EarthRefCoord[2]; // 地面平面坐标系 单位:米 [0] 北向 +X [1] 东向 +Y 注意:暂时以校内智能楼差分站为参考基准
	
	float Roll_rad;          //单位:弧度 
	float Pitch_rad;         //单位:弧度
	float Yaw_rad;           //单位:弧度
	//速度
	INT16 Speed_cm_ps;          //单位:厘米/秒
	INT16 SPD_LefWheel_cm_ps;   //单位:厘米/秒
	INT16 SPD_RightWhell_cm_ps; //单位:厘米/秒
	INT16 IMU_R_xyz_mrad[3];    //角速率:毫弧度
	INT16 IMU_A_xyz_mm_ps[3];   //IMU加速度:毫米
	//GPS
	UINT16 GpsSol_pDOP;      //0.01,Postition DOP
	UINT8  GpsSol_numSV;     //Number of Svs used in navigation solution; 
	UINT16 GpsSol_ecefX_cm;  //ECEF X: 单位厘米
	UINT16 GpsSol_ecefY_cm;  //ECEF Y: 单位厘米
	UINT16 GpsSol_ecefZ_cm;  //ECEF Z: 单位厘米
	//安全
	UINT16 nSize;     //结构体大小 
	UINT8 checksum;   //Checksum of above data.
}WRC_MC_NAV_INFO;
memset(&gMC_NAV, 0, sizeof(gMC_NAV));
gMC_NAV.Head = 0x0824;
gMC_NAV.navID = NAV;
gMC_NAV.Latitude_degree = g_Lattitude;
gMC_NAV.Longitude_degree = g_Longitude;
gMC_NAV.Yaw_rad = g_Heading;
gMC_NAV.Speed_cm_ps = (g_vcu_vstate1.speed - 50) / 3.6 * 100;
gMC_NAV.nSize = sizeof(gMC_NAV);
int UDP_send_data()
{ 
       
	if (initial == false) { 
       
		initial = true;
		if ((brdcFd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
		{ 
       
			printf("fail to create socket\n");
			return -1;
		}
		 
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章