开发者手册

主要包含【开发者上手】、【API案例教学】及【API参考手册】三块内容。

开发者上手

1. 关于

SimOne 是 51SIM 自主研发的一款集 静态和动态数据导入、测试场景案例编辑、传感器仿真、动力学仿真、可视化、测试与回放、虚拟数据集生成 等一体化的自动驾驶仿真与测试平台。平台提供了多种类型和语言的 API 接口实现外部算法系统与仿真平台的通讯机制,可以满足 L2/L3/L4 算法的测试与训练。仿真平台基本实现全模块开放性,可以支持 感知、融合、决策、规划及控制算法 的部分开环或整体闭环测试,主要应用场景如下:

  • 感知算法 + 仿真平台开环 :满足目标识别和预测的测试,可拓展支持多传感器分布式及 HIL

  • 融合算法 + 仿真平台开环 :通过获取单传感器目标级真值开展感知融合算法的测试和训练

  • 决策规划控制算法 + 仿真平台开环 :跳过感知融合模块,利用多传感器融合后目标级真值开展相关算法的测试,可拓展支持无 GPU 的云端大规模部署和并发运行

  • 感知融合决策规划控制算法 + 仿真平台闭环 :完整链路的闭环测试,可拓展整车在环 VIL

2. API 概览

2.1 多语言与框架技术接口

类别 API 接口 描述
语言支持 C++ 为使用 C++开发的项目提供接口支持。
Python 提供 Python 语言的接口支持,方便进行快速开发和原型制作。
运行控制 Restful API 提供基于 HTTP 的 Restful API,支持 Web 服务接口,控制 Simone 界面的运行流程,比如可控制创建案例库,导入导出案例,运行停止案例等。
API + 第三方中间件 Simulink 提供 Simulink 接口,适用于模拟和模型基础的设计。
ROS1/2 支持 ROS1/2 框架,便于机器人操作系统中的应用开发。

2.2 功能支持

注意

下方链接主要为各功能 API 详解,具体可查看 API 功能支持

如需查看 API 汇总列表,具体可查看 C++/Python 接口语言支持

API 类型 API 接口 功能
1. 基础服务类
主要提供车辆选择、仿真工作模式设置和热区数据获取的功能。
ServiceAPI 选择车辆: 选择具体的目标车辆进行控制,并订阅其状态更新
设置仿真工作模式: 根据需要选择帧同步(保证实时性和稳定性)或非帧同步(提高运行效率)模式
获取热区数据:
通过主动 API 调用或自动回调函数获取车辆及其周边环境的实时数据
2. 传感器类
为开发者提供了从 SimOne 仿真环境中获取各种传感器数据的能力。
SensorAPI 获取目标级或物理级信息: 包括图像信息、激光雷达点云、毫米波雷达及超声波雷达目标级信息等
获取传感器真值数据: 既能满足感知算法接入测试,也能满足跳过感知,直接从决策算法接入的开环测试需求
环境信息配置与管理 :涉及获取和设置与仿真环境相关信息(如天气、光照和地面条件等),对于创建特定测试场景非常关键。
StreamingAPI 获取物理级传感器流式传输 :实时获取和自动回调图像及点云数据,支持多种格式。
V2XAPI V2X 消息处理 :获取特定车辆 UPER 编码的 V2X 消息及更新通知。
3. 控制通信类
通过控制信号输入驱动被测车辆运行,实现复杂交通场景模拟。
PNCAPI 车辆状态与初始化 :涵盖选择测试车辆、初始化状态信息、设置起始位置和重置车辆状态的操作。
预警信息与控制策略 :包括设置和接收预警信息、控制车辆动作,以及规划控制输出的必要接口,确保测试车辆按照算 法进行动态响应。
4. 高精地图运行时类
为决策算法提供厘米级高精度地图信息,包括路网和交通元素,支持包括路径规划和定位在内的 多种 API 调用。
HDMapAPI 地图与车道分析 :提供高精地图加载及车道详细信息查询,强化定位和路由能力。
环境识别与判断 :集成交通灯、标志、停车位等环境要素的识别,辅助决策及判断。
5. 评价算法类
获取用户自定义评价功能所需要的基本仿真数据以及评价需要的用户规控算法内部相关信号。
EvaluationAPI 存取评价数据 :存取用户自定义的评价功能所需的数据,用于用户自定义的评价算法。

2.3 API 调用示例

注意

[SimOne-安装目录]/SimOne/SimOneAPI 中的范例代码根据目录分类,演示了 SimOne 仿真产品的各类 API 在客户本地算法程序中的应用。

下方链接主要为 API调用参考示例,具体可查看 API调用参考示例

示例 文件夹 描述 子文件夹 描述
算法示例 ADAS ADAS 基础算法对接 SimOne 仿真平台接口应用示例。 ACC 自适应巡航控制算法示例。
AEB 自动紧急制动算法示例。
AEB-Daemon 云仿真环境连续案例运行 AEB 算法示例。
AEB-Evaluation 以 AEB 算法为例,展示如何在用户算法内输出评价所需要的信号数据。
AVP 自动泊车算法示例。
bin ADAS 算法应用程序生成目录。
Build 用于存放构建和编译项目产生的文件目录。
LKA 自动车道保持巡航算法示例。
TestEvaluation 用于测试和示范如何利用 EvaluationAPI 获取评价所需要的数据。
TrajectoryControl 控制车辆行驶轨迹的系统或算法。
util 包含一系列辅助工具和实用程序的目录。
Autopilot 自动驾驶算法综合 CurveSample 全局路径规划和局部路径调整示例
LimitChangeLaneSample 前方有障碍物示例
TrafficLightSample 获取场景中交通灯的相位状态示例
include 包含 SimOne 自带的库和第三方的调用的依赖库文件,主要包括一些 .h 和 .hpp 。
lib 包含 运行 SimOne 需要依赖的动态库,C++API 的头文件、数据结构文件,PythonAPI 的头文件、数据结构文件,PythonAPI 的算法示例。
适配第三方中间件 Cyber Apollo(r6.0.0)对接 SimOne 仿真平台基于 Cyber 中间件的接口示例。
Matlab SimOneAPI 在 Simulink 中的封装,包含模块接口和示例。
ROS 对接 SimOne 仿真平台基于 ROS1 中间件的接口示例。
ROS2 对接 SimOne 仿真平台基于 ROS2 中间件的接口示例。
SensorRaw 物理级数据可视化接口示例。 3rdparty 第三方插件 opencv,pcl
SensorCamera 物理级摄像头数据传输示例
SensorLidar 物理级激光雷达数据传输示例
SensorLidarROS 物理级激光雷达数据传输至 ROS 示例
SensorRadar4D 4D 毫米波雷达数据传输示例
功能模块示例 Tutorial SimOneAPI C++ 接口基础调用方法示例。 Dynamics 动力学 使用示例
HDMap HDMapAPI 使用示例
PNC PNCAPI 使用示例
Sensor 传感器 使用示例
Traffic 交通流 API 使用示例
V2X V2X 使用示例

3. 技术架构

3.1 技术架构图

3.2 自动驾驶算法联调的基本流程

以 Apollo 为例,可以通过设计一个 bridge 程序 CybertronBridgeApollo ,控制 Apollo 算法的启停,自动设置部分 Apollo 参数,结合 SimOne 案例集,达到 自动化测试 的目的。

CybertronBridgeApollo 桥接程序的主要工作包括两部分: 准备加载的信息 实时传递的数据。

  1. 控制流

    • 在案例运行之前,必须加载某些信息,例如 车辆的具体参数、相机配置参数、地图 等。这类信息随着案例的不同或主车设置的变化而变化,但在案例运行过程中则保持不变。

    • 这类信息被称作“控制流”,它们需要在案例启动之前预先设置好并传递给 Apollo。

  2. 数据流

    • 案例运行时会实时产生另一些数据,例如 GPS 信息、主车底盘信息、图像及点云数据

    • 这类信息被称作“数据流”,需要不断实时地传递给 Apollo 算法进行处理。

通过这种方式, CybertronBridgeApollo 能够确保 Apollo 自动驾驶平台在测试案例运行时接收到所需的所有必要信息和实时数据,以确保正确地执行自动化测试。具体实现流程如下:

3.3 SimOne 支持的算法联调场景

3.3.1 只接入决策规划

  • 示例伪代码: C++

// 主车Id
const char* mv_id = "0";
// 是否加入帧同步
bool isJoinTimeLoop = false;
// BridgeIO 服务 Ip
    const char* serverIP = "127.0.0.1";
// 初始化 SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);

// 回调方式获取底盘等gps数据
if (IsCallBackMode)
{
            auto function = [](const char* mainVehicleId, SimOne_Data_Gps *pGps){
                            output_gps(pGps);
            };
            SetGpsUpdateCB(function);
    }
// 非帧同步方式获取底盘等gps数据
    else
{
            std::unique_ptr<SimOne_Data_Gps> pGps = std::make_unique<SimOne_Data_Gps>();
            int lastFrame = 0;
            while(true)
            {
                    bool flag = GetGps(mv_id, pGps.get());
                    if (flag && pGps->frame != lastFrame)
                    {
                            lastFrame  = pGps->frame;
                            output_gps(pGps.get());
                    }
                    if (!flag)
                    {
                            std::cout<<"Get GPS Fail"<< std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
    }

// 获取案例结束状态
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
    // 关闭 SimOneAPI
    if (!SimOneAPI::TerminateSimOneAPI())
    {
        std::cout << "TerminateSimOneAPI Failed!" << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}

// GPS 数据:
void output_gps(SimOne_Data_Gps* pData)
{
    std::cout<<"frame:"<< pData->frame << std::endl;
    std::cout << "posX/Y/Z: [" << pData->posX << ", " << pData->posY << ", " << pData->posZ << "]" << std::endl;
    std::cout << "oriX/Y/Z: [" << pData->oriX << ", " << pData->oriY << ", " << pData->oriZ << "]" << std::endl;
    std::cout << "velX/Y/Z: [" << pData->velX << ", " << pData->velY << ", " << pData->velZ << "]" << std::endl;
    std::cout << "throttle: " << pData->throttle << std::endl;
    std::cout << "brake: " << pData->brake << std::endl;
    std::cout << "steering: " << pData->steering << std::endl;
    std::cout << "gear: " << pData->gear << std::endl;
    std::cout << "accelX/Y/Z: " << pData->accelX << ", "  << pData->accelY << ", " << pData->accelZ << "]" << std::endl;
    std::cout << "angVelX/Y/Z: " << pData->angVelX << ", "  << pData->angVelY << ", " << pData->angVelZ << "]" << std::endl;
    std::cout << "wheelSpeedFL: " << pData->wheelSpeedFL << std::endl;
    std::cout << "wheelSpeedFR: " << pData->wheelSpeedFR << std::endl;
    std::cout << "wheelSpeedRL: " << pData->wheelSpeedRL << std::endl;
    std::cout << "wheelSpeedRR: " << pData->wheelSpeedRR << std::endl;
    std::cout << "engineRpm: " << pData->engineRpm << std::endl;
    std::cout << "odometer: " << pData->odometer << std::endl;
}

// 调用第三方决策控制算法,通过获取到的数据去计算生成control,pose
{
    // 方式一:通过设置位置点移动主车(无动力学)
    std::unique_ptr<SimOne_Data_Pose_Control> pPose = std::make_unique<SimOne_Data_Pose_Control>();
            [](pPose.get())
    {
        // 生成主车轨迹点,Eg:
        // Position X on Opendrive (by meter)
        pPose->posX = m_gps.posX + cos(m_gps.oriZ); // 基于主车当前位置 X 方向移动一米
        // Position Y on Opendrive (by meter)
        pPose->posY = m_gps.posY + sin(m_gps.oriZ);
        // Position Z on Opendrive (by meter)
        pPose->posZ = m_gps.posZ;
        // Rotation X on Opendrive (by radian)
        pPose->oriX = m_gps.oriX;
        // Rotation Y on Opendrive (by radian)
        pPose->oriY = m_gps.oriY;
        // Rotation Z on Opendrive (by radian)
        pPose->oriZ = m_gps.oriZ;
        // Automatically set Z according to scene
        pPose->autoZ = false;
            };

    // 方式二:通过油门、刹车、方向消息驱动主车(有动力学)
    std::unique_ptr<SimOne_Data_Control> pCtrl = std::make_unique<SimOne_Data_Control>();
    [](pCtrl.get())
    {
        // 生成控制消息,Eg:
        pCtrl->timestamp = getCurrentTime(); // uint64  时间戳,单位us
        pCtrl->throttleMode = ESimOne_Throttle_Mode::ESimOne_Throttle_Mode_Speed; // vehicle speed, m/s,   in this mode, brake input is ignored
        pCtrl->throttle = 10; // m/s  double 油门开度 0-100。100表示最大油门驱动
        pCtrl->steeringMode = ESimOne_Steering_Mode::ESimOne_Steering_Mode_SteeringWheelAngle; // steering wheel angle, degree
        pCtrl->steering = 0;
        pCtrl->isManualGear = false;
        pCtrl->gear = ESimOne_Gear_Mode::ESimOne_Gear_Mode_Drive; // forward gear for automatic gear
    }

    // 方式三:通过规划轨迹点驱动主车(有动力学)
    std::unique_ptr<SimOne_Data_Control_Trajectory> pTraj = std::make_unique<SimOne_Data_Control_Trajectory>();
    [](pTraj.get())
    {
        // 生成规划轨迹,Eg:
        float posx = m_gps.posX; // position x
        float posy = m_gps.posY; // position y
        float speed = 10; // m/s
        float accel = 1; // accelelation m/s^2
        float theta = m_gps.oriZ; // yaw   rad
        float kappa = 0; // curvature
        float relative_time = 0; // time relative to the first trajectory point
        float s = 0; // distance from the first trajectory point
        pTraj->point_num = 10;
        for (int i = 0; i < pTraj->point_num; i++)
        {
            pTraj->points[i].posx = posx;
            pTraj->points[i].posy = posy;
            pTraj->points[i].speed = speed;
            pTraj->points[i].accel = accel;
            pTraj->points[i].theta = theta;
            pTraj->points[i].kappa = kappa;
            pTraj->points[i].relative_time = relative_time;
            pTraj->points[i].s = s;
            posx = posx + cos(theta);
            posy = posy + sin(theta);
            relative_time += 1;
            s += 1;
        }
        pTraj->isReverse = false;
    }
}

/* 控制方式一:设置主车位置 API
 * input param:
 *     mainVehicleId: Vehilcle index, configure order of web UI, starts from 0
 *     pPose: Pose to set
 * return: Success or not
*/
if (!SimOneAPI::SetPose(0, &pose_ctl))
{
  std::cout << "Set Pose failed!" << std::endl;
}

/* 控制方式二:主车控制 (通过油门、刹车、方向等消息驱动主车(有动力学),控制参数由算法端提供)
     * input param:
     *     mainVehicleId: Vehilcle index, configure order of web UI, starts from 0
     *     pControl: vehicle control data
     * return: Success or not
     */
if (!SetDrive(0, pCtrl.get()))
{
  std::cout << "SetDrive Failed!" << std::endl;
}

/* 控制方式三:主车控制 (通过规划轨迹点驱动主车(有动力学),不可同时使用SetDrive)
      * input param:
      *     mainVehicleId: Vehilcle index, configure order of web UI, starts from 0
      *     pControlTrajectory: vehicle planning trajectory
      * return: Success or not
      */
if (!SetDriveTrajectory("0", pTraj.get()))
{
  std::cout << "SetDrive Failed!" << std::endl;
}
3.3.2 感知算法训练

  • 示例伪代码: C++

// 主车Id
const char* mv_id = "0";
// 是否加入帧同步
bool isJoinTimeLoop = false;
// BridgeIO 服务 Ip
    const char* serverIP = "10.66.9.194";
// 初始化 SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);

// 回调方式获取真值数据
    if (IsCallBackMode)
{
            auto function = [](const char* mainVehicleId, SimOne_Data_Obstacle *pObstacle) {
                    output_ground_truth(pObstacle);
            };
            SetGroundTruthUpdateCB(function);
    }
// 非帧同步方式获取真值数据
    else {
            std::unique_ptr<SimOne_Data_Obstacle> pObstacle = std::make_unique<SimOne_Data_Obstacle>();
            int lastFrame = 0;
            while (true) {
                    bool flag = GetGroundTruth(mv_id,  pObstacle.get());
                    if (flag && pObstacle->frame != lastFrame)
                    {
                            lastFrame  = pObstacle->frame;
                            output_ground_truth(pObstacle.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetGroundTruth Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
    }

// 真值数据:
void output_ground_truth(SimOne_Data_Obstacle* pObstacle)
{
    std::cout <<"frame:"<< pObstacle->frame << std::endl;
        std::cout << "obstacleSize: " << pObstacle->obstacleSize << std::endl;
        for (int i=0; i<pObstacle->obstacleSize ; i++)
        {
            std::cout << "obstacle[" << i << "].id: " << pObstacle->obstacle[i].id << std::endl;
            std::cout << "obstacle[" << i << "].viewId: " << pObstacle->obstacle[i].viewId << std::endl;
            std::cout << "obstacle[" << i << "].type: " << pObstacle->obstacle[i].type << std::endl;
            std::cout << "obstacle[" << i << "].theta: " << pObstacle->obstacle[i].theta << std::endl;
            std::cout << "obstacle[" << i << "].posX/Y/Z: [" << pObstacle->obstacle[i].posX << ", " << pObstacle->obstacle[i].posY << ", " << pObstacle->obstacle[i].posZ << "]" << std::endl;
            std::cout << "obstacle[" << i << "].oriX/Y/Z: [" << pObstacle->obstacle[i].oriX << ", " << pObstacle->obstacle[i].oriY << ", " << pObstacle->obstacle[i].oriZ << "]" << std::endl;
            std::cout << "obstacle[" << i << "].velX/Y/Z: [" << pObstacle->obstacle[i].velX << ", " << pObstacle->obstacle[i].velY << ", " << pObstacle->obstacle[i].velZ << "]" << std::endl;
            std::cout << "obstacle[" << i << "].length: " << pObstacle->obstacle[i].length << std::endl;
            std::cout << "obstacle[" << i << "].width: " << pObstacle->obstacle[i].width << std::endl;
            std::cout << "obstacle[" << i << "].height: " << pObstacle->obstacle[i].height << std::endl;
            std::cout << "obstacle[" << i << "].accelX/Y/Z: [" << pObstacle->obstacle[i].accelX << ", " << pObstacle->obstacle[i].accelY << ", " << pObstacle->obstacle[i].accelZ << "]" << std::endl;
        }
}

// 获取案例结束状态
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
    // 关闭 SimOneAPI
    if (!SimOneAPI::TerminateSimOneAPI())
    {
        std::cout << "TerminateSimOneAPI Failed!" << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}

// 摄像头节点 udp server ip
const char* img_ip = "127.0.0.1";
// 摄像头节点 udp server port
unsigned short img_port = 123456;

// 回调方式获取摄像头传感器物理级数据
    if (IsCallBackMode)
{
            auto function = [](SimOne_Streaming_Image* pImage) {
                    output_image(pImage);
            };
            SetStreamingImageUpdateCB(img_ip, img_port, function);
    }
// 非帧同步方式获取摄像头传感器物理级数据
    else
{
            std::unique_ptr<SimOne_Streaming_Image> pImage= std::make_unique<SimOne_Streaming_Image>();
            int lastFrame = 0;
            while (true)
    {
        bool flag = GetStreamingImage(img_ip, img_port, pImage.get());
                    if (flag && pImage->frame != lastFrame)
                    {
                            lastFrame  = pImage->frame;
                            output_image(pImage.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetStreamingImage Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
    }

// 图像数据:
void output_image(SimOne_Streaming_Image* pImage)
{
    if (pImage->width != 0 && pImage->height != 0)
    {
        std::cout << "frame: " << pImage->frame << std::endl;
        std::cout << "width: " << pImage->width << std::endl; // int Image resolution width 1920 max
        std::cout << "height: " << pImage->height << std::endl; // int Image resolution height 1080 max
        std::cout << "imageDataSize: " << pImage->imageDataSize << std::endl; // 1920 x 1080 x 3 max
        std::cout << "imageData: " << pImage->imageData << std::endl;
    }
}

// 激光雷达节点 udp server ip
const char* pcd_ip = "127.0.0.1";
// 激光雷达节点 udp server port
unsigned short pcd_port = 123456;
// 激光雷达节点 udp server info_port
unsigned short pcd_info_port = 654321;

// 回调方式获取激光雷达传感器物理级数据
    if (IsCallBackMode)
{
            auto function = [](SimOne_Streaming_Point_Cloud* pPointcloud) {
                    output_point_cloud(pPointcloud);
            };
    SetStreamingPointCloudUpdateCB(pcd_ip, pcd_port, pcd_info_port, function);
    }
// 非帧同步方式获取激光雷达传感器物理级数据
    else
{
            std::unique_ptr<SimOne_Streaming_Point_Cloud> pPointCloud = std::make_unique<SimOne_Streaming_Point_Cloud>();
            int lastFrame = 0;
            while (true) {
        bool flag = GetStreamingPointCloud(pcd_ip, pcd_port, pcd_info_port, pPointCloud.get());
                    if (flag && pPointCloud->frame != lastFrame)
                    {
                            lastFrame  = pPointCloud->frame;
                        output_point_cloud(pPointcloud.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetStreamingPointCloud Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(1));
            }
    }

// 点云数据:
static std::string sNames[] = {"x", "y", "z", "intensity"};
static int sOffsets[] = {0, 4, 8, 12};
static int sDatatypes[] = {7, 7, 7, 7};
void output_point_cloud(SimOne_Streaming_Point_Cloud* pPointcloud)
{
    std::cout << "frame: " << pPointcloud->frame << std::endl; // sequence number long long
    std::cout << "pointStep: " << pPointcloud->pointStep << std::endl; // int
    std::cout << "height: " << pPointcloud->height << std::endl; // int
    std::cout << "width: " << pPointcloud->width << std::endl; // int
}

// 调用第三方感知算法函数, 对真值数据、物理集数据 进行感知训练
[](pObstacle, pImage, pPointCloud)
{
    // 感知训练
}
3.3.3 融合算法训练

  • 示例伪代码: C++

// 主车Id
const char* mv_id = "0";
// 是否加入帧同步
bool isJoinTimeLoop = false;
// BridgeIO 服务 Ip
    const char* serverIP = "10.66.9.194";
// 初始化 SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);

// 回调方式获得所有超声波雷达信息
    if (IsCallBackMode)
{
            auto function = [](const char* mainVehicleId, SimOne_Data_UltrasonicRadars* pUltrasonics)
            {
                    output_ultrasonic_radars(pUltrasonics);
            };
            SetUltrasonicRadarsCB(function);
    }
// 非帧同步方式获得所有超声波雷达信息
    else
    {
            std::unique_ptr<SimOne_Data_UltrasonicRadars> pDetections = std::make_unique<SimOne_Data_UltrasonicRadars>();
            int lastFrame = 0;
            while (true)
            {
                    bool flag = GetUltrasonicRadars(mv_id, pDetections.get());
                    if (flag && pDetections->frame != lastFrame)
                    {
                            lastFrame  = pDetections->frame;
                            output_ultrasonic_radars(pDetections.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetUltrasonicRadars Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
    }

// 超声波雷达数据
void output_ultrasonic_radars(SimOne_Data_UltrasonicRadars* pUltrasonicData)
{
        std::cout <<"ultrasonicRadarNum: " << pUltrasonicData->ultrasonicRadarNum << std::endl;
        for (int i = 0; i < pUltrasonicData->ultrasonicRadarNum; i++)
        {
        std::cout <<"frame:"<< pUltrasonicData->ultrasonicRadars[i].frame << std::endl;
            std::cout <<"sensorId:"<< pUltrasonicData->ultrasonicRadars[i].sensorId << std::endl;
            std::cout <<"obstacleNum:"<< pUltrasonicData->ultrasonicRadars[i].obstacleNum << std::endl;
            for (int j = 0; j < pUltrasonicData->ultrasonicRadars[i].obstacleNum; j++)
            {
                    std::cout << "obstacleDetections[" << j << "].obstacleRanges: "<< pUltrasonicData->ultrasonicRadars[i].obstacleDetections[j].obstacleRanges << std::endl;
                    std::cout << "obstacleDetections[" << j << "].x: "<< pUltrasonicData->ultrasonicRadars[i].obstacleDetections[j].x << std::endl;
                    std::cout << "obstacleDetections[" << j << "].y: "<< pUltrasonicData->ultrasonicRadars[i].obstacleDetections[j].y << std::endl;
                    std::cout << "obstacleDetections[" << j << "].z: "<< pUltrasonicData->ultrasonicRadars[i].obstacleDetections[j].z << std::endl;
            }
        }
}

// 回调方式获得所有毫米波雷达信息
if (IsCallBackMode)
{
            auto function = [](const char* mainVehicleId, const char* sensorId, SimOne_Data_RadarDetection* pRadarData)
            {
                    output_radar_detection(pRadarData);
            };
            SetRadarDetectionsUpdateCB(function);
    }
// 非帧同步方式获得所有毫米波雷达信息
    else
    {
            std::unique_ptr<SimOne_Data_RadarDetection> pRadarData = std::make_unique<SimOne_Data_RadarDetection>();
            int lastFrame = 0;
            while (true)
            {
                    bool flag = GetRadarDetections(mv_id, "objectBasedRadar1", pRadarData.get());
                    if (flag && pRadarData->frame != lastFrame)
                    {
                            lastFrame  = pRadarData->frame;
                            output_radar_detection(pRadarData.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetRadarDetections Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(30));
            }
    }

// 毫米波雷达数据
void output_radar_detection(SimOne_Data_RadarDetection* pRadarData)
{
        std::cout<< "frame:" << pRadarData->frame << std::endl;
        std::cout<< "detectNum :" << pRadarData->detectNum << std::endl;
        for (int i = 0; i < pRadarData->detectNum; i++)
        {
                std::cout << "detections[" << i << "].ip: " << pRadarData->detections[i].id << std::endl;
                std::cout << "detections[" << i << "].subId: " << pRadarData->detections[i].subId << std::endl;
                std::cout << "detections[" << i << "].type: " << pRadarData->detections[i].type << std::endl;
                std::cout << "detections[" << i << "].posX/Y/Z: [" << pRadarData->detections[i].posX << ", " << pRadarData->detections[i].posY << ", " << pRadarData->detections[i].posZ << "]"<< std::endl;
                std::cout << "detections[" << i << "].velX/Y/Z: [" << pRadarData->detections[i].velX << ", " << pRadarData->detections[i].velY << ", " << pRadarData->detections[i].velZ << "]"<< std::endl;
                std::cout << "detections[" << i << "].accelX/Y/Z: [" << pRadarData->detections[i].accelX << ", " << pRadarData->detections[i].accelY << ", " << pRadarData->detections[i].accelZ << "]"<< std::endl;
                std::cout << "detections[" << i << "].oriX/Y/Z: [" << pRadarData->detections[i].oriX << ", " << pRadarData->detections[i].oriY << ", " << pRadarData->detections[i].oriZ << "]"<< std::endl;
                std::cout << "detections[" << i << "].length: " << pRadarData->detections[i].length << std::endl;
                std::cout << "detections[" << i << "].width: " << pRadarData->detections[i].width << std::endl;
                std::cout << "detections[" << i << "].height: " << pRadarData->detections[i].height << std::endl;
                std::cout << "detections[" << i << "].range: " << pRadarData->detections[i].range << std::endl;
                std::cout << "detections[" << i << "].rangeRate: " << pRadarData->detections[i].rangeRate << std::endl;
                std::cout << "detections[" << i << "].azimuth: " << pRadarData->detections[i].azimuth << std::endl;
                std::cout << "detections[" << i << "].vertical: " << pRadarData->detections[i].vertical << std::endl;
                std::cout << "detections[" << i << "].snrdb: " << pRadarData->detections[i].snrdb << std::endl;
                std::cout << "detections[" << i << "].rcsdb: " << pRadarData->detections[i].rcsdb << std::endl;
                std::cout << "detections[" << i << "].probability: " << pRadarData->detections[i].probability << std::endl;
        }
}

// 回调方式获取目标级传感器检测到的感知真值
if (IsCallBackMode)
    {
            auto function = [](const char* MainVehicleID, const char* sensorId, SimOne_Data_SensorDetections* pGroundtruth)
            {
                    output_sensor_detections(pGroundtruth);
            };
            SetSensorDetectionsUpdateCB(function);
    }
// 非帧同步方式获取目标级传感器检测到的感知真值
    else
    {
            std::unique_ptr<SimOne_Data_SensorDetections> pGroundtruth = std::make_unique<SimOne_Data_SensorDetections>();
            int lastFrame = 0;
            while (true)
            {
                    // "sensorFusion1" "objectBasedCamera1" "objectBasedLidar1" "perfectPerception1"
                    bool flag = GetSensorDetections(mainVehicleId.c_str(), "perfectPerception1", pGroundtruth.get());
                    if (flag && pGroundtruth->frame != lastFrame)
                    {
                            lastFrame = pGroundtruth->frame;
                            output_sensor_detections(pGroundtruth.get());
                    }
                    if (!flag)
                    {
                            std::cout << "GetSensorDetections Failed!" << std::endl;
                    }
                    std::this_thread::sleep_for(std::chrono::milliseconds(10));
            }
    }

// 目标极传感器真值数据
void output_sensor_detections(SimOne_Data_SensorDetections* pGroundtruth)
{
        std::cout << "frame:"<< pGroundtruth->frame << std::endl;
        std::cout << "objectSize: "<< pGroundtruth->objectSize << std::endl;
        for (int i = 0; i < pGroundtruth->objectSize; i++)
        {
        std::cout << "objects[" << i  << "].id" << pGroundtruth->objects[i].id << std::endl;
        std::cout << "obstacles[" << i << "].type: " << pGroundtruth->objects[i].type << std::endl;
        std::cout << "objects[" << i  << "].posX/Y/Z: " << "[" << pGroundtruth->objects[i].posX << ", " << pGroundtruth->objects[i].posY << ", " << pGroundtruth->objects[i].posZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].oriX/Y/Z: " << "[" << pGroundtruth->objects[i].oriX << ", " << pGroundtruth->objects[i].oriY << ", " << pGroundtruth->objects[i].oriZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].length: " << pGroundtruth->objects[i].length << std::endl;
        std::cout << "objects[" << i  << "].width: " << pGroundtruth->objects[i].width << std::endl;
        std::cout << "objects[" << i  << "].height: " << pGroundtruth->objects[i].height << std::endl;
        std::cout << "objects[" << i  << "].range: " << pGroundtruth->objects[i].range << std::endl;
        std::cout << "objects[" << i  << "].velX/Y/Z: " << "[" << pGroundtruth->objects[i].velX << ", " << pGroundtruth->objects[i].velY << ", " << pGroundtruth->objects[i].velZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].accelX/Y/Z: " << "[" << pGroundtruth->objects[i].accelX << ", " << pGroundtruth->objects[i].accelY << ", " << pGroundtruth->objects[i].accelZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].probability: " << pGroundtruth->objects[i].probability << std::endl;
        std::cout << "objects[" << i  << "].relativePosX/Y/Z: " << "[" << pGroundtruth->objects[i].relativePosX << ", " << pGroundtruth->objects[i].relativePosY << ", " << pGroundtruth->objects[i].relativePosZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].relativeRotX/Y/Z: " << "[" << pGroundtruth->objects[i].relativeRotX << ", " << pGroundtruth->objects[i].relativeRotY << ", " << pGroundtruth->objects[i].relativeRotZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].relativeVelX/Y/Z: " << "[" << pGroundtruth->objects[i].relativeVelX << ", " << pGroundtruth->objects[i].relativeVelY << ", " << pGroundtruth->objects[i].relativeVelZ << "]" << std::endl;
        std::cout << "objects[" << i  << "].bbox2dMinX: " << pGroundtruth->objects[i].bbox2dMinX  << std::endl;
        std::cout << "objects[" << i  << "].bbox2dMinY: " << pGroundtruth->objects[i].bbox2dMinY  << std::endl;
        std::cout << "objects[" << i  << "].bbox2dMaxX: " << pGroundtruth->objects[i].bbox2dMaxX  << std::endl;
        std::cout << "objects[" << i  << "].bbox2dMaxY: " << pGroundtruth->objects[i].bbox2dMaxY  << std::endl;
    }
}


// 调用第三方融合算法函数,对目标集数据进行融合处理
[](pUltrasonicData, pRadarData, pSensorData)
{
    // 融合处理
}

// 获取案例结束状态
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
    // 关闭 SimOneAPI
    if (!SimOneAPI::TerminateSimOneAPI())
    {
        std::cout << "TerminateSimOneAPI Failed!" << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
3.3.4 感知决策规划闭环

  • 示例伪代码: C++

// 主车Id
const char* mv_id = "0";
// 是否加入帧同步
bool isJoinTimeLoop = false;
// BridgeIO 服务 Ip
    const char* serverIP = "10.66.9.194";
// 初始化 SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);

// 调用第三方感知算法函数, 对真值数据、物理集数据 进行感知训练
perception_result = [](pObstacle, pImage, pPointCloud)
{
    // 感知训练
}

// 调用第三方融合算法函数,对目标集数据进行融合处理
fusion_result = [](perception_result)
{
    // 融合处理
}

// 调用第三方决策控制算法,通过获取到的数据去计算生成control,pose
{
    // 方式一:通过设置位置点移动主车(无动力学)
            [](fusion_result)
    {
        SimOne_Data_Pose_Control pose_ctl;
        ...
        SimOneAPI::SetPose(0, &pose_ctl))
            };

    // 方式二:通过油门、刹车、方向等消息驱动主车(有动力学)
    [](fusion_result)
    {
        SimOne_Data_Control ctrl;
        ...
        SetDrive(0, &ctrl);
    }

    // 方式三:通过规划轨迹点驱动主车(有动力学)
    [](pTraj.get())
    {
        SimOne_Data_Control_Trajectory traj;
        ...
        SetDriveTrajectory("0", &traj);
    }
}

// 获取案例结束状态
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
    // 关闭 SimOneAPI
    if (!SimOneAPI::TerminateSimOneAPI())
    {
        std::cout << "TerminateSimOneAPI Failed!" << std::endl;
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}

4. 附录 1:系统约定

4.1 坐标系统

对于高精度地图而言,系统提供两种坐标系统:

  1. 世界坐标系/站心直角坐标系(Local ENU) 世界坐标系为 x,y,z 右手坐标系

    惯例适用于地理参考,即对应站心直角坐标系,x 为正东(East,E),y 为正北(North,N),z 为 Up(U)。

  2. 参考线坐标系/轨道系统 s-t 坐标系(Track System s-t coordinate)

    路网运行时根据不同参考线基准分别定义了 2 个 s-t 坐标系:

    • 道路参考线 为基准定义 s-t 坐标系

    • 车道虚拟中心线 为基准定义 s-t 坐标系

4.1.1 空间直角坐标系

  • 坐标轴 :空间任意选定一点 O,过点 O 作三条互相垂直的数轴 Ox,Oy,Oz,它们都以 O 为原点且具有相同的长度单位。这三条轴分别称作 x 轴(横轴),y 轴(纵轴),z 轴(竖轴)。

  • 空间直角坐标系 O-xyz :它们的正方向 符合右手规则 ,即以右手握住 z 轴,当右手的四个手指 x 轴的正向以 90 度转向 y 轴正向时,大拇指的指向就是 z 轴的正向,这样就构成了一个空间直角坐标系。

  • 原点 :定点 O 称为该坐标系的原点。

与之相对应的是左手空间直角坐标系。一般在数学中更常用右手空间直角坐标系。

4.1.2 传感器坐标系

4.2 单位

类别 名称 英文名称/缩写 单位 描述/备注
物理量 长度 Length m 米,用来表示位置信息
角度 Angle rad 弧度,用来表示物体对于中心位置的偏移角度
速度 Speed m/s 米/秒,用来表示速度,加速度,角速度等
转速 RPM r/min 转/分钟,用来表示轮子转速,发动机转速等
控制参数 油门 Throttle 无单位 [0-1] 0 表示没有油门,1 表示油门最大
刹车 Brake 无单位 [0-1] 0 表示不踩刹车,1 表示刹车踩到底
方向盘 Steering 无单位 [-1,1] -1 表示左打 540°,1 表示右打 540°
方向盘度量 ESteeringMode 无单位 百分比,力矩,角度来表示方向盘的幅度
状态信息 手刹 Handbrake - true 或者 false,表示拉起和放下手刹
档位 EGearMode - 表示车辆的挡位状态,如 P 档,N 档,D 档等
目标物类型 SimOne_Obstacle_Type - 目标物的类型,如车辆、行人
交通灯状态 SimOne_TrafficLight_Status - 交通信号灯状态,如红灯、绿灯
信号数据 信噪比 SNR dB 分贝,信号强度比的度量单位
散射截面 RCS mdb 用来表示电磁波雷达截面散射面积
数据规格 点云格式 Point Step - 点云的数据规格,如 16 线,32 线
检测概率 Probability 无单位 [0-1] 预测模型输出的目标检测置信度
包围盒信息 bbox2d 坐标信息 用于描述对象在图像或空间中的覆盖范围

5. 附录 2:专业术语

5.1 帧同步与回调函数

SimOne 系统中的帧同步是基于虚拟时间的逻辑帧,这意味着整个系统的操作都是按帧进行的:

  1. 帧同步的概念:

    • 系统中的每个动作都依赖于逻辑帧的执行。

    • 一帧的执行时间在现实中可以很短(如 0.00001 秒)或很长(如 100000 秒),而与真实时间解耦。

    • 通过基于帧的时间控制,可以灵活地调节仿真系统的运行速度,例如加速或减缓案例运行。

  2. 获取 SimOne 数据的方法:

    • 回调函数 :当系统有新数据时,系统会通过注册的回调函数通知用户获取数据。

    • 主动调用 API :用户可以主动调用 API(如:GetGps)来获取当前帧的数据。如果系统帧没有进步,连续调用将返回相同的数据。

  3. 帧同步和数据获取的结合:

    • 使用帧同步 API,可控制 SimOne 系统案例的运行时间。在某个给定帧内的数据,无论调用多少次获取数据的 API,都将是相同的。

    • 如果不使用帧同步控制,直接调用 API 或回调函数获取数据的方式更为直接,适用于仅需获取场景数据的使用案例。

5.2 传感器仿真(目标级与物理级)

传感器在自动驾驶系统中的应用可以分为 目标级 物理级 两大类,它们分别服务于不同的应用场景,并通过特定的 API 激活方式来开始接收数据。以下是通过表格整理的内容概览:

传感器类型 激活 API
目标级传感器
获取目标对象的信息(如位置、速度等)
用于传感器融合算法
将 enable 参数设置为 true 开始接收数据 SIMONE_NET_API bool SetSensorObjectbasedDataEnable(bool enable);
物理级传感器
提供图像和点云等物理信息
用于测试和验证感知算法
将 enable 参数设置为 true 开始接收数据 SIMONE_NET_API bool SetSensorPhysicalbasedDataEnable(bool enable);

注意

额外说明

使用 UDP 数据注入 方法 获取物理级传感器数据 时, 不需要激活传感器的 API ,因为 UDP 注入会直接提供所需的数据。这一方法简化了数据获取过程,适用于物理信息的直接采集。

  • UDP :即用户数据报协议(User Datagram Protocol),是一种简单的网络通信协议,允许应用程序在不建立稳定连接的情况下发送数据包。


6. FAQ

参见 用户常见问题

API 案例教学

C++算法接入

注意

本教程以 AEB 算法为例进行介绍,别的算法也可使用本教程进行接入。

C++接口信息请先查看 C++_Python 接口语言支持

1. 文件定义

序号 文件(上图蓝框文件表示为 Windows) 解释
1 src 文件夹 放示例代码
2 CMakeLists.txt 使用 CMake 构建工具配置和生成项目构建系统的脚本
3/7 gen_vs_proj.bat /gen_make_debug.sh/gen_make_release.sh 生成算法工程的执行文件
4 build 文件夹 生成的算法工程文件夹
5/8 build_debug.bat /build_debug.sh/rebuild_debug.sh Windows /Linux 环境下(重新)生成 debug 可执行算法程序的执行文件
build_release.bat /build_release.sh/rebuild_release..sh Windows /Linux 环境下(重新)生成 release 可执行算法程序的执行文件
6 built_in_controller.bat /built_in_controller.sh Windows /Linux 环境下生成控制器的执行文件

2. 上手教程 Windows

2.1 环境准备

Visual Studio 2017、CMake

注意

Visual Studio 2017 安装资源 👉 vs_Community.exe ;

包含以下几个包即可👇

2.2 算法示例程序生成

注意

接入算法方式一:(点击下方跳转)

执行脚本生成工程和启动算法

注意

接入算法方式二:(点击下方跳转)

进入vs执行生成工程操作

2.2.1 接入算法方式一

注意

执行脚本生成工程和启动算法

2.2.1.1 生成工程目录

1.进入算法工程目录: 【SimOne-安装路径】/SimOne/SimOneAPI/ADAS/Build

注意

【SimOne-安装路径】/SimOne/SimOneAPI/Turial 也适用本教程。

2.鼠标左键双击执行 gen_vs_proj.bat 脚本,生成 build 目录。

2.2.1.2 生成可执行算法程序

1. 【SimOne-安装路径】/SimOne/SimOneAPI/ADAS/bin/Release 中有准备好的生成示例,可以进行查看。

注意

如果要生成新的算法程序可以按照后续步骤操作,会 新生成 exe 程序替换原有的 exe

也可以修改 Release 文件夹名称,则会 重新生成所有内容

2.鼠标左键双击执行 build_release.bat 脚本,生成可执行算法程序。

3.查看生成出来的可执行算法程序,位于 【SimOne-安装路径】/SimOne/SimOneAPl/lib/Release 目录中

2.2.1.3 为可执行算法程序添加依赖库

将生成的算法可执行程序拷贝至依赖库目录里面 【SimOne-安装路径】/SimOne/SimOneAPl/lib/Win64。

2.2.1.4 执行算法

点击任意一个算法示例即可执行。


2.2.2 接入算法方式二

注意

进入vs执行生成工程操作

2.2.2.1 生成算法工程

1.进入算法工程目录: 【SimOne-安装路径】/SimOne/SimOneAPI/ADAS/Build

注意

【SimOne-安装路径】/SimOne/SimOneAPI/Turial 也适用本教程。

2.鼠标左键双击执行 gen_vs_proj.bat 脚本,生成 build 目录。

3.生成算法 Visual Studio 工程: 【SimOne_安装路径】/SimOne/SimOneAPI/ADAS/Build/build/ADASSample.sln

2.2.2.2 编译

1.用 Visual Studio 2017 打开 ADASSample 工程,编译模式切换为 Release Debug

注意

Debug 模式会生成在 Debug 目录,Release 生成在 Release 目录

2.选择 ALL_BUILD 设为启动项目

3.可按照如下方式查看相关算法的示例,并自行进行修改。

4.可选择 ALL_BUILD 点击 生成 ,也可选择单独的算法(如 AEB) 点击 生成

注意

如果之前生成过可以点击 重新生成

5. 【SimOne-安装路径】/SimOne/SimOneAPI/ADAS/bin 文件夹下生成算法可执行文件 Release

2.2.2.3 为可执行算法程序添加依赖库(参考方式一)

将生成的算法可执行程序拷贝至依赖库目录里面 【SimOne-安装路径】/SimOne/SimOneAPl/lib/Win64。

2.2.2.4 执行算法(参考方式一)

点击任意一个算法示例即可执行。

2.3 用例编辑运行
2.3.1 创建用例
  1. 新建用例 ,选择 标准用例 ,填入 用例名称

2.3.2 编辑用例,加载算法主车
  1. 选择 地图 主车预设 ,可设置主车的 速度 为 10m/s。

  1. 拖入对手元素,尽量与主车保持一定距离,可设置其 速度 0 m/s ,然后点击 保存 用例。

2.3.3 运行用例,验证控制算法
  1. 点击 运行用例 ,将 默认控制器 自驾控制器 设置为 API 算法 ,然后点击 创建 ,运行用例。

  1. 进入用例之后用例仿真运行时间不会变化, 横纵向算法显示为 loading… ,此时用例在 等待接入算法状态

  1. 保证 AEB.exe 在用例运行前打开 ,若成功接入则在渲染视窗中会 展现算法效果 (例如 接入 AEB 算法后主车会在对手元素后一段距离减速至 0 m/s),且 横纵向算法 也会以此改变。

2.4 前端算法管理(可选)

可将不同的算法进行前端管理,方便调用,参见 软件在环测试


3. 上手教程 Ubuntu

注意

从源代码编译

Linux 安装包附随带有 API 使用示例: SimOneAPI.tar.gz

3.1 环境准备
  1. 准备好 C++库,用户需安装好 cmake 和 clang 编译器。

sudo apt-get install uuid-dev libx11-dev libxrandr-dev libsdl2-dev libx11-dev clang libc++-dev abi++-dev libc++1
  1. 添加环境变量 。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/SimOneApi库目录 (比如/SimOne/SimOneAPI/lib/Linux64)
3.2 生成算法工程
  1. 在 SimOne 的安装包中找到算法示例包 SimOneAPI.tar.gz

  1. 进入 SimOne 安装目录 /SimOne/ 执行 tar -xvf SimOneAPI.tar.gz 解压算法示例包。

  1. 进入 SimOne 安装目录中的 /SimOne/SimOneAPI/ADAS/Bulid ,执行命令 bash gen_make_release.sh 生成工程目录

  1. 在此目录再次执行 命令 bash rebuild_release.sh 命令 生成可执行文件 ,并在 /SimOne/ SimOneAPI/ADAS/bin 目录当中查看 可执行文件 AEB

  1. 添加 SimOneAPI 环境变量,需要根据安装位置改变。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/SimOneApi库目录 (比如/SimOne/SimOneAPI/lib/Linux64)

  1. 执行算法,如 ./AEB

3.3 创建案例
  1. 案例库 新建 文件夹 ,点击 新建案例

  1. 选择 标准案例 ,然后点击 下一步

  1. 输入 案例名称 ,点击 创建 案例。

  1. 点击 主车预设 ,拖入 API 控制主车 ,拖入视窗。

  1. 点击 保存 运行案例 创建任务

  1. 查看算法接入状态,接入 纵向横向控制器 都显示 AEB 证明算法已经被成功接入,此时控制台打印信息已经发生改变。

Python算法接入

1. 前言

本手册旨在指导开发人员如何将算法接入到SimOne当中。通过详细的步骤和示例,帮助开发人员快速上手并完成算法的集成工作。

注意

python接口信息请先查看 C++_Python 接口语言支持

2. 环境准备

2.1 解释器版本

本项目使用的 Python 解释器版本为 3.6.4。请确保你的环境中已经安装了该版本的 Python 解释器。

2.2 解释器位置

SimOne软件已经携带推荐解释器,解释器位于指定目录中,路径为 \SimOne\Tools\python36。

2.3 开发工具
  • IDE: PyCharm

3. 算法接入步骤

3.1 打开算法示例工程

3.2 执行算法示例

3.3 运行场景案例

3.4 查看接入状态

自动化创建和运行案例

1. 前提

2. 使用步骤

2.1 导入所有需要的依赖库

2.2 修改 API 连接路径与登录模式

2.3 运行 API 接入 SimOne
2.3.1 命令行执行
  1. 运行一个案例: python xxx.py --category_name='入门案例' --case_name='构建标准案例2.0'

  2. 运行一个案例并选择主车: python xxx.py --category_name='入门案例' --case_name='构建标准案例2.0' --vehicle_name='手动控制-默认'

  3. 运行案例库中所有的案例: python xxx.py --category_name='入门案例'

  4. 运行案例库中所有的案例并选择主车: python xxx.py --category_name='入门案例' --vehicle_name='手动控制-默认'

2.4 命令行输出结果

停车牌停车时间判定 Lua Sample(api 0.2)

1. 包资源

目前 Lua zip 包结构如下,(压缩 zip 包时确保顶级目录如上图所示,不要针对整个目录压缩),其中:

  • debug_server: 包含一些 lua 调试工具,可忽略。

  • lua_path :包含了需要一些第三方的 Lua 库

  • luac_path :包含了一些用 C 实现的 Lua 库,这些都可以由开发者自行扩展

  • main.lua :Lua 包的入口文件,请不要更改上述文件及目录名。

  • stop_sign.xodr :是一个包含停车标志的地图,这个 Lua 判定包要完成的功能就是判断车辆是否在停车牌 10 米范围内合法车道上停车了大于 3 秒的时间。

更详细的规则是:

在离开停车牌区域的时候,判断是否有过在区域内停车超过3秒,如果有,没事,如果没有,报错。

2. 代码注释

# 下方代码完成引用路径的设置,不用更改。

# 设置一些案例配置。

# on_init 函数会在案例载入时执行,完成初始化工作,目前只是检查 lua api 版本是否相符。

# on_loop 函数每一帧都会被调用,C++会将 当前车辆列表(vehicles),上一帧的车辆列表(pre_vehicles),主车 id(main_id) 都传入进来。

# 案例结束时调用,可以为空。

32 行 判断主车是否在标志牌区域内

36 行 获取当前是否是停止状态

37 行 设置了一个内置变量,值是 “处于停车牌内并且是停车状态”

38 行 stopped_time 值就是 维持 “处于停车牌内并且是停车状态” 变量为真的时间长度,也就是 在区域内停车了多久

42- 44 行 如果时间足够长,设置案例成功

46 - 47 行 检测”in_region” 是否由真变假了,也就是判断离开停车牌区域的时机。

48 - 54 行 如果离开的时候,案例成功了,就返回成功,否则返回失败。如果还 没离开区域,还不知道是否成功,则返回 simone.PENDING, 表示结果还未知。

API 参考手册

多语言与框架技术接口 API 功能支持 调用示例
C++/Python 接口语言支持
Restful API 运行控制
第三方中间件 Simulink
第三方中间件 ROS
基础服务类
传感器类
控制通信类
高精地图运行时类
评价算法类
算法示例
适配第三方中间件示例
功能模块示例

目录导航

1.1 多语言与框架技术接口

类别 API 接口 描述
语言支持 C++ 为使用 C++开发的项目提供接口支持。
Python 提供 Python 语言的接口支持,方便进行快速开发和原型制作。
运行控制 Restful API 提供基于 HTTP 的 Restful API,支持 Web 服务接口,控制 Simone 界面的运行流程,比如可控制创建案例库,导入导出案例,运行停止案例等。
API + 第三方中间件 Simulink 提供 Simulink 接口,适用于模拟和模型基础的设计。
ROS1/2 支持 ROS1/2 框架,便于机器人操作系统中的应用开发。

1.2 API 功能支持

注意

下方链接主要为各功能 API 详解,具体可查看 API 功能支持

如需查看 API 汇总列表,具体可查看 C++_Python 接口语言支持

API 类型 API 接口 功能
1. 基础服务类
主要提供车辆选择、仿真工作模式设置和热区数据获取的功能。
ServiceAPI 选择车辆: 选择具体的目标车辆进行控制,并订阅其状态更新
设置仿真工作模式: 根据需要选择帧同步(保证实时性和稳定性)或非帧同步(提高运行效率)模式
获取热区数据:
通过主动 API 调用或自动回调函数获取车辆及其周边环境的实时数据
2. 传感器类
为开发者提供了从 SimOne 仿真环境中获取各种传感器数据的能力。
SensorAPI 获取目标级或物理级信息: 包括图像信息、激光雷达点云、毫米波雷达及超声波雷达目标级信息等
获取传感器真值数据: 既能满足感知算法接入测试,也能满足跳过感知,直接从决策算法接入的开环测试需求
环境信息配置与管理 :涉及获取和设置与仿真环境相关信息(如天气、光照和地面条件等),对于创建特定测试场景非常关键。
StreamingAPI 获取物理级传感器流式传输 :实时获取和自动回调图像及点云数据,支持多种格式。
V2XAPI V2X 消息处理 :获取特定车辆 UPER 编码的 V2X 消息及更新通知。
3. 控制通信类
通过控制信号输入驱动被测车辆运行,实现复杂交通场景模拟。
PNCAPI 车辆状态与初始化 :涵盖选择测试车辆、初始化状态信息、设置起始位置和重置车辆状态的操作。
预警信息与控制策略 :包括设置和接收预警信息、控制车辆动作,以及规划控制输出的必要接口,确保测试车辆按照算 法进行动态响应。
4. 高精地图运行时类
为决策算法提供厘米级高精度地图信息,包括路网和交通元素,支持包括路径规划和定位在内的 多种 API 调用。
HDMapAPI 地图与车道分析 :提供高精地图加载及车道详细信息查询,强化定位和路由能力。
环境识别与判断 :集成交通灯、标志、停车位等环境要素的识别,辅助决策及判断。
5. 评价算法类
获取用户自定义评价功能所需要的基本仿真数据以及评价需要的用户规控算法内部相关信号。
EvaluationAPI 存取评价数据 :存取用户自定义的评价功能所需的数据,用于用户自定义的评价算法。

1.3 调用示例

注意

[SimOne 安装目录]/SimOne/SimOneAPI 中的范例代码根据目录分类,演示了 SimOne 仿真产品的各类 API 在客户本地算法程序中的应用。

下方链接主要为 API 调用示例,具体可查看 API调用参考示例

示例 文件夹 描述 子文件夹 描述
算法示例 ADAS ADAS 基础算法对接 SimOne 仿真平台接口应用示例。 ACC 自适应巡航控制算法示例。
AEB 自动紧急制动算法示例。
AEB-Daemon 云仿真环境连续案例运行 AEB 算法示例。
AEB-Evaluation 以 AEB 算法为例,展示如何在用户算法内输出评价所需要的信号数据。
AVP 自动泊车算法示例。
bin ADAS 算法应用程序生成目录。
Build 用于存放构建和编译项目产生的文件目录。
LKA 自动车道保持巡航算法示例。
TestEvaluation 用于测试和示范如何利用 EvaluationAPI 获取评价所需要的数据。
TrajectoryControl 控制车辆行驶轨迹的系统或算法。
util 包含一系列辅助工具和实用程序的目录。
Autopilot 自动驾驶算法综合 CurveSample 全局路径规划和局部路径调整示例
LimitChangeLaneSample 前方有障碍物示例
TrafficLightSample 获取场景中交通灯的相位状态示例
include 包含 SimOne 自带的库和第三方的调用的依赖库文件,主要包括一些 .h 和 .hpp 。
lib 包含 运行 SimOne 需要依赖的动态库,C++API 的头文件、数据结构文件,PythonAPI 的头文件、数据结构文件,PythonAPI 的算法示例。
适配第三方中间件 Cyber Apollo(r6.0.0)对接 SimOne 仿真平台基于 Cyber 中间件的接口示例。
Matlab SimOneAPI 在 Simulink 中的封装,包含模块接口和示例。
ROS 对接 SimOne 仿真平台基于 ROS1 中间件的接口示例。
ROS2 对接 SimOne 仿真平台基于 ROS2 中间件的接口示例。
SensorRaw 物理级数据可视化接口示例。 3rdparty 第三方插件 opencv,pcl
SensorCamera 物理级摄像头数据传输示例
SensorLidar 物理级激光雷达数据传输示例
SensorLidarROS 物理级激光雷达数据传输至 ROS 示例
SensorRadar4D 4D 毫米波雷达数据传输示例
功能模块示例 Tutorial SimOneAPI C++ 接口基础调用方法示例。 Dynamics 动力学 使用示例
HDMap HDMapAPI 使用示例
PNC PNCAPI 使用示例
Sensor 传感器 使用示例
Traffic 交通流 API 使用示例
V2X V2X 使用示例

C++_Python 接口语言支持

注意

算法接入教程请查看 C++算法接入 Python算法接入

1. API 查询方法

可以在下方 API 汇总列表 中找到所需 API ,然后点击链接 C++ API 文档 / Python API 文档 查看 API 具体参数。也可以在搜索框进行搜索。具体步骤如下:

注意

C++ API 文档 查看技巧如下, Python API 文档 直接点击链接即可。

2. API 汇总列表

类别 接口 功能 C++ API Python API
ServiceAPI
20个
截取节点信息 节点通信数据发送 API SendRouteMessage
节点通信数据接收 API ReceiveRouteMessageCB
选择车辆并初始化 初始化 SimOne API InitSimOneAPI SoInitSimOneAPI
多车版本-初始化 SimOne API InitSimOneAPIEx SoInitSimOneAPIEx
初始化 SimOne API 带超时 InitSimOneAPIWithTimeOut SoInitSimOneAPIWithTimeOut
多车版本 - 初始化 SimOne API 带超时 InitSimOneAPIExWithTimeOut SoInitSimOneAPIExWithTimeOut
设置日志格式 日志设置接口 SetLogOut SoSetLogOut
获取主车状态 获取主车状态信息 GetMainVehicleStatus SoGetMainVehicleStatus
获取主车状态信息回调的函数 SetMainVehicleStatusUpdateCB SoAPISetMainVehicleStatusUpdateCB
获取案例信息 获取当前库的版本号 GetVersion SoAPIGetVersion
获取案例详情 GetCaseInfo SoAPIGetCaseInfo
获取案例运行状态 GetCaseRunStatus SoGetCaseRunStatus
获取主车信息列表 GetMainVehicleList SoGetCaseRunStatus
获取高精度地图元数据信息 GetHDMapData SoGetHDMapData
案例控制 等待并获取当前帧值 Wait SoAPIWait
进行下一帧 NextFrame SoAPINextFrame
暂停,用于非帧同步调试 Pause SoAPIPause
继续,用于非帧同步调试 Continue SoAPIContinue
自动回调帧数据 仿真场景中每帧的回调函数 SetFrameCB SoAPISetFrameCB
退出 退出 API 节点 TerminateSimOneAPI SoTerminateSimOneAPI
SensorAPI
19个
GPS 获取主车 GPS 信息 GetGps SoGetGps
主车 GPS 更新回调 SetGpsUpdateCB SoApiSetGpsUpdateCB
真值 获得仿真场景中的物体真值信息 GetGroundTruth SoGetGroundTruth
获得仿真场景中的物体真值信息更新回调 SetGroundTruthUpdateCB SoApiSetGroundTruthUpdateCB
毫米波雷达 获得毫米波雷达目标信息 GetRadarDetections SoGetRadarDetections
毫米波雷达目标信息更新回调 SetRadarDetectionsUpdateCB SoApiSetRadarDetectionsUpdateCB
超声波雷达 获得一个超声波雷达信息 GetUltrasonicRadar SoGetUltrasonicRadar
获得所有超声波雷达信息 GetUltrasonicRadars SoGetUltrasonicRadars
超声波雷达真值信息更新回调 SetUltrasonicRadarsCB SoApiSetUltrasonicRadarsCB
目标级传感器 获取传感器检测到物体的对应真值(支持的传感器包括目标级相机/目标级激光雷达/完美传感器) GetSensorDetections SoGetSensorDetections
传感器真值信息更新回调(支持的传感器包括目标级相机/目标级激光雷达/完美传感器) SetSensorDetectionsUpdateCB SoApiSetSensorDetectionsUpdateCB
获得仿真场景中的交通灯真值 GetTrafficLight SoGetTrafficLights
获取传感器检测到车道与车道线数据(仅目标级相机和融合传感器支持) GetSensorLaneInfo SoGetSensorLaneInfo
获取传感器检测到车道与车道线数据回调 SetSensorLaneInfoCB SoApiSetSensorLaneInfoCB
获取传感器检测到地面喷漆信息(包括车道停止线/地面箭头/人行横道线) GetSensorRoadMarkInfo SoGetSensorRoadMarkInfo
获取传感器检测到地面喷漆信息(包括车道停止线/地面箭头/人行横道线数据回调) SetSensorRoadMarkInfoCB SoApiSetSensorRoadMarkInfoCB
配置信息 获得所有传感器的配置信息(Id/类型/频率/位置和朝向等) GetSensorConfigurations SoGetSensorConfigurations
环境 获取当前环境相关信息(天气/光照/地面等) GetEnvironment SoGetEnvironment
设置当前环境相关信息(天气/光照/地面等) SetEnvironment SoSetEnvironment
StreamingAPI
4个
物理级传感器流式传输 实时获取图像数据(图像格式包括 RGB/JPEG/Segmentation/H.265 等) GetStreamingImage SoGetStreamingImage
设置实时图像数据更新回调(图像格式包括 RGB/JPEG/Segmentation/H.265 等) SetStreamingImageUpdateCB SoApiSetStreamingImageUpdateCB
实时获取 SimOne_Streaming_Point_Cloud 格式点云数据 GetStreamingPointCloud SoGetStreamingPointCloud
设置点云数据更新回调 SetStreamingPointCloudUpdateCB SoApiSetStreamingPointCloudUpdateCB
V2XAPI
2个
V2X 获得对应车辆编号 V2X 中的 UPER 编码之后的 V2X 消息 GetV2XInfo SoGetV2XInfo
获得对应车辆编号 V2X 中的 UPER 编码之后的 V2X 消息更新回调 SetV2XInfoUpdateCB SoApiSetV2XInfoUpdateCB
PNCAPI
15个
选择车辆并初始化 注册 SimOne_Data_Gps 包含的状态以外的主车状态信息 RegisterVehicleState SoRegisterVehicleState
设置主车控制器的名字 SetDriverName SoSetDriverName
车辆位置与状态 设置主车位置 SetPose SoSetPose
重置主车状态 SetVehicleToInitState SoSetVehicleToInitState
车辆控制 主车控制 SetDrive SoSetDrive
主车控制模式 SetDriveMode SoGetControlMode
轨迹与规划控制 预测轨迹设置 SetTrajectory
主车控制(通过规划轨迹) SetDriveTrajectory SoSetDriveTrajectory
获取状态 获取通过 RegisterVehicleState 注册的主车状态信息 GetVehicleState SoGetVehicleState
获取车辆控制模式 GetControlMode SoGetControlMode
获取 SimOneDriver 控制信号 GetDriverControl SoGetDriverControl
获取案例主车路径点 GetWayPoints SoGetWayPoints
事件与信息设置 设置主车预警消息 SetVehicleEvent SoSetVehicleEvent
设置车辆信号灯状态 SetSignalLights SoSetSignalLights
场景事件回调 SetScenarioEventCB SoAPISetScenarioEventCB
HDMapAPI
50个

暂无PythonAPI
加载 标记高精地图已经初始化完成 setHdmapLoad
加载高精度地图 LoadHDMap
获取车道相关信息 获取最接近输入点的车道,所属车道优先 GetNearMostLane 车道检测
获取临近车道列表 GetNearLanes
获取视野范围内所有车道 GetNearLanesWithAngle
获取离最近车道左右边缘线的距离 GetDistanceToLaneBoundary 车道信息获取
获取车道信息(包含车道 ID,左右边缘线,虚拟中心线) GetLaneSample
获取车道连接信息 GetLaneLink
获取车道类型 GetLaneType
获取车道宽度 GetLaneWidth
获取输入点投影到指定车道中心线上的点和切线方向 GetLaneMiddlePoint
获取当前车辆位置所在车道的信息 GetLaneSampleByLocation
获取前方一定距离内的所有车道信息(包括车道ID、左右边缘线、虚拟中心线) GetForwardLaneSample
获取前方车道信息 GetForwardLaneInfo
根据指定车道 ID 和局部坐标获取输入点左右两侧车道标线信息 GetRoadMark 车道线获取
获取所有车道线信息列表 GetLaneData
获取指定车道线所在 Section 的所有车道线 ID 列表 GetSectionLaneList
获取路网指定坐标点的高程列表 GetHeights 地图数据获取
获取道路长度 GetRoadLength
获取车道长度 GetLaneLength
获取所有车道线信息列表 GetLaneLineInfo
获取 section 列表 GetSectionList
通过类型获取车道信号列表 GetSignalListOnLaneByType 导航数据获取
获取指定道路 ID 车道名称列表 GetLaneList
获取路口相关信息 获取所有交叉路口 ID 列表 GetJunctionList
获取指定十字路口详细信息 GetJunction
获取拓扑信息 GetTopoGraph
获取交通标志相关信息 获取地图中信号灯列表 GetTrafficLightList 交通信号灯
获取指定车道绑定的信号灯列表 GetSpecifiedLaneTrafficLightList
获取地图中交通标志列表 GetTrafficSignList 交通标志
获取指定车道关联交通标志列表 GetSpecifiedLaneTrafficSignalList
获取指定车道所在道路上的网状线列表 GetCrossHatchList 网状线信息获取
获取交通灯给定作用车道的关联停止线列表 GetStoplineList 停止线
获取给定车道的关联停止线列表 GetSpecifiedLaneStoplineList
获取交通灯给定作用车道的关联人行横道线列表 GetCrosswalkList 人行横道
获取给定车道的关联人行横道线列表 GetSpecifiedLaneCrosswalkList
获取地图中停车位列表 GetParkingSpaceList 停车位信息获取
获取地图指定点前方停车位列表 GetParkingSpaceIds
判断元素是否存在 查询指定车道是否存在于地图中 ContainsLane
判断位置是否与车道线重叠 IsOverlapLaneLine
判断指定道路是否是双向道路 IsTwoSideRoad
判断车道是否为机动车道 IsDriving
判断车道是否在交叉路口内 IsInJunction
判断坐标点是否在车道内 IsInsideLane
定位 获取相对于车道虚拟中心线的 ST 坐标 GetLaneST
获取相对于道路参考线的 ST 坐标 GetRoadST
根据车道 ST 坐标获取局部坐标 GetInertialFromLaneST
路由 获取路网路径规划 GenerateRoute
获取路网路径规划详细信息 GenerateRoute_V2
获取规划路径所途径道路的 ID 列表 Navigate
EvaluationAPI
6个
存储数据 初始化评价服务 InitEvaluationService SoInitEvaluationService
初始化评价服务,本地存储数据 InitEvaluationServiceWithLocalData SoInitEvaluationServiceWithLocalData
保存评价算法所需的各类信息(JSON 格式) SaveEvaluationRecord SoSaveEvaluationRecord
添加信号 添加评价算法所需的各类信息(JSON 格式) AddEvaluationRecord SoAddEvaluationRecord
判定 场景判定事件回调 SetJudgeEventCB SoSetJudgeEventCB
发送场景判定事件 AddJudgeEvent SoAddJudgeEvent

API 功能支持

本文档主要介绍 API 功能支持具体内容。

  • API 调用示例参考 调用示例 ([SimOne 安装目录]\SimOne\SimOneAPI )

API 类型 API 接口 功能
1. 基础服务类
主要提供车辆选择、仿真工作模式设置和热区数据获取的功能。
ServiceAPI 选择车辆: 选择具体的目标车辆进行控制,并订阅其状态更新
设置仿真工作模式: 根据需要选择帧同步(保证实时性和稳定性)或非帧同步(提高运行效率)模式
获取热区数据:
通过主动 API 调用或自动回调函数获取车辆及其周边环境的实时数据
2. 传感器类
为开发者提供了从 SimOne 仿真环境中获取各种传感器数据的能力。
SensorAPI 获取目标级或物理级信息: 包括图像信息、激光雷达点云、毫米波雷达及超声波雷达目标级信息等
获取传感器真值数据: 既能满足感知算法接入测试,也能满足跳过感知,直接从决策算法接入的开环测试需求
环境信息配置与管理 :涉及获取和设置与仿真环境相关信息(如天气、光照和地面条件等),对于创建特定测试场景非常关键。
StreamingAPI 获取物理级传感器流式传输 :实时获取和自动回调图像及点云数据,支持多种格式。
V2XAPI V2X 消息处理 :获取特定车辆 UPER 编码的 V2X 消息及更新通知。
3. 控制通信类
通过控制信号输入驱动被测车辆运行,实现复杂交通场景模拟。
PNCAPI 车辆状态与初始化 :涵盖选择测试车辆、初始化状态信息、设置起始位置和重置车辆状态的操作。
预警信息与控制策略 :包括设置和接收预警信息、控制车辆动作,以及规划控制输出的必要接口,确保测试车辆按照算 法进行动态响应。
4. 高精地图运行时类
为决策算法提供厘米级高精度地图信息,包括路网和交通元素,支持包括路径规划和定位在内的 多种 API 调用。
HDMapAPI 地图与车道分析 :提供高精地图加载及车道详细信息查询,强化定位和路由能力。
环境识别与判断 :集成交通灯、标志、停车位等环境要素的识别,辅助决策及判断。
5. 评价算法类
获取用户自定义评价功能所需要的基本仿真数据以及评价需要的用户规控算法内部相关信号。
EvaluationAPI 存取评价数据 :存取用户自定义的评价功能所需的数据,用于用户自定义的评价算法。

1. 基础服务类

1.1 ServiceAPI
1.1.1 选择车辆并初始化

注意

该操作可以设定是否使用同步帧功能

1、帧同步(保证实时性和稳定性)

2、非帧同步(提高运行效率)

事件 API
初始化 SimOne API SIMONE_API bool InitSimOneAPI(const char* mainVehicleId = "0", bool isFrameSync = false, const char *serverIP = "127.0.0.1", int port = 23789, void(*startCase)()=0, void(*endCase)()=0, int registerNodeId=0);
多车版本-初始化 SimOne API SIMONE_API bool InitSimOneAPIEx(char** mainVehicleIdList, int count, bool isFrameSync = false, const char *serverIP = "127.0.0.1", int port = 23789, void(*startCase)() = 0, void(*endCase)() = 0, int registerNodeId = 0);
初始化 SimOne API 带超时 SIMONE_API bool InitSimOneAPIWithTimeOut(const char* mainVehicleId = "0", bool isFrameSync = false, const char *serverIP = "127.0.0.1", int port = 23789, int timeOutMS = -1, void(*startCase)() = 0, void(*endCase)() = 0, int registerNodeId = 0);
多车版本 - 初始化 SimOne API 带超时 SIMONE_API bool InitSimOneAPIExWithTimeOut(char** mainVehicleIdList, int count, bool isFrameSync = false, const char *serverIP = "127.0.0.1", int port = 23789, int timeOutMS = -1, void(*startCase)() = 0, void(*endCase)() = 0, int registerNodeId = 0);
参数名 解释
mainVehicleId 主机车辆 ID(范围从 0 到 9)
isFrameSync 是否同步帧
serverIP BridgeIO 服务器 IP 地址
port BridgeIO 服务器端口号
startCase 案例开始前调用的回调函数
endCase 案例结束后调用的回调函数
registerNodeId 注册节点 ID(当前未使用
count 主车辆 ID 数量
timeOutMS 超时时间,以毫秒为单位
1.1.2 获取主车状态
事件 API
主动获取主车状态 SIMONE_API bool GetMainVehicleStatus(const char* mainVehicleId, SimOne_Data_MainVehicle_Status *pMainVehicleStatus);
回调方式获取之车状态 SIMONE_API bool SetMainVehicleStatusUpdateCB(void(*cb)(const char* mainVehicleId, SimOne_Data_MainVehicle_Status *pMainVehicleStatus));
参数名 解释
mainVehicleId 主车的 ID
SimOne_Data_MainVehicle_Status 指向主车状态信息的指针

SimOne_Data_MainVehicle_Status 结构体说明:

参数名 解释
mainVehicleId 主车 ID 的队列
mainVehicleStatus 对应的状态
1.1.3 其他函数说明
类别 事件 API
退出 退出 API 节点 SIMONE_API bool TerminateSimOneAPI();
获取案例信息 获取案例详情 SIMONE_API bool GetCaseInfo(SimOne_Data_CaseInfo *pCaseInfo);
获取案例运行状态 SIMONE_API ESimOne_Case_Status GetCaseRunStatus();
获取主车信息列表 SIMONE_API bool GetMainVehicleList(SimOne_Data_MainVehicle_Info *pMainVehicleInfo);
获取高精度地图元数据信息 SIMONE_API bool GetHDMapData(SimOne_Data_Map* hdMap);
获取当前库的版本号 SIMONE_API const char *GetVersion();
案例控制 等待并获取当前帧值 SIMONE_API int Wait();
进行下一帧 SIMONE_API void NextFrame(int frame); //frame 为具体的第几帧
暂停,用于非帧同步调试 SIMONE_API int Pause();
继续,用于非帧同步调试 SIMONE_API int Continue();
自动回调帧数据 仿真场景中每帧的回调函数 SIMONE_API bool SetFrameCB(void(*FrameStart)(int frame), void(*FrameEnd)(int frame));
截取节点信息 节点通信数据发送API SIMONE_API bool SendRouteMessage(int length, void* pBuffer, int msgId, int toNodeId, ESimOne_Client_Type toNodeType);
节点通信数据接收API SIMONE_API bool ReceiveRouteMessageCB(void(*cb)(int fromId, ESimOne_Client_Type fromType, int length, const void* pBuffer, int commandId));
设置日志格式 日志设置接口 SIMONE_API bool SetLogOut(ESimOne_LogLevel_Type level, const char *format, ...);

SimOne_Data_CaseInfo 如下:

参数名 解释
caseName 案例名称
caseId 案例 ID
taskId 任务 ID

SimOne_Data_MainVehicle_Info 结构如下:

参数名 解释
size 车辆数量
id_list 车辆 ID
type_list 车辆类型

SimOne_Data_Map 结构如下:

参数名 解释
openDrive 地图名称
openDriveUrl 地图下载的URL
opendriveMd5 地图文件的MD5值

2. 传感器类

2.1 SensorAPI
新增 获得所有传感器的配置信息(Id/类型/频率/位置和朝向等) GetSensorConfigurations SoGetSensorConfigurations
新增 获取传感器检测到地面喷漆信息(包括车道停止线/地面箭头/人行横道线) GetSensorRoadMarkInfo SoGetSensorRoadMarkInfo
获取传感器检测到地面喷漆信息(包括车道停止线/地面箭头/人行横道线数据回调) SetSensorRoadMarkInfoCB SoApiSetSensorRoadMarkInfoCB
2.1.1 GPS

GPS 获取数据的 API 有:

事件 API
获取主车 GPS 信息 SIMONE_NET_API bool GetGps(int mainVehicleId, SimOne_Data_Gps *pGps)
主车 GPS 更新回调 SIMONE_NET_API bool SetGpsUpdateCB(void(cb)(int mainVehicleId, SimOne_Data_GpspGps))
  • mainVehicleId 为主车 ID; pGps 的数据结构 SimOne_Data_Gps 如下:

数据 解释
float posX; Opendrive 中地图坐标系位置信息 X 坐标(单位 米)
float posY; Opendrive 中地图坐标系位置信息 Y 坐标(单位 米)
float posZ; Opendrive 中地图坐标系位置信息 Z 坐标(单位 米)
float oriX; Opendrive 中地图坐标系旋转位置信息 X 坐标(单位 弧度)
float oriY; Opendrive 中地图坐标系旋转位置信息 Y 坐标(单位 弧度)
float oriZ; Opendrive 中地图坐标系旋转位置信息 Z 坐标(单位 弧度)
float velX; Opendrive 中地图坐标系速度信息 X 坐标(单位 m/s)
float velY; Opendrive 中地图坐标系速度信息 Y 坐标(单位 m/s)
float velZ; Opendrive 中地图坐标系速度信息 Z 坐标(单位 m/s)
float throttle; 主车油门
float brake; 主车刹车
float steering; 主车方向盘
int gear; 主车档位
float accelX; Opendrive 中地图坐标系加速度 X 坐标(单位 m/s^2)
float accelY; Opendrive 中地图坐标系加速度 Y 坐标(单位 m/s^2)
float accelZ; Opendrive 中地图坐标系加速度 Z 坐标(单位 m/s^2)
float angVelX; Opendrive 中地图坐标系速度方向在 X 坐标(单位 弧度)
float angVelY; Opendrive 中地图坐标系速度方向在 Y 坐标(单位 弧度)
float angVelZ; Opendrive 中地图坐标系速度方向在 Z 坐标(单位 弧度)
float wheelSpeedFL; 主车前面左轮的转速(单位 m/s)
float wheelSpeedFR; 主车前面右轮的转速(单位 m/s)
float wheelSpeedRL; 主车后面左轮的转速(单位 m/s)
float wheelSpeedRR; 主车后面面右轮的转速(单位 m/s)
float engineRpm; 发动机转速(单位 r/min)
float odometer; 主车里程表(单位 米)
2.1.2 摄像头以及目标级摄像头

2.1.2.1 物理级摄像头

事件 API
获取图像信息 SIMONE_NET_API bool GetImage(const int mainVehicleId, const int sensorId, SimOne_Data_Image *pImage)
设置图像更新回调 SIMONE_NET_API bool SetImageUpdateCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_ImagepImage))
获取流式图像信息 SIMONE_NET_API bool GetStreamingImage(const char ip, unsigned short port, SimOne_Data_ImagepImage)
设置流式图像回调 SIMONE_NET_API bool SetStreamingImageCB(const char* ip, unsigned short port, void(cb)(SimOne_Data_ImagepImage))

mainVehicleId 为主车 ID; sensorId 为摄像头 ID; ip 为接收机器的 ip 地址; port 为分配的端口号; pImage 为每帧图像信息; SimOne_Data_Image 的结构如下:

数据 解释
int width; 图像的宽度
int height; 图像的高度
SimOne_Image_Format format; 图像的格式目前只支持 RGB(每通道 8 位)
int imageDataSize; 图像的大小
Char imageData[SOSM_IMAGE_DATA_SIZE_MAX]; 图像数据存储数组,最大 1920 x 1200 x 3

1 与 2 方式获取物理级摄像头信息时不需要配置 UDP 信息,仅以 3 、4 的方式获取物理级图像信息时,需要在网页端订阅通道上配置 UDP 信息例如:udp://127.0.0.1:13956,截图如下:

2.1.2.2 目标级摄像头

事件 API
获取传感器检测到物体的对应真值 (支持的传感器包括目标级相机/目标级激光雷达/完美传感器)
传感器真值信息更新回调 (支持的传感器包括目标级相机/目标级激光雷达/完美传感器)
获取传感器检测到车道与车道线数据 (仅目标级相机和融合传感器支持)
获取传感器检测到车道与车道线数据 回调
  • 其中 pGroundtruth 为目标信息集合, SimOne_Data_SensorDetections 结构如下:

数据 解释
int objectSize; 目标数量
SimOne_Data_SensorDetections_Entry objects[SOSM_SENSOR_DETECTIONS_OBJECT_SIZE_MAX]; 目标存储集合,最多存储 256 个目标
  • SimOne_Data_SensorDetections_Entry 结构如下:

数据 解释
int id; 目标 ID
SimOne_Obstacle_Type type; 目标类型,与目标物理材质对应类型一致
float posX; 目标在世界坐标系中的 X 坐标(单位 米)
float posY; 目标在世界坐标系中的 Y 坐标(单位 米)
float posZ; 目标在世界坐标系中的 Z 坐标(单位 米)
float oriX; 目标在世界坐标系中的 X 轴方向的旋转坐标(单位 弧度)
float oriY; 目标在世界坐标系中的 Y 轴方向的旋转坐标(单位 弧度)
float oriZ; 目标在世界坐标系中的 Z 轴方向的旋转坐标(单位 弧度)
float length; 目标的长度(单位 米)
float width; 目标的宽度(单位 米)
float height; 目标的高度(单位 米)
float range; 目标相对于传感器的距离(单位 米)
float velX; 目标在 X 轴上的速度(单位 km/h)
float velY; 目标在 Y 轴上的速度(单位 km/h)
float velZ; 目标在 Z 轴上的速度(单位 km/h)
float probability; 目标为当前类型的置信度(0~1 之间)
float relativePosX; 目标相对于传感器的 X 坐标(单位 米)
float relativePosY; 目标相对于传感器的 Y 坐标(单位 米)
float relativePosZ; 目标相对于传感器的 Z 坐标(单位 米)
float relativeRotX; 目标相对于传感器的 X 轴方向的旋转坐标(单位 米)
float relativeRotY; 目标相对于传感器的 Y 轴方向的旋转坐标(单位 米)
float relativeRotZ; 目标相对于传感器的 Z 轴方向的旋转坐标(单位 米)
float relativeVelX; 目标相对于传感器的 X 轴方向的速度坐标(单位 km/h)
float relativeVelY; 目标相对于传感器的 Y 轴方向的速度坐标(单位 km/h)
float relativeVelZ; 目标相对于传感器的 Z 轴方向的速度坐标(单位 km/h)
float bbox2dMinX ; 像素坐标系下目标的 2d 包围盒左上角 X 坐标
float bbox2dMinY ; 像素坐标系下目标的 2d 包围盒左上角 Y 坐标
float bbox2dMaxX ; 像素坐标系下目标的 2d 包围盒右下角 X 坐标
float bbox2dMaxY ; 像素坐标系下目标的 2d 包围盒右下角 Y 坐标
  • 其中 pLaneInfo 为车道信息集合, SimOne_Data_LaneInfo 结构如下:

数据 解释
int id; 车道 ID
ESimOneLaneType laneType; 车道类型
int laneLeftID; 当前车道的左边车道 ID
int laneRightID; 当前车道的右边车道 ID
int lanePredecessorID[SOSM_SENSOR_LANE_OBJECT_SIZE_MAX]; 当前车道前继集合最大 256
int laneSuccessorID[SOSM_SENSOR_LANE_OBJECT_SIZE_MAX]; 当前车道后继集合最大 256
SimOne_Data_LaneLineInfo l_Line; 当前车道左边缘线信息
SimOne_Data_LaneLineInfo c_Line; 当前车道中间线信息
SimOne_Data_LaneLineInfo r_Line; 当前车道右边缘线信息
SimOne_Data_LaneLineInfo ll_Line; 当前车道左左边缘线信息
SimOne_Data_LaneLineInfo rr_Line; 当前车道右右边缘线信息
2.1.3 理想传感器
  • 理想传感器是用来获取目标真值的,只有目标级信息。与理想传感器相关的 API 有:

事件 API
获得仿真场景中的物体真值信息
获得仿真场景中的物体真值信息更新回调
获取传感器检测到物体的对应真值(支持的传感器包括目标级相机/目标级激光雷达/完美传感器)
传感器真值信息更新回调(支持的传感器包括目标级相机/目标级激光雷达/完美传感器)
  • 其中 3 4 上面已经介绍过,1 2 中 SimOne_Data_Obstacle 结构如下:

数据 解释
int obstacleSize; 目标数量
SimOne_Data_Obstacle_Entry obstacle[SOSM_OBSTACLE_SIZE_MAX]; 目标存储数组最多存储 100 个
  • SimOne_Data_Obstacle_Entry 结构如下:

数据 解释
int id; 目标 ID
int viewId; 目标可视化 ID
SimOne_Obstacle_Type type; 目标类型,与目标物理材质对应类型一致
float theta; 全局坐标系方位角,这里用的是 oriZ 的值
float posX; 目标在世界坐标系中的 X 坐标(单位 米)
float posY; 目标在世界坐标系中的 Y 坐标(单位 米)
float posZ; 目标在世界坐标系中的 Z 坐标(单位 米)
float oriX; 目标在世界坐标系中的 X 轴方向的旋转坐标(单位 弧度)
float oriY; 目标在世界坐标系中的 Y 轴方向的旋转坐标(单位 弧度)
float oriZ; 目标在世界坐标系中的 Z 轴方向的旋转坐标(单位 弧度)
float velX; 目标在 X 轴上的速度(单位 km/h)
float velY; 目标在 Y 轴上的速度(单位 km/h)
float velZ; 目标在 Z 轴上的速度(单位 km/h)
float length; 目标的长度(单位 米)
float width; 目标的宽度(单位 米)
float height; 目标的高度(单位 米)
2.1.4 超声波雷达

超声波雷达用来探测目标离传感器的相对距离,以及返回目标的位置信息,相关的 API 如下:

事件 API
获得一个超声波雷达信息 SIMONE_NET_API bool GetUltrasonicRadar(int mainVehicleId, int sensorId, SimOne_Data_UltrasonicRadar *pUltrasonic)
获得所有超声波雷达信息 SIMONE_NET_API bool GetUltrasonicRadars(int mainVehicleId, SimOne_Data_UltrasonicRadars *pUltrasonics)
超声波雷达真值信息更新回调 SIMONE_NET_API bool SetUltrasonicRadarsCB(void(cb)(int mainVehicleId, SimOne_Data_UltrasonicRadarspUltrasonics))

1 获取的是单个超声波雷达的信息,而 2 返回的是所有超波雷达信息的集合;

  • SimOne_Data_UltrasonicRadar 的结构如下:

数据 解释
int id; 超声波 ID
int obstacleNum; 超声雷达检测到目标的数量
SimOne_Data_UltrasonicRadarDetection_Entry obstacledetections[SOSM_OBSTACL_SIZE_MAX]; 检测到目标集合,最多存储 100 个
  • SimOne_Data_UltrasonicRadarDetection_Entry 的结构如下:

数据 解释
float obstacleRanges = 0; 目标力传感器的距离(单位米)
float x = 0; 目标相对于传感器的 x 坐标(单位米)
float y = 0; 目标相对于传感器的 y 坐标(单位米)
  • SimOne_Data_UltrasonicRadars 的结构如下:

数据 解释
int UltrasonicRadarsNum; 超声波雷达数量
SimOne_Data_UltrasonicRadar ultrasonicRadars[SOSM_ULTRASONICRADAR_SIZE_MAX]; 超声波雷达存储集合,最多存储 100 个
2.1.5 毫米波雷达

毫米波雷达用来探测目标距离,速度,角度信息,相关的 API 如下:

事件 API
获得毫米波雷达目标信息 SIMONE_NET_API bool GetRadarDetections(const int mainVehicleId, const int sensorId, SimOne_Data_RadarDetection *pDetections)
毫米波雷达目标信息更新回调 SIMONE_NET_API bool SetRadarDetectionsUpdateCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_RadarDetectionpDetections))
  • 输入:mainVehicleId 为主车 ID;sensorId 为毫米波雷达 ID;

  • 输出:SimOne_Data_RadarDetection *pDetections,其结构体如下:

    • struct SimOne_Data_RadarDetection : public SimOne_Data

数据 解释
int detectNum; 目标物个数
SimOne_Data_RadarDetection_Entry detections[SOSM_RADAR_SIZE_MAX]; 目标物集合
  • struct SimOne_Data_RadarDetection_Entry

数据 解释
int id; 目标物 ID
int subId; 目标物子 ID
SimOne_Obstacle_Type type; 目标物类型
float posX; 目标物在雷达坐标系的 X 轴位置(雷达坐标系采用右手坐标:前进方向为 X,正上方向为 Z)
float posY; 目标物在雷达坐标系的 Y 轴位置
float posZ; 目标物在雷达坐标系的 Z 轴位置
float velX; 目标物在雷达坐标系的 X 轴速度
float velY; 目标物在雷达坐标系的 Y 轴速度
float velZ; 目标物在雷达坐标系的 Z 轴速度
float range; 目标物在雷达坐标系的距离
float rangeRate; 目标物在雷达坐标系的径向速度
float azimuth; 目标物在雷达坐标系的水平角度
float vertical; 目标物在雷达坐标系的垂直角度
float snrdb; 目标物回波信号的信噪比
float rcsdb; 目标物 RCS 值
float probability; 目标物置信度
2.1.6 激光雷达以及目标级激光雷达

2.1.6.1 物理级激光雷达

事件 API(貌似删除了?)
1 SIMONE_NET_API bool GetPointCloud(int mainVehicleId, int sensorId, SimOne_Data_Point_Cloud *pPointCloud)
2 SIMONE_NET_API bool SetPointCloudUpdateCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_Point_CloudpPointCloud))
3 SIMONE_NET_API bool GetStreamingPointCloud(const char ip, unsigned short port, unsigned short infoPort,SimOne_Data_Point_CloudpPointCloud)
4 SIMONE_NET_API bool SetStreamingPointCloudUpdateCB(const char* ip, unsigned short port,unsigned short infoPort, void(cb)(SimOne_Data_Point_CloudpPointCloud))

mainVehicleId 为主车 ID; sensorId 为激光雷达 ID; ip 为接收机器的 ip 地址; port 为激光雷达数据端口号; infoPort 为用户配置数据端口; pPointCloud 为每帧点云信息, SimOne_Data_Point_Cloud 的结构如下:

1 与 2 方式获取激光雷达信息时不需要配置 UDP 信息,仅以 3、4 的方式获取物理级激光雷达信息时,需要在网页端通道上配置 UDP 信息例如:udp://127.0.0.1:6699,截图如下:

2.1.6.2 目标级激光雷达

事件 API
1 SIMONE_NET_API bool GetSensorDetections(int mainVehicleId, int sensorId, SimOne_Data_SensorDetections *pGroundtruth)
2 SIMONE_NET_API bool SetSensorDetectionsUpdateCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_SensorDetectionspGroundtruth))

其中 pGroundtruth SimOne_Data_SensorDetections 结构已经在摄像头与目标级摄像头 API 中已介绍。

2.1.7 目标级融合传感器
事件 API
获取传感器检测到物体的对应真值(支持的传感器包括目标级相机/目标级激光雷达/完美传感器) SIMONE_NET_API bool GetSensorDetections(int mainVehicleId, int sensorId, SimOne_Data_SensorDetections *pGroundtruth)
传感器真值信息更新回调(支持的传感器包括目标级相机/目标级激光雷达/完美传感器) SIMONE_NET_API bool SetSensorDetectionsUpdateCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_SensorDetectionspGroundtruth))
获取传感器检测到车道与车道线数据(仅目标级相机和融合传感器支持) SIMONE_NET_API bool GetSensorLaneInfo(int mainVehicleId, int sensorId, SimOne_Data_LaneInfo *pLaneInfo)
获取传感器检测到车道与车道线数据回调 SIMONE_NET_API bool SetSensorLaneInfoCB(void(cb)(int mainVehicleId, int sensorId, SimOne_Data_LaneInfopLaneInfo))

其中 pGroundtruth SimOne_Data_SensorDetections SimOne_Data_LaneInfo 结构已经在摄像头与目标级摄像头 API 中已介绍。

2.2 StreamingAPI
名称 事件 C++ API Python API
物理级传感器流式传输 实时获取图像数据(图像格式包括 RGB/JPEG/Segmentation/H.265 等) GetStreamingImage SoGetStreamingImage
设置实时图像数据更新回调(图像格式包括 RGB/JPEG/Segmentation/H.265 等) SetStreamingImageUpdateCB SoApiSetStreamingImageUpdateCB
实时获取 SimOne_Streaming_Point_Cloud 格式点云数据 GetStreamingPointCloud SoGetStreamingPointCloud
设置点云数据更新回调 SetStreamingPointCloudUpdateCB SoApiSetStreamingPointCloudUpdateCB
2.3 V2XAPI

V2X(车联网)技术关键在于两部分设备: OBU RSU ,它们通过无线通信方式实现车与车以及车与路边设施之间的互联。具体的设备功能和通信方式如下表所示:

序号 组件 设施 描述 通信方式
1 OBU (车载端) 车辆内部安装 作为车辆通信节点 直连 RSU;与其他 OBU 通过 LTE 广播通信
2 RSU (路侧端) 路边设施安装 类似大型 WIFI,支持车辆通信 广播 CSAE2020 标准信息给所有车辆 OBU

在 CSAE2020 标准下, RSU 负责将关键安全和导航信息以广播的方式传输给车载的 OBU ,确保车辆及时获取重要通信。

详细的广播消息类型及其描述如右表所示:

消息类型 覆盖内容
SPAT 信号灯状态信息,例如红绿灯变换
RSI 路侧信息,涉及道路状况例如施工、限速等
RSM 路侧安全信息,包括事故报告、车辆异常等
MAP 地图信息,详细描述路口设计及其信号灯相位信息
2.3.1 V2X API 概览
事件 API
获取主车通过 OBU 接收到的特定 V2X 消息 SIMONE_API bool GetV2XInfo(const char* mainVehicleId, const char* sensorId, int infoType, SimOne_Data_V2XNFS*pDetections)
设置回调函数,以获取所有接收到的 V2X 消息 SIMONE_API bool SetV2XInfoUpdateCB(void(cb)(const char mainVehicleId, const char* sensorId, SimOne_Data_V2XNFS*pDetections))
2.3.2 API 详细说明

2.3.2.1 GetV2XInfo 函数

用于获取指定类型的 V2X 消息。

参数 参数 类型 描述
输入 mainVehicleId const char* 主车 ID。
sensorId const char* OBU 设备 ID。
infoType int 要获取的 V2X 消息类型。
输出 pDetections SimOne_Data_V2XNFS* 返回的 V2X 消息。

2.3.2.2 SetV2XInfoUpdateCB 函数

用于设置 V2X 消息更新的回调,确保消息实时更新且无数据丢失。

参数 参数 类型 描述
输入 cb function 回调函数。
mainVehicleId const char* 主车 ID。
sensorId const char* OBU 设备 ID。
输出 pDetections SimOne_Data_V2XNFS* 返回的 V2X 消息。

2.3.2.3 V2X 消息结构体 SimOne_Data_V2XNFS 说明:

字段名称 类型 描述
infoType int 消息类型,按照 ESimOne_V2X_MessageFrame_PR 枚举定义
V2XMsgFrameSize int 消息的字节大小
MsgFrameData char[SOSM_V2X_MSGFRAME_SIZE_MAX] ASN 编码的十六进制字符形式的应用层消息

注意 :更详细的消息定义可参考《CSAE 2020 合作式智能运输系统 - 车用通信系统应用层及应用数据交互标准》。

3. 控制通信类

3.1 PNCAPI

调用示例可参考 调用示例

4. 高精地图运行时类

4.1 HDMapAPI

高精度地图路网运行时目前提供的 API 包括功能为: 全图查询,定位,路由,交通灯和标志牌,停车位 等。

4.1.1 基本概念
  1. 坐标系统 :对于高精度地图而言,系统提供 Local ENU 和 s-t 两种坐标系统

A. 世界坐标系/站心直角坐标系(Local ENU) 世界坐标系为 x,y,z 右手坐标系

惯例适用于地理参考,即对应站心直角坐标系,x 为正东(East,E),y 为正北(North,N),z 为 Up(U)。

B. 参考线坐标系/轨道系统 s-t 坐标系(Track System s-t coordinate)

路网运行时根据不同参考线基准分别定义了 2 个 s-t 坐标系:

  • 道路参考线 为基准定义 s-t 坐标系

  • 车道虚拟中心线 为基准定义 s-t 坐标系

  1. 车道标识符 :高精度地图中的 laneName 为车道提供了唯一标识,结合道路编号、路段索引和车道编号,实现了精准的车道信息查询和定位。

    • 标识符格式 : $roadId_sectionIndex_laneId

      • $roadId : 道路的唯一编号。

      • _sectionIndex : 道路中特定路段的索引,用于标识道路的不同部分。

      • _laneId : 车道编号,在每个路段中独一无二。

    例如:

    • "1_0_-1" 表示道路编号为 1 的路段索引 0 上的右侧第一条车道( 负号表示右侧 )。

    • "1_0_2" 表示同一路段上左侧的第二条车道( 正号表示左侧 )。

  2. 坐标转换 :LocalENU(x,y,z) 坐标和 [s,t] 坐标相互转换

    1. Road 参考线体系下的 [s,t] 坐标

      • 定义: 道路参考线 为基准线,参考线右侧 t 值为负,左侧 t 值为正

      • 例子: * *P(-51.5,-73.5)对应 Road 1 的[s,t]坐标系的值是(7,-5.25)

    2. Lane 虚拟中心线体系下的 [s,t] 坐标

      • 定义: 车道虚拟中心线 为基准线,基准线右侧 t 为负,左侧 t 为正,主车沿着车道虚拟中心线行驶,那么 t 值永远为 0

      • 例子 :P(-51.5,-73.5),对应 Lane “1_0_-2”的[s,t]坐标系的值是(7,0);对应 Lane “1_0_-1”的[s,t]坐标系的值是(7,-3.5)

  1. 定位障碍物 :使用 Road 参考线体系下的[s,t]坐标,我们可以确定障碍物相对于主车前进方向的横向距离(t)和纵向距离(s)。

    • 定义 :以道路参考线为基准线,参考线右侧 t 值为负,左侧 t 值为正,S 是沿着道路参考线的累加值

    • 例子 :主车相对于道路的 ST 坐标(25,-5.25)

4.1.2 全局查询

4.1.3 定位

4.1.4 路由

5. 评价算法类

5.1 EvaluationAPI
5.1.1 评价 API 功能介绍

Simone 支持用户自定义评价功能,EvaluationAPI 用于获取存储用户自定义的评价功能所需的数据,主要为:

(1)仿真过程数据,例如主车以及障碍物的位姿数据等;

(2)用户规控算法的内部输出信号,例如状态机信号、控制信号等;

5.1.2 评价 API 存储数据的方式

目前存储用户自定义评价所需数据的方式有两种:本地文件存储与数据库存储。

对应的 API 如下:

API 功能 API
用于获取仿真过程数据,并将数据存储到数据库中。 InitEvaluationService
用于获取仿真过程数据,并将数据存储到本地文件。 InitEvaluationServiceWithLocalData
保存评价算法所需的各类信息(JSON 格式)。 SaveEvaluationRecord
5.1.3 评价 API 添加规控算法内部信号

用户自定义评价算法需要的数据除了仿真过程数据,有些可能还需要特定的规控算法内部信号,用户可以通过 API 自行添加评价所需要的数据,例如变道信号、控制信号等。

API 功能 API
添加评价算法所需的各类信息(JSON 格式),信号格式示例:{"category": "signal", "timestamp": 1648363819335, "ACC": "on", "ACCSpeed": 20} AddEvaluationRecord

第三方中间件 ROS

1. 数据交互流程概述

  1. 获取仿真感知数据 :ROS API 负责从 SimOne 仿真平台中收集感知数据。

  2. 数据转换 :收集到的仿真感知数据被转换成标准的 ROS 消息格式。

  3. 发布消息到 ROS Topic :转换后的数据被发布到指定的 ROS 话题(Topic)上供进一步使用。

  4. 驾驶算法订阅处理 :驾驶算法模块订阅这些话题,并将数据传入规控/感知模块,进行算法训练和处理。

  5. 发布控制消息 :算法处理后,生成的控制消息被发布到仿真主车控制话题上。

  6. 通信闭环完成控制 :ROS API 捕捉这些控制消息,并将其作为参数传入 SimOne 仿真主车的动力学节点。这样便驱动了仿真场景中主车的具体行动。

  7. 算法验证和调试 :驾驶算法可以选择订阅特定的话题消息来验证局部模块的准确性。此外,通过在 ROS 环境中建立一个闭环系统,可以实现对驾驶算法整体性能的综合验证。

2. 数据通信流程简图

3. 软件环境

  • 编程语言 :C++

4. 编译环境

4.1 ROS Msg 消息转换

将 SimOne API 数据格式转为 ROS 可发布/订阅的标准数据格式。

  1. 编写 ROS msg 消息文件

    根据 SimOne API 接口数据,参照 C++数据类型与 ROS msg 数据类型的映射关系,编写对应的 ROS API msg 消息文件。

  2. 创建 ROS 工程 Workspace

执行以下命令创建 ROS 工程 Workspace:

  mkdir -p ~/catkin_ws/src
  cd ~/catkin_ws/src
  catkin_init_workspace
  1. 创建功能包

执行以下命令

  cd ~/catkin_ws/src
  catkin_create_pkg <package_name> roscpp std_msgs
  1. 添加 msg 消息文件至功能包

将编写好的 msg 消息文件放入功能包的指定目录下:

  mkdir ~/catkin_ws/src/<package_name>/msg
  1. 添加功能依赖

~/catkin_ws/src/<package_name>/package.xml 文件中添加功能依赖:

  <build_dependmessage_generation</build_depend<exec_dependmessage_runtime</exec_depend
  1. 修改 CMakeLists.txt

~/catkin_ws/src/<package_name>/CMakeLists.txt 文件中添加必要的编译选项,以支持自定义消息的编译。

find_package(catkin REQUIRED COMPONENTS
    roscpp
    std_msgs
    message_generation
)

add_message_files(FILES
    <ROS API msg 消息文件 .msg>
)

generate_messages(DEPENDENCIES
    std_msgs
)

catkin_package(
    CATKIN_DEPENDS roscpp std_msgs message_runtime
)
  1. 编译功能包

返回到 catkin_ws 目录并编译功能包:

  cd ~/catkin_ws
  catkin_make
  1. 编译整个工作空间

为确保整个工作空间构建成功,再次执行:

  cd ~/catkin_ws
  catkin_make
  1. 检查 C++头文件

检查 msg 文件生成的 C++头文件是否位于以下目录中:

  ~/catkin_ws/devel/include/<package_name>/
  1. 将生成的 C++头文件整合至 ROS API 工程

将第 9 步生成的 C++头文件融入 ROS API 工程,以便在工程中使用自定义消息。

4.2 ROS 接口示例工程目录结构
ROS/
├── CMakeLists.txt   # 工程编译脚本
├── gen_make_debug.sh  # debug 工程编译环境生成脚本
├── gen_make_release.sh  # release 工程编译环境生成脚本
├── include     # 工程头文件
├── lib      # 工程依赖库
├── run      # ROS API 节点可执行程序生成目录
└── src      # ROS API 工程源文件
4.3 ROS 接口示例工程编译

编译 ROS 接口工程需要完成以下几个步骤:

  1. 执行编译脚本

    • 对于调试模式,运行 gen_make_debug.sh 脚本。

    • 对于发布模式,运行 gen_make_release.sh 脚本。

  2. 进入构建目录

    • 对于调试构建,请使用 cd build_debug 命令进入构建目录。

    • 对于发布构建,请使用 cd build_release 命令进入构建目录。

  3. 开始构建项目

    • 在命令行中输入 make 命令开始构建过程。构建完成后,ROS API 节点程序将生成在 run/trans_node_ros 路径下。

5. 运行 ROS 通信节点

要启动并运行 ROS API 节点,请按照以下步骤操作:

  1. 启动 ROS 核心

    • 在命令行中输入 roscore 来启动 ROS 核心服务。

  2. 执行 ROS API 节点程序

    • 运行 trans_node_ros 程序。程序启动时,将根据 config.ini 配置文件中的参数来初始化设置。

    • config.ini 运行参数配置文件

    [BridgeIO] Sim-One API 客户端连接设置
    BridgeIO_IP=10.66.9.111 SimOne BridgeIO 节点 IP
    
    [HostVehicle] Sim-One 仿真主车设置
    Vehicle_ID=0 Sim-One 仿真主车 ID
    
    [Sensor] Sim-One 传感器通信配置
    IMG_IP=10.66.9.244 图像数据 UDP 接收端 IP
    IMG_PORT=13944 图像数据 UDP 接收端 Port
    PCD_IP=10.66.9.244 点云数据 UDP 接收端 IP
    PCD_PORT=6699 点云数据 UDP 接收端 Port
    PCD_PORT_INFO=7788 点云数据 UDP 接收端 InfoPort
    
    [ROS] ROS 消息配置
    GPS_Topic=/gps Gps 消息发布 Topic
    GroundTruth_Topic=/ground_truth 感知物体真值消息发布 Topic
    Image_Topic=/image 图像数据消息发布 Topic
    PointCloud_Topic=/point_cloud 点云数据消息发布 Topic
    Radar_Topic=/radar_detection 毫米波雷达数据消息发布 Topic
    Sensor_Topic=/sensor_detection 目标及传感器真值数据消息发布 Topic
    LaneInfo_Topic=/lane_info 感知车道/车道线数据消息发布 Topic
    CTL_Topic=/control 主车控制(油门/刹车/方向)数据消息订阅 Topic
    POSE_CTL_Topic=/pose_control 主车控制(离散点)数据消息订阅 Topic
    

6. 消息验证

6.1 运行 SimOne 测试案例
  1. SimOne 仿真端操作

    • 启动 Sim-One,新建测试案例

    • 新建测试主车(加载相关传感器,配置控制系统为 手动 / API 控制)

    • 运行案例(选择主车为该主车)

  2. ROS 端操作

    • 运行 SimOne ROS Bridge

    • 启动第三方算法

6.2 图像数据验证
  • 使用 rviz 可视化工具订阅 Image Topic ,以显示实时的图像数据。

6.3 点云数据验证
  • 通过 rviz 订阅 PointCloud Topic ,观察点云图像的实时更新。

6.4 结构化数据验证
  • 执行以下命令来配置环境并监听 ROS 话题以输出实时数据:

  source ~/catkin_ws/devel/setup.bash
  rostopic echo /gps

7. 接口

  1. 通过 Sim-One API 获取仿真感知数据

主车Gps消息回调
bool SetGpsUpdateCB(void(*cb)(const char* mainVehicleId, SimOne_Data_Gps *pGps));
获取仿真感知物体真值回调
bool SetGroundTruthUpdateCB(void(*cb)(const char* mainVehicleId, SimOne_Data_Obstacle *pObstacle));
获取摄像头图像数据回调
bool SetStreamingImageUpdateCB(const  char* ip, unsigned short port, void(*cb)(SimOne_Streaming_Image *pImage));
获取激光雷达点云数据回调
bool SetStreamingPointCloudUpdateCB(const  char* ip, unsigned short port, unsigned short infoPort, void(*cb)(SimOne_Streaming_Point_Cloud *pPointCloud));
获取毫米波雷达目标信息回调
bool SetRadarDetectionsUpdateCB(void(*cb)(const char* mainVehicleId, const char* sensorId, SimOne_Data_RadarDetection *pDetections));
获取目标及传感器真知数据回调
bool SetSensorDetectionsUpdateCB(void(*cb)(const char* mainVehicleId, const char* sensorId, SimOne_Data_SensorDetections *pGroundtruth));
获取感知车道与车道线数据回调
bool GetSensorLaneInfo(const char* mainVehicleId, const char* sensorId, SimOne_Data_LaneInfo *pLaneInfo);
  1. 通过 ROS Publisher 将感知消息发布到相应 Topic 上

发布Gps消息
pub_gps = handle_gps.advertise<msg_gen::gps>(gps_topic.c_str(), 1);
pub_gps_p->publish(gps_d);
发布仿真感知物体真值消息
pub_ground_truth = handle_ground_truth.advertise<msg_gen::obstacle>(ground_truth_topic.c_str(), 1);
pub_ground_truth_p->publish(obstacle_d);
发布摄像头图像数据消息
pub_image = handle_image.advertise<sensor_msgs::Image>(image_topic.c_str(), 1);
pub_image_p->publish(img_d);
发布激光雷达点云数据消息
pub_point_cloud = handle_point_cloud.advertise<sensor_msgs::PointCloud2>(point_cloud_topic.c_str(), 1);
pub_point_cloud_p->publish(point_cloud_d);
发布毫米波雷达目标信息
pub_radar = handle_radar.advertise<msg_gen::radardetection>(radar_topic.c_str(), 1);
pub_radar_p->publish(radar_detection_d);
发布目标及传感器真值消息
pub_sensor = handle_sensor.advertise<msg_gen::sensordetections>(sensor_topic.c_str(), 1);
pub_sensor_p->publish(sensor_detections_d);
发布感知车道/车道线消息
pub_laneinfo = handle_laneinfo.advertise<msg_gen::laneinfo>(lane_info_topic.c_str(), 1);
pub_laneinfo_p->publish(lane_info_d);
  1. 通过 ROS Subscriber 订阅主车控制相关 Topic

订阅主车控制消息离散点 控制
sub_ctl = handle_ctl.subscribe(ctl_topic.c_str(), 1, &ros_trans_node::rcv_ctl_cb, this);
订阅主车控制消息油门/刹车/方向 控制
sub_pose_ctl = handle_pose_ctl.subscribe(pose_ctl_topic.c_str(), 1, &ros_trans_node::rcv_pose_ctl_cb, this);
  1. 通过 Sim-One API 设置主车控制参数

根据离散点设置主车位置
SimOneAPI::SetPose(0, &pose_ctl);
设置主车控制参数
SimOneAPI::SetDrive(vehicle_id.c_str(), pCtrl.get());

API调用参考示例

注意

[SimOne-安装路径]\SimOne\SimOneAPI 中的范例代码根据目录分类,演示了 SimOne 仿真产品的各类 API 在客户本地算法程序中的应用。如需编译参考 算法接入

注意

例如:调用传感器 API 来获取【目标级别】或者是【物理级别】传感器的数据,然后传送到客户的算法程序里面来测试【无人驾驶算法】,客户也可以使用【传感器数据】来作为传感器融合的 raw data。

目录结构如下所示

示例 文件夹 描述 子文件夹 描述
算法示例 ADAS ADAS 基础算法对接 SimOne 仿真平台接口应用示例。 ACC 自适应巡航控制算法示例。
AEB 自动紧急制动算法示例。
AEB-Daemon 云仿真环境连续案例运行 AEB 算法示例。
AEB-Evaluation 以 AEB 算法为例,展示如何在用户算法内输出评价所需要的信号数据。
AVP 自动泊车算法示例。
bin ADAS 算法应用程序生成目录。
Build 用于存放构建和编译项目产生的文件目录。
LKA 自动车道保持巡航算法示例。
TestEvaluation 用于测试和示范如何利用 EvaluationAPI 获取评价所需要的数据。
TrajectoryControl 控制车辆行驶轨迹的系统或算法。
util 包含一系列辅助工具和实用程序的目录。
Autopilot 自动驾驶算法综合 CurveSample 全局路径规划和局部路径调整示例
LimitChangeLaneSample 前方有障碍物示例
TrafficLightSample 获取场景中交通灯的相位状态示例
include 包含 SimOne 自带的库和第三方的调用的依赖库文件,主要包括一些 .h 和 .hpp 。
lib 包含 运行 SimOne 需要依赖的动态库,C++API 的头文件、数据结构文件,PythonAPI 的头文件、数据结构文件,PythonAPI 的算法示例。
适配第三方中间件 Cyber Apollo(r6.0.0)对接 SimOne 仿真平台基于 Cyber 中间件的接口示例。
Matlab SimOneAPI 在 Simulink 中的封装,包含模块接口和示例。
ROS 对接 SimOne 仿真平台基于 ROS1 中间件的接口示例。
ROS2 对接 SimOne 仿真平台基于 ROS2 中间件的接口示例。
SensorRaw 物理级数据可视化接口示例。 3rdparty 第三方插件 opencv,pcl
SensorCamera 物理级摄像头数据传输示例
SensorLidar 物理级激光雷达数据传输示例
SensorLidarROS 物理级激光雷达数据传输至 ROS 示例
SensorRadar4D 4D 毫米波雷达数据传输示例
功能模块示例 Tutorial SimOneAPI C++ 接口基础调用方法示例。 Dynamics 动力学 使用示例
HDMap HDMapAPI 使用示例
PNC PNCAPI 使用示例
Sensor 传感器 使用示例
Traffic 交通流 API 使用示例
V2X V2X 使用示例

1. 算法示例

1.1 ADAS 基础算法
1.1.1 ACC 自适应巡航控制算法

注意

Adaptive Cruise Control(自适应巡航控制),一种可自动调整车速以维持与前车安全距离的系统。

算法构思

自适应巡航控制算法。

算法流程图

添前车行驶车辆。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.1.2 AEB 自动紧急制动算法

注意

Automatic Emergency Braking(自动紧急制动算法),在检测到潜在碰撞风险时,系统会自动执行制动来防止或减轻撞击的后果。

注意

目录在 [SimOne 安装目录]\SimOne\SimOneAPI\ADAS\AEB

注意

紧急刹车演示代码(c++、python)位于 src 文件夹中,您可以参考此代码来考虑接入您的算法到 SimOne 仿真场景中去。

算法构思

获取对手车离主车的距离然后根据 AEB 算法来刹车。

算法流程图

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.1.3 AEB-Daemon

注意

云仿真环境,连续案例运行 AEB 算法示例。

1.1.4 AEB-Evaluation

暂无介绍

1.1.5 AVP 自动泊车算法

注意

Automated Valet Parking(自动代客泊车),指可以自动驾驶汽车前往车位并完成停车的技术。

算法构思

自动泊车算法。

算法流程图

寻找停车区域,然后泊车算法运行。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.1.6 LKA 自动车道保持巡航算法

注意

Lane Keeping Assist(车道保持辅助),指可以帮助驾驶员保持在当前车道的系统。

算法构思

自动车道保持巡航算法。

算法流程图

添加道路中心线的顶点来循迹。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.1.7 TestEvaluation

暂无说明

1.1.8 TrajectoryControl 轨迹控制

注意

ADAS/TrajectoryControl 示例程序演示如何使用轨迹控制主车的运动。

  1. 如何运行该示例

    由于示例程序中的轨迹为固定的,为了运行该示例,需要建立一个案例。

    • 新建一个标准案例进行编辑,下图为案例的配置信息。地图使用 三车道路口 ,主车选择 API 控制 ,主车的初始位置设置为 轨迹开始的位置 ,初始速度为 轨迹第一个点的初始速度

    • 编辑保存后,运行该案例,然后启动示例程序,可以看到车辆沿着程序中定义的轨迹运动,先直线前进 140 米左右向右变道,然后右拐。

  2. 通过轨迹控制主车的 API

    • 轨迹控制主车的 API 原型如下:

    bool SetDriveTrajectory(const char* mainVehicleId, SimOne_Data_Control_Trajectory *pControlTrajectory)
    
    • 用户的 轨迹规划模块 根据主车当前的 位置朝向状态 ,规划出主车接下来的运动轨迹,轨迹包含一系列的 轨迹点 。规划出来的一条轨迹只需要通过 API 发送一次。

    • 每一个 轨迹点 包含:① 车辆期望的位置和朝向(Yaw),② 当前主车的速度、加速度,以及 ③ 该轨迹点相对于当前轨迹起点的相对距离和相对时间。轨迹起点的相对距离和相对时间都为 0。

    • 示例中的三条轨迹是依次连接的,但用户的轨迹可以有重叠的部分,这样也更能保证车辆运动的连贯性。

  3. 轨迹控制的内部实现

    • SimOne 内置了一个控制模块,根据用户轨迹得到车辆的控制信号,然后使用 动力学 控制车辆运动。在该示例中车辆速度恒定为 10 米/秒,所以右转时已经超出了车辆的控制极限,车辆右转时开到轨迹之外,然后由于 控制模块的纠偏 重新回到规划的轨迹上。

1.2 Autopilot 综合算法
1.2.1 CurveSample

算法构思

全局路径规划和局部路径调整,综合演示 SimOne API 的例子。

算法流程图

  1. 全局路径规划:

    • 获取从起点至终点可能路线的道路编号集合( naviRoadIdList ),等同于地图服务商提供的推荐路线。

  1. 局部路径规划( GetReferencePath 函数)

该函数的目的是实时获取主车当前所在的道路编号,并与 naviRoadIdList 进行对比,从而在全局规划的基础上做出局部路径的规划和调整。

  • 获取主车当前车道 :利用 GetNearMostLane 函数,获取车辆当前所在的车道 laneName

  • 添加中心线顶点 :使用 AddSamples 函数,将当前车道的中心线顶点加入到路径变量 path 中,作为路径规划的一部分。

  • 遍历和比较道路编号 :通过 while 循环遍历 naviRoadIdList 中的每个道路编号。对于每个编号,使用 GetValidSuccessor 函数寻找正确的后继道路编号,以实现连续的路径规划。

  • 设计 GetValidSuccessor 函数 :该函数用于找到合适的后继道路编号,并与全局道路规划集合 naviRoadIdList 中的道路编号进行对比,确定局部路径规划的方向。

  1. 路径规划实现细节( GetValidSuccessor 函数实现)

该函数的核心思想是根据当前道路编号及其后继道路编号,查找并确定正确的后继道路,以便于主车继续沿着规划的路径行驶至目的地。这一过程可能涉及递归调用以处理复杂的道路关系。

总结

上述过程结合了全局路径规划与局部路径调整的思路。通过获取全局的道路编号集合( naviRoadIdList )作为规划基线,并设计 GetReferencePath 函数来进行实时路径规划和调整,确保车辆能够根据实时状况,沿着最优路径行驶至目的地。此过程中的 GetValidSuccessor 函数是局部路径规划的关键,它确保车辆可以根据实际情况,选择合适的后继道路,实现精确的导航及行驶。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.2.2 LimitChangeLaneSample

算法构思

算法流程图

计算 A,B,C 点,后将 S->A->B->C->E 作为算法设计的路径

M 点(目标障碍物)投影到车道“1_0_-1”的虚拟中心线得到 B 点

M 点同车道 s 方向后退 30 米,得到 A 点

M 点同车道 s 方向前进 30 米,得到 C 点

M 点(目标障碍物)投影到车道“1_0_-1”的虚拟中心线得到 B 点获取 B 点位置。

A 点到 B 点的插值距离,这里用直线, 你也可以用 Clothoid 螺旋曲线。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

1.2.3 TrafficLightSample

算法构思

获取场景中交通灯的相位状态。

算法流程图

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

2. SimOneAPI 适配第三方中间件

2.1 Cyber

ApolloCybertronBridge 接入方式:

Apollo API 接入方式:

Apollo SimOne 仿真通信接口:

模块 接口功能 数据传输方向 通信通道 Message Channel 消息结构文件 Proto Message Structure
Control 纵向控制(油门刹车方向等) Apollo -> SimOne /apollo/control apollo/modules/control/proto/control_cmd.proto
Planning 导航接口(全局规划轨迹) SimOne -> Apollo /apollo/routing_request apollo/modules/routing/proto/routing.proto
导航消息反馈 Apollo -> SimOne /apollo/routing_response apollo/modules/routing/proto/routing.proto
规划接口(规划轨迹) Apollo -> SimOne /apollo/planning apollo/modules/planning/proto/planning.proto
Canbus 底盘消息(主车状态) SimOne -> Apollo /apollo/canbus/chassis apollo/modules/canbus/proto/chassis.proto
Localizati Imu(角速度、加速度) SimOne -> Apollo /apollo/sensor/gnss/corrected_imu apollo/modules/localization/proto/imu.proto
Gps(车辆位姿、速度) SimOne -> Apollo /apollo/sensor/gnss/odometry apollo/modules/localization/proto/gps.proto
Driver Ins状态 SimOne -> Apollo /apollo/sensor/gnss/ins_stat apollo/modules/drivers/gnss/proto/ins.proto
Perception 障碍物感知 SimOne -> Apollo /apollo/perception/obstacles apollo/modules/perception/proto/perception_obstacle.proto
交通信号灯感知 SimOne -> Apollo /apollo/perception/traffic_light apollo/modules/perception/proto/traffic_light_detection.proto
2.2 Matlab

使用说明

请参考软件在环测试中的 simulink 联合仿真部分。页面位置调整

2.3 ROS

请参考 第三方中间件 ROS

2.4 Sensor_Raw
2.4.1 Camera

用法简述

物理级摄像头数据传输的演示代码,您可以参考此代码来实时发送摄像头仿真图像至您的算法或控制器。

在传感器配置页面正确填写接收端的 ip 和端口,SimOne 将通过 udp 协议发送数据。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

2.4.2 Lidar

用法简述

物理级激光雷达数据传输的演示代码,您可以参考此代码来实时发送激光雷达仿真点云数据至您的算法或控制器。

在传感器配置页面正确填写接收端的 ip 和端口,SimOne 将通过 udp 协议发送数据。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

2.4.3 LidarROS

用法简述

物理级激光雷达数据传输至 ROS 演示代码,您可以参考此代码来实时发送激光雷达仿真点云数据至您的 ROS 系统。

在传感器配置页面正确填写接收端的 ip 和端口,SimOne 将通过 udp 协议发送数据。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

2.4.4 SensorRadar4D

用法简述

4D 毫米波雷达数据传输的演示代码,您可以参考此代码来实时发送 4D 毫米波雷达仿真点云数据至您的算法或控制器。

在传感器配置页面正确填写接收端的 ip 和端口,SimOne 将通过 udp 协议发送数据。

编译环境

  • CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

  • 先运行 gen_vs_proj.bat 生成 Visual Studio 工程位于 build 文件夹 ,再运行 build_release.bat ,最后运行 run_sensor_radar4d_view.bat

使用流程

在 SimOne 中运行案例,在 VS 中运行算法。

3. 功能模块示例 Tutorial

3.1 Dynamics

算法构思

分别使用 SimOneNetAPI 测试配置车辆的加速,制动性能以及操稳。

算法流程图

百公里加速测试; 百公里加速后制动测试; 阶跃,斜坡以及 sine 扫频转向测试。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

  1. 运行案例和测试流程 :在 SimOne 中运行案例,在 VS 中运行算法。

  2. 测试结果保存 :如果指定结果保存路径,测试的结果将在路径下生产 CSV 文件,如果无指定路径,将在默认 exe 路径下保存。

  3. 测试内容 :测试中包含对转向系统的时域扫频测试,可以参照文件中包含的 PostProcessing.m 文件在 MATLAB 中进行频域后处理。

  4. 数据后处理 :在保存数据时,在执行 exe 文件后加上 *-csvPath “文件名.csv” *这样便会在相应路径下生成测试结果。

3.2 HDMap

算法构思

  1. 启动仿真案例 :当 SimOne 仿真案例启动时,系统会生成一个 URL 地址,并发送到 HDMap API 端。

  2. 加载地图文件 :HDMap API 使用接收到的 URL 地址发起 HTTP 请求,从数据平台中加载仿真案例运行时指定的 .xodr 地图文件。地图文件被加载到内存中以供后续使用。

  3. 实时数据提供 :基于主车在静态地图上的动态位置,HDMap API 实时返回关键地图数据给第三方驾驶算法,这些数据包括:地图真值数据、道路路网信息、车道及车道线类型等。

算法流程图

3.2.1 HDMap API

注意

【SimOne 安装位置】/SimOne/SimOneAPI/include/SimOneHDMapAPI.h

  • 获取主车当前位置最近车道示例伪代码:

#include "SimOneServiceAPI.h"
#include "SimOneHDMapAPI.h"
#include "SimOneSensorAPI.h"
#include "SSD/SimPoint3D.h"
#include "SSD/SimString.h"

int main(int argc, char* argv[])
{
        const char* mv_id = "0"; // 主车Id
        bool isJoinTimeLoop = false; // 是否加入帧同步
        const char* serverIP = "127.0.0.1"; // BridgeIO IP

    // Step1: 初始化 SimOne API
    InitSimOneAPI(mv_id, isJoinTimeLoop, serverIP);

    // Step2: 加载高精度地图,地图文件由 SimOne 仿真 Web 端建立案例时指定
        int timeout = 20; // HDMap加载超时时间设置,若超时函数将返回推出
        if (!SimOneAPI::LoadHDMap(timeout)) // 从数据平台获取运行案例地图文件并加载到内存
        {
                std::cout << "LoadHDMap Failed!" << std::endl;
        return 0;
        }

        std::unique_ptr<SimOne_Data_Gps> pGPS = std::make_unique<SimOne_Data_Gps>();
        while (true)
        {
        // Step3: 获取主车GPS信息
                if (!GetGps(0/*vehicleId*/, pGPS.get()))
                {
                        std::cout << "Get GPS Failed!" << std::endl;
                }
        else
        {
            // 传入参数 主车当前位置(3D 点)
            SSD::SimPoint3D pos(pGps->posX, pGps->posY, pGps->posZ);
            // 传出参数 车道线ID,格式为 roadId_sectionIndex_laneId E.g.道路参考线右侧第一条车道表示为“1_0_-1”;左侧第二条车道表示为“1_0_2”
            SSD::SimString laneId;
            // 传出参数 主车位置相对检出车道的s-t坐标值
            double s, t;
            // 传出参数 主车位置相对检出车道所在道路中心线的s-t坐标值 (模糊值),通过调用 GetRoadST API 可获取更为精确的值
            double s_toCenterLine, t_toCenterLine;

            // Step 4: 获取最接近输入点的车道,所属车道优先
            if (!GetNearMostLane(pos, laneId, s, t, s_toCenterLine, t_toCenterLine))
                {
                std::cout << "Error: lane is not found." << std::endl;
                }
            else
            {
                std::cout << "lane id: " << laneId.GetString() << std::endl;;
                std::cout << "s: " << s << "    t: " << t << std::endl;
                std::cout << "s_toCenterLine: " << s_toCenterLine << "  t_toCenterLine: " << t_toCenterLine << std::endl;
            }
        }

                std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }

        return 0;
}

编译环境

  • HDMap API Tutorial 示例工程目录结构

Tutorial
    ├── bin
       ├── DynamicsTest
       ├── HDMap
       ├── logServer.txt
       ├── log_taskImage.txt
       ├── PNCSample
       ├── SensorSample
       └── SensorV2X
    ├── Build
       ├── build_debug.bat
       ├── build_release
       ├── build_release.bat
       ├── CMakeLists.txt
       ├── gen_make_debug.sh
       ├── gen_make_release.sh
       ├── gen_vs_proj_debug.bat
       ├── gen_vs_proj_release.bat
       ├── rebuild_debug.sh
       └── rebuild_release.sh
    ├── HDMap
       ├── CMakeLists.txt
       ├── gen_vs_proj.bat
       ├── include
       ├── src

    bin目标生成目录
    Build: 编译目录
    HDMap: HDMap API 示例源码目录

编译:

CMakeList.txt 支持生成 windows / ubuntu 的项目工程

  • Windows:

    1. 进入 Build 目录,运行 gen_vs_proj_debug.bat gen_vs_proj_release.bat 生成 Visual Studio 工程

    2. 打开 Visual Studio 示例工程, 选择 HDMap 工程编译

  • Linux:

    1. cd Build

    2. ./gen_make_debug.sh (或 ./gen_make_release.sh

    3. cd build_debug (或 cd build_release

    4. make -j4

使用流程

  • 调用相应 HDMap API API 功能支持

  • API 测试:

    • 启动 SimOne,新建测试案例

    • 新建测试主车(配置控制系统为 手动 / API 控制)

    • 运行案例(选择主车为该主车)

    • 编译测试代码,bin 目录下生成可执行文件

    • 运行示例程序 ,查看运行结果

3.3 PNC

算法构思

决策规划控制算法利用多传感器融合后的目标级真值数据,开展相关算法验证。SimOne 仿真主车控制 API 提供了 离散点、油门/刹车/方向、规划轨迹 等驱动方式,算法的控制消息通过 API 将规划控制消息传入 SimOne 仿真系统来验证主车控制结果的准确性。

算法流程图

3.3.1 PNC API
  • 【SimOne 安装位置】/SimOne/SimOneAPI/include/SimOnePNCAPI.h

  • 示例伪代码:

// 主车Id
 const char* mv_id = "0";
 // 是否加入帧同步
 bool isJoinTimeLoop = false;
 // BridgeIO 服务 Ip
     const char* serverIP = "10.66.9.194";
 // 初始化 SimOneAPI
 InitSimOneAPI("0", isJoinTimeLoop, serverIP);

 // 控制方式一: 设置主车位置 API
std::unique_ptr<SimOne_Data_Pose_Control> pPose = std::make_unique<SimOne_Data_Pose_Control>();
[](pPose.get())
{
   // 控制算法输出主车轨迹点,Eg:
  pPose->posX; // Position X on Opendrive (by meter)
  pPose->posY; // Position Y on Opendrive (by meter)
  pPose->posZ; // Position Z on Opendrive (by meter)
  pPose->oriX; // Rotation X on Opendrive (by radian)
  pPose->oriY; // Rotation Y on Opendrive (by radian)
  pPose->oriZ; // Rotation Z on Opendrive (by radian)
  pPose->autoZ; // Automatically set Z according to scene
};
// mainVehicleId[input param]: Vehilcle index, configure order of web UI, starts from 0
// pPose[input param]: Pose to set
 if (!SimOneAPI::SetPose(0, &pose_ctl))
 {
   std::cout << "Set Pose failed!" << std::endl;
 }

// 控制方式二:主车控制 (通过油门、刹车、方向等消息驱动主车(有动力学),控制参数由算法端提供)
std::unique_ptr<SimOne_Data_Control> pCtrl = std::make_unique<SimOne_Data_Control>();
[](pCtrl.get())
{
   // ToDo: 控制算法输出控制消息
   // Eg:
   pCtrl->timestamp; // uint64  时间戳,单位us
   pCtrl->throttleMode = ESimOne_Throttle_Mode::ESimOne_Throttle_Mode_Speed; // vehicle speed, m/s,   in this mode, brake input is ignored
   pCtrl->throttle; // m/s  double 油门开度 0-100。100表示最大油门驱动
   pCtrl->steeringMode = ESimOne_Steering_Mode::ESimOne_Steering_Mode_SteeringWheelAngle; // steering wheel angle, degree
   pCtrl->steering;
   pCtrl->isManualGear = false;
   pCtrl->gear = ESimOne_Gear_Mode::ESimOne_Gear_Mode_Drive; // forward gear for automatic gear
}
// mainVehicleId[input param]: Vehilcle index, configure order of web UI, starts from 0
// pControl[input param]: vehicle control data
 if (!SetDrive(0, pCtrl.get()))
 {
   std::cout << "SetDrive Failed!" << std::endl;
 }

// 控制方式三:主车控制 (通过规划轨迹点驱动主车(有动力学),不可同时使用SetDrive)
std::unique_ptr<SimOne_Data_Control_Trajectory> pTraj = std::make_unique<SimOne_Data_Control_Trajectory>();
[](pTraj.get())
{
   // ToDo: 控制算法输出规划轨迹
   // Eg:
   for (int i = 0; i < pTraj->point_num; i++)
   {
      pTraj->points[i].posx; // position x
      pTraj->points[i].posy; // position y
      pTraj->points[i].speed; // m/s
      pTraj->points[i].accel; // accelelation m/s^2
      pTraj->points[i].theta; // yaw   rad
      pTraj->points[i].kappa; // curvature
      pTraj->points[i].relative_time; // time relative to the first trajectory point
      pTraj->points[i].s; // distance from the first trajectory point
      pTraj->isReverse = false;
   }
}
// mainVehicleId[input param]: Vehilcle index, configure order of web UI, starts from 0
// pControlTrajectory[input param]: vehicle planning trajectory
 if (!SetDriveTrajectory("0", pTraj.get()))
 {
   std::cout << "SetDrive Failed!" << std::endl;
 }

编译环境

  • PNC API Tutorial 示例工程目录结构

Tutorial
 ├── bin
    ├── DynamicsTest
    ├── HDMap
    ├── logServer.txt
    ├── log_taskImage.txt
    ├── PNCSample
    ├── SensorSample
    └── SensorV2X
 ├── Build
    ├── build_debug.bat
    ├── build_release
    ├── build_release.bat
    ├── CMakeLists.txt
    ├── gen_make_debug.sh
    ├── gen_make_release.sh
    ├── gen_vs_proj_debug.bat
    ├── gen_vs_proj_release.bat
    ├── rebuild_debug.sh
    └── rebuild_release.sh
 ├── PNC
    ├── CMakeLists.txt
    ├── gen_vs_proj.bat
    ├── include
    └── src

bin目标生成目录
Build: 编译目录
HDMap: HDMap API 示例源码目录

编译:

CMakeList.txt 支持生成 windows / ubuntu 的项目工程

  • Windows:

    1. 进入 Build 目录,运行 gen_vs_proj_debug.bat gen_vs_proj_release.bat 生成 Visual Studio 工程

    2. 打开 Visual Studio 示例工程, 选择 HDMap 工程编译

  • Linux:

    1. cd Build

    2. ./gen_make_debug.sh (或 ./gen_make_release.sh

    3. cd build_debug (或 cd build_release

    4. make -j4

使用流程

  • API 测试:

    • 启动 SimOne,新建测试案例

    • 新建测试主车(配置控制系统为 手动 / API 控制)

    • 运行案例(选择主车为该主车)

    • 编译测试代码,bin 目录下生成可执行文件

    • 运行示例程序 ,查看运行结果

3.4 Sensor

3.5 Traffic

交通流案例 - 如何使用 DST API 控制

算法构思

动态交通流 API 可以让用户控制场景里面的对手车的轨迹。

算法流程图

对手车的轨迹在外部 json 文件里面配置。

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

使用流程

在场景中需要使用交通流案例,把类型设置为 api。

3.6 V2X
3.6.1 V2XADAS

算法构思

国标中有五种消息 BSM、RSI、RSM、SPAT、MAP 。

缩写 全称 类型 描述 应用场景
BSM Basic Safety Message V2V 包含车辆的基础信息,如速度、方向、刹车状态等。 变道预警、盲区预警、交叉路口碰撞预警等
RSI Road Side Information V2I 路侧信息,用于警示即将到来的事件或路况。 道路施工、限速提示、超速预警、公交车道预警等
RSM Road Safety Message V2I 路侧的安全相关消息,由边缘设备提供。 事件检测警示,如事故、车辆异常、异物侵入等
SPAT Signal Phase and Timing V2I 交通灯的相位与时序信息。 车速引导、绿波带导航等
MAP MAP Message V2I 提供路口地图描述及与交通灯的关系。 辅助 SPAT 消息,提供路口导航与交通灯相位引导

SimOne 仿真 V2X 传感器节点综合仿真系统内部的感知、交通流,路侧设备以及路网等数据,按照国标 V2X 数据格式转换为相应类型的消息,通过 SimOne V2X API 输出给使用了 V2X 消息的 Adas 算法来做训练。

算法流程图

3.6.2 V2XAPI
  • 【SimOne-安装位置】/SimOne/SimOneAPI/include/SimOneV2XAPI.h

  • 示例伪代码:

// 主车Id
 const char* mv_id = "0";
 // 是否加入帧同步
 bool isJoinTimeLoop = false;
 // BridgeIO 服务 Ip
     const char* serverIP = "127.0.0.1";
 // 初始化 SimOneAPI
 InitSimOneAPI("0", isJoinTimeLoop, serverIP);

 // 回调方式获取真值数据
if (IsCallBackMode) {
             auto function = [](const char* mainVehicleId, const char* sensorId, SimOne_Data_V2XNFS *pDetections) {
                     std::cout << "sensorId:" << sensorId << std::endl;
      std::cout <<" SetV2XInfoUpdateCB strlen= " << pDetections->V2XMsgFrameSize << std::endl;
      std::cout  << "MsgFrameData: " << pDetections->MsgFrameData << std::endl;
             };

   // 获得对应车辆编号V2X中的UPER编码之后的v2x消息更新回调
             SetV2XInfoUpdateCB(function);
     }
     else {
             std::unique_ptr<SimOne_Data_V2XNFS> pDetections = std::make_unique<SimOne_Data_V2XNFS>();
             while (true)
   {
                // 获得对应车辆编号V2X中的UPER编码之后的v2x消息
                     if (GetV2XInfo(mv_id, "obu1" /*V2X Sensor ID*/, ESimOne_V2X_MessageFrame_PR::ESimOne_V2X_MessageFrame_PR_rsiFrame /* V2X 消息类型 */, pDetections.get()))
      {
                             std::cout << "GetV2XInfo strlen = " << strlen(pDetections->MsgFrameData) << std::endl;
         std::cout << "MsgFrameData: " << pDetections->MsgFrameData << std::endl;
                             std::this_thread::sleep_for(std::chrono::milliseconds(20));
                     }
                     else {
                             std::cout << "GetV2XInfo Fail" << std::endl;
                     }
                     std::this_thread::sleep_for(std::chrono::milliseconds(10));
             }
     }

编译环境

CMakeList.txt 支持生成 windows / ubuntu 的项目工程。

  • V2X Tutorial 示例工程目录结构

Tutorial
 ├── bin
    ├── DynamicsTest
    ├── HDMap
    ├── logServer.txt
    ├── log_taskImage.txt
    ├── PNCSample
    ├── SensorSample
    └── SensorV2X
 ├── Build
    ├── build_debug.bat
    ├── build_release
    ├── build_release.bat
    ├── CMakeLists.txt
    ├── gen_make_debug.sh
    ├── gen_make_release.sh
    ├── gen_vs_proj_debug.bat
    ├── gen_vs_proj_release.bat
    ├── rebuild_debug.sh
    └── rebuild_release.sh
 └── V2X
     └── V2XADAS

bin目标生成目录
Build: 编译目录
HDMap: HDMap API 示例源码目录

编译:

CMakeList.txt 支持生成 windows / ubuntu 的项目工程

  • Windows:

    1. 进入 Build 目录,运行 gen_vs_proj_debug.bat gen_vs_proj_release.bat 生成 Visual Studio 工程

    2. 打开 Visual Studio 示例工程, 选择 V2X 工程编译

  • Linux:

    1. cd Build

    2. ./gen_make_debug.sh (或 ./gen_make_release.sh

    3. cd build_debug (或 cd build_release

    4. make -j4

使用流程

  • API 测试:

    • 启动 SimOne,新建测试案例(案例交通参与者设置 OBU)

    • 新建测试主车(启用 OBU 配置控制系统为 手动 / API 控制)

    • 运行案例(选择主车为该主车)

    • 编译测试代码,bin 目录下生成可执行文件

    • 运行示例程序 ,查看运行结果