4D毫米波雷达—赛恩领动SINPRO-SFR-2K

最近4D毫米波雷达的产品化应用越来越广泛,多家自动驾驶、辅助驾驶的产品开始量产装车4D Radar,由于它价格低廉(千元左右),探测距离达到200米+,相比激光雷达能穿透烟尘,可以覆盖大雾、雪天等场景,甚至可以探测到视觉和激光因遮挡看不到的车辆和障碍物,随着技术的进一步发展迭代,未来有代替激光雷达的趋势,因此本文将对4D毫米波进行初步的研究,看看点云的输出密度和准确度上跟激光雷达有多大差异。

一、概述

1. 4D Radar的技术特点

我们以一个“夜间+大雾”场景来说明4D毫米波的技术优势。

  • 摄像头依赖光线,在夜里+大雾等能见度低的场景下,图像可能模糊、对比差、细节缺失;
  • 激光雷达也可能受到雾、雨、雪、水滴、雪花、粉尘等散射、反射、吸收的影响,导致点云质量下降。

因此传统以视觉(摄像头)+激光雷达为主的感知方案,有其局限性。

相比之下,毫米波雷达的波长更长对雨、雾、灰尘、水滴等的穿透性较强,不容易受到光照和能见度的影响。尤其是4D毫米波雷达,即便在雾、夜等低能见度条件下,仍能有效探测周围物体,并且具备了类似激光雷达的立体(3D+高度)感知能力,因此被视为一种“全天候/全时段感知传感器。

2. 4D Radar的局限性

2.1 点云稀疏&分辨率/细节有限

即便是4D毫米波雷达,其点云数量/密度/分辨率与高线束、高分辨率的激光雷达相比,仍然有一定差距。像是在多车并道、小车距离很近、障碍物形态复杂(栏杆、路缘、交通锥、行人、小型电动车…)复杂场景4D毫米波雷达可能只能检测到一个“点”或很少几个反射点,难以准确判断物体的形状、边界、尺寸、类别(是车、人、栏杆还是树?)

2.2 点云“噪声+稀疏+不确定性”问题

雷达波反射可能因地面、湿度、水滴、雾滴、建筑反射、地面铺装、其他车辆金属结构、雨雪、环境杂散波干扰等产生噪声4D毫米波雷达点云本来就比激光雷达稀疏,遇到复杂/静态/低反射目标(比如黑色物体、空气中轻微雾滴、透明物体…)时可能根本没有回波或回波太弱。这样的不确定性使得仅靠4D毫米波雷达判断路况显得不够可靠。

4D radar在低速场景可结合摄像头进行感知,在高速场景可辅助激光雷达探测遮挡障碍物、穿透雾、雪等场景。

3. SFR-2K技术参数

本文以赛恩领动SFR-2K为例,进行技术验证。赛恩领动的4D radar是一款车规级成像雷达,拥有120°水平视场角,最长探测距离300m,可以全天候全工况提供探测物体的距离、速度、角度以及高度等信息。

具体技术参数如下:

视觉遮挡区域的障碍物探测能力:

二、准备工作

1. 雷达连线

红黑线接12V供电,黄绿CAN线不用接,网络线这里通过转换盒子转为网口接PC。

2. 网络配置

SINPRO-SFR-2K出厂默认IP为192.168.3.10,我们这里把本机及网关配置到192.168.3网段:

网络配置完毕后可以ping通4d radar:

tcpdump抓包,可以看到4d radar在广播数据:

三、雷达调试

1. SFR-2K通信协议

赛恩领动官方没有提供driver和demo程序,只有通信报文协议定义。

SFR-2K的对外报文共有6种类型:1点云、2目标、3障碍物、4系统信息、7日志、8Dump,主要使用前4种。

传输协议使用UDP,报文头48bytes:

Payload根据报文类型区分,有不同的包大小和解析协议:

雷达报文发送周期15hz,默认发包顺序如下:(可能会丢包、乱序)

2. 驱动编写

我们这里根据协议定义编写driver,并将点云输出到topic,以用于可视化。

通信:接收radar的udp组播数据

bool RadarDriver::connect() {
    int _socket_recv = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (_socket_recv < 0) {
        std::cout << " [SOCKET] Init send socket failed" << std::endl;
        return false;
    }
    int reuse_mode = 1;
    if (setsockopt(_socket_recv, SOL_SOCKET, SO_REUSEPORT, &reuse_mode, sizeof(reuse_mode))) {
        std::cout << " [SOCKET] set REUSEPORT failed." << std::endl;
        close(_socket_recv);
        return false;
    }

    sockaddr_in dst_addr;  // radar information
    memset(&dst_addr, 0, sizeof(dst_addr));
    dst_addr.sin_family = AF_INET;
    dst_addr.sin_addr.s_addr = inet_addr("192.168.3.10");
    dst_addr.sin_port = htons(11011);

    sockaddr_in local_addr;  // driver information
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = INADDR_ANY;  // inet_addr("192.168.3.100");
    local_addr.sin_port = htons(11011);
    // send
    if (bind(_socket_recv, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) {
        std::cout << " [SOCKET] bind local address error" << std::endl;
        return false;
    }
    // add multicast group
    struct ip_mreq multicast_group;
    multicast_group.imr_multiaddr.s_addr = inet_addr("239.168.3.1");  // 组播ip
    multicast_group.imr_interface.s_addr = htonl(INADDR_ANY);         // inet_addr("192.168.3.100");  // 本机ip

    if (setsockopt(_socket_recv, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&multicast_group, sizeof(multicast_group)) < 0) {
        std::cout << " [SOCKET] Adding multicast group failed, error: " << strerror(errno) << std::endl;
        close(_socket_recv);
        return false;
    }
    std::cout << " [SOCKET] init recv socket successfully" << std::endl;
}
bool RadarDriver::recive() {
    // 接收并打印数据
    struct sockaddr_in multicastAddr;
    char buffer[65536];
    while (true)
    {
      socklen_t addrLen = sizeof(multicastAddr);
      ssize_t recvLen = recvfrom(_socket_recv, buffer, sizeof(buffer), 0 , (struct sockaddr *)&multicastAddr, &addrLen);
      if (recvLen < 0){
        std::cout << " [SOCKET] recvfrom failed" << std::endl;
        return false;
    }

      buffer[recvLen] = '\0';
      std::cout << " [SOCKET] Receive multicast message: " << buffer << std::endl;
    }

    return true;
}

解析:参考协议解析udp包header,然后直接memcpy到对应结构体即可,这里不再赘述。

主程序:接收并发送点云topic

int main(int argc, char **argv) {
    ros::init(argc, argv, "sinpro_sfr_2k-node");
    ros::NodeHandle nh;
    ros::Publisher pub = nh.advertise<sensor_msgs::PointCloud2>("/sensor/sinpro_sfr_2k/points", 1);

    // init radar udp multicast
    std::shared_ptr<RadarDriver> _driver;
    if (!_driver->init()) {
        std::cout << " [INIT] RadarDriver Init Failed" << std::endl;
        return;
    }
    std::cout << " [INIT] RadarDriver Init Success. Port: " << _driver->get_port() << std::endl;

    // start recive data
    while (ros::ok()) {
        if (!_driver->receive()) {
            std::cout << " not recive data!" << std::endl;
            continue;
        }

        if (_driver->get_data()->pointcloud_size() > 0) {
            std::cout << "[DATA] recive pointcloud size " << _driver->get_data()->pointcloud_size() << " recive object_num " << object_num << " recive obstacle_num " << obstacle_num << std::endl;

            // 输出点云到topic
            pcl::PointCloud<pcl::PointXYZ> cloud;
            for (int i = 0; i < _driver->get_data()->pointcloud_size(); ++i) {
                auto point = _driver->get_data()->pointcloud(i);
                if (point.rng_m() < 0 || point.rng_m() > 300){
                    std::cout << " point rng_m out rang: " << point.rng_m() << std::endl;
                    continue;
                }
                // 4D毫米波径向距离、方位角、俯仰角,转换为ros点云x,y,z坐标
                float x = point.rng_m() * cos(point.ele_rad()) * cos(point.azi_rad());
                float y = point.rng_m() * cos(point.ele_rad()) * sin(point.azi_rad());
                float z = point.rng_m() * sin(point.ele_rad());
                cloud.points.push_back(pcl::PointXYZ(x, y, z));
            }
            sensor_msgs::PointCloud2 msg;
            pcl::toROSMsg(cloud, msg);
            msg.header.stamp = ros::Time::now();
            msg.header.frame_id = "base_link";
            pub.publish(msg);
        }
    }
    _driver->close();

    ros::AsyncSpinner spinner(1);
    spinner.start();
    ros::waitForShutdown();
}

3. 点云可视化

这里从俯视图可以看到点云密度还是很稀疏的,3D立体图上看点云更加稀疏,跟16线的激光雷达还是完全没法比的。

结论:作为主传感器探测信息不够,作为辅助传感器是可行的。

 

yan 25.12.11

 

参考:

赛恩领动

发表评论

您的电子邮箱地址不会被公开。