当前位置:首页 > 汽车电子 > 汽车电子
[导读]车载ADAS里毫米波雷达常走UART数据口或车载以太网上送点云/目标列表。Linux侧别指望“open设备节点就能拿到结构体”,真实数据是二进制字节流:帧同步头+帧头+TLV块。驱动层负责收字节、对齐帧边界;应用层负责解析点云、时间对齐、送感知线程。


车载ADAS里毫米波雷达常走UART数据口或车载以太网上送点云/目标列表。Linux侧别指望“open设备节点就能拿到结构体”,真实数据是二进制字节流:帧同步头+帧头+TLV块。驱动层负责收字节、对齐帧边界;应用层负责解析点云、时间对齐、送感知线程。

一、接入方式:配置口与数据口分开

TI系模块典型是两路串口:一路CLI发cfg配置(chirp参数、帧率、输出TLV类型),一路高速数据口出点云;以太网方案(DCA1000类)则走UDP原始流。

Linux下用termios配数据口:

int radar_open(const char*dev){

   int fd=open(dev,O_RDWR|O_NOCTTY);

   struct termios t; tcgetattr(fd,&t);

   cfsetispeed(&t,B921600); cfsetospeed(&t,B921600);

   t.c_cflag |= CS8|CREAD|CLOCAL; t.c_lflag=0; t.c_iflag=0;

   t.c_oflag=0; t.c_cc[VTIME]=0; t.c_cc[VMIN]=0;

   tcsetattr(fd,TCSANOW,&t); return fd;

}

CLI口只在启动时写配置,写完后关掉;数据口常开,单独采集线程读。

二、帧同步:按Magic Word重对齐

雷达持续吐流,中间丢几字节就会整体错位。正确做法是环形缓冲收数据,每次搜Magic Word重新同步,不依赖“上次帧长”。

static const uint8_t MAGIC[8]={0x02,0x01,0x04,0x03,0x06,0x05,0x08,0x07};

int find_magic(uint8_t*buf,int len){

   for(int i=0;i+8<=len;i++)

       if(!memcmp(buf+i,MAGIC,8)) return i;

   return -1;

}

帧头里取total_length、frame_num、num_tlv,校验长度够了再解析,不够留着下次拼。

三、TLV解析点云

TLV结构就是type+length+payload,点云块通常是若干点连续排列:

typedef struct{ float x,y,z,doppler; uint16_t snr; }__attribute__((packed)) point_t;

void parse_tlv(uint8_t*p,uint32_t len,point_t*out,int*pcnt){

   uint32_t off=0;

   while(off+4<=len){

       uint32_t type=*(uint32_t*)(p+off);          // 端序按雷达SDK定

       uint32_t sz  =*(uint32_t*)(p+off+4);

       uint8_t *pl=p+off+8;

       if(type==POINT_CLOUD_TLV){

           int n=sz/sizeof(point_t);

           for(int i=0;i<n && *pcnt<MAX_PT;i++){

               point_t pt; memcpy(&pt,pl+i*sizeof(point_t),sizeof(pt));

               out[(*pcnt)++]=pt;

           }

       }

       off+=8+sz;

   }

}

注意三坑:

端序:x/y/z是float小端还是大端,跟芯片SDK走

符号:距离/坐标负数别当uint16解析

单位:米还是厘米、速度是m/s还是放大100倍,必须按协议文档换算

四、实时采集:双缓冲+实时线程

ADAS不允许在主线程里read阻塞、也不允许每帧malloc。做法:

采集线程SCHED_FIFO,绑隔离核

双缓冲:dma/串口读到buf A,解析完交换给感知线程用buf B

只拷贝一次,解析后点云数组送下游

打时间戳用CLOCK_MONOTONIC,跨传感器靠PTP/帧号对齐

struct sched_param sp={.sched_priority=80};

pthread_setschedparam(pthread_self(),SCHED_FIFO,&sp);

cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(2,&cpuset);

pthread_setaffinity_np(pthread_self(),sizeof(cpuset),&cpuset);

串口场景不是真正零拷贝,但双缓冲能避免解析期覆盖、减少系统调用次数;以太网DMA场景才可走mmap ring buffer进一步省拷贝。

主循环伪代码:

uint8_t rx[4096]; point_t frame[MAX_PT];

while(run){

   int n=read(fd,rx,sizeof(rx));

   ring_push(rx,n);

   int sync=resync_magic();

   if(sync>=0 && frame_complete()){

       int cnt=0; parse_header(); parse_tlv(payload,plen,frame,&cnt);

       swap_to_perception(frame,cnt,frame_no,timestamp);

   }

}

五、ADAS工程落坑

波特率不够会丢帧:点云多就上921600或改以太网

帧号跳变要报警:连续丢帧可能是UART溢出或CPU被别的线程抢

解析线程别做聚类/跟踪:只出原始点云,聚类放感知线程

SNR阈值过滤:低信噪比点直接丢弃,减少误检

时间同步:雷达自带frame timestamp,和相机/LiDAR对齐用PTP,别用recv返回时刻

安全:雷达数据进ADAS决策前做范围校验,x/y/z超物理量程按无效点丢弃

调试:先用cat /dev/ttyXXX或python解析确认magic和点数,再写C;别一上来就进系统架构

按“配置口发cfg→数据口收流→Magic重同步→TLV取点云→双缓冲交换→实时线程送感知”落地,嵌入式Linux侧能把毫米波点云稳定接进ADAS流水线;重点不是“驱动多底层”,而是帧边界对齐、端序单位正确、采集线程不被调度抖动打断。要不要我再补一段AWR1843点云TLV偏移表,或SocketCAN+雷达目标级融合的写法?



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭