开发者手册
主要包含【开发者上手】、【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 接口 | 功能 |
---|---|---|
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
桥接程序的主要工作包括两部分:
准备加载的信息
和
实时传递的数据。
-
控制流 :
-
在案例运行之前,必须加载某些信息,例如 车辆的具体参数、相机配置参数、地图 等。这类信息随着案例的不同或主车设置的变化而变化,但在案例运行过程中则保持不变。
-
这类信息被称作“控制流”,它们需要在案例启动之前预先设置好并传递给 Apollo。
-
-
数据流 :
-
案例运行时会实时产生另一些数据,例如 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 坐标系统
对于高精度地图而言,系统提供两种坐标系统:
-
世界坐标系/站心直角坐标系(Local ENU) 世界坐标系为 x,y,z 右手坐标系
惯例适用于地理参考,即对应站心直角坐标系,x 为正东(East,E),y 为正北(North,N),z 为 Up(U)。
-
参考线坐标系/轨道系统 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 系统中的帧同步是基于虚拟时间的逻辑帧,这意味着整个系统的操作都是按帧进行的:
-
帧同步的概念:
-
系统中的每个动作都依赖于逻辑帧的执行。
-
一帧的执行时间在现实中可以很短(如 0.00001 秒)或很长(如 100000 秒),而与真实时间解耦。
-
通过基于帧的时间控制,可以灵活地调节仿真系统的运行速度,例如加速或减缓案例运行。
-
-
获取 SimOne 数据的方法:
-
回调函数 :当系统有新数据时,系统会通过注册的回调函数通知用户获取数据。
-
主动调用 API :用户可以主动调用 API(如:GetGps)来获取当前帧的数据。如果系统帧没有进步,连续调用将返回相同的数据。
-
-
帧同步和数据获取的结合:
-
使用帧同步 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++算法接入
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
2.2 算法示例程序生成
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 创建用例
-
新建用例 ,选择 标准用例 ,填入 用例名称 。
2.3.2 编辑用例,加载算法主车
-
选择 地图 和 主车预设 ,可设置主车的 速度 为 10m/s。
-
拖入对手元素,尽量与主车保持一定距离,可设置其 速度 为 0 m/s ,然后点击 保存 用例。
2.3.3 运行用例,验证控制算法
-
点击 运行用例 ,将 默认控制器 和 自驾控制器 设置为 API 算法 ,然后点击 创建 ,运行用例。
-
进入用例之后用例仿真运行时间不会变化, 横纵向算法显示为 loading… ,此时用例在 等待接入算法状态 。
-
保证 AEB.exe 在用例运行前打开 ,若成功接入则在渲染视窗中会 展现算法效果 (例如 接入 AEB 算法后主车会在对手元素后一段距离减速至 0 m/s),且 横纵向算法 也会以此改变。
2.4 前端算法管理(可选)
可将不同的算法进行前端管理,方便调用,参见 软件在环测试 。
3. 上手教程 Ubuntu
注意
从源代码编译
Linux 安装包附随带有 API 使用示例: SimOneAPI.tar.gz
3.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
-
添加环境变量 。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/SimOneApi库目录 (比如/SimOne/SimOneAPI/lib/Linux64)
3.2 生成算法工程
-
在 SimOne 的安装包中找到算法示例包 SimOneAPI.tar.gz 。
-
进入 SimOne 安装目录 /SimOne/ 执行
tar -xvf SimOneAPI.tar.gz
解压算法示例包。
-
进入 SimOne 安装目录中的 /SimOne/SimOneAPI/ADAS/Bulid ,执行命令
bash gen_make_release.sh
生成工程目录 。
-
在此目录再次执行 命令
bash rebuild_release.sh
命令 生成可执行文件 ,并在 /SimOne/ SimOneAPI/ADAS/bin 目录当中查看 可执行文件 AEB 。
-
添加 SimOneAPI 环境变量,需要根据安装位置改变。
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/SimOneApi库目录 (比如/SimOne/SimOneAPI/lib/Linux64)
-
执行算法,如
./AEB
。
3.3 创建案例
-
案例库 新建 文件夹 ,点击 新建案例 。
-
选择 标准案例 ,然后点击 下一步 。
-
输入 案例名称 ,点击 创建 案例。
-
点击 主车预设 ,拖入 API 控制主车 ,拖入视窗。
-
点击 保存 和 运行案例 并 创建任务 。
-
查看算法接入状态,接入 纵向横向控制器 都显示 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 命令行执行
-
运行一个案例:
python xxx.py --category_name='入门案例' --case_name='构建标准案例2.0'
-
运行一个案例并选择主车:
python xxx.py --category_name='入门案例' --case_name='构建标准案例2.0' --vehicle_name='手动控制-默认'
-
运行案例库中所有的案例:
python xxx.py --category_name='入门案例'
-
运行案例库中所有的案例并选择主车:
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 接口 | 功能 |
---|---|---|
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 文档 直接点击链接即可。
-
API调用参考示例 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 基本概念
-
坐标系统 :对于高精度地图而言,系统提供 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 坐标系
-
车道标识符 :高精度地图中的
laneName
为车道提供了唯一标识,结合道路编号、路段索引和车道编号,实现了精准的车道信息查询和定位。-
标识符格式 :
$roadId_sectionIndex_laneId
-
$roadId
: 道路的唯一编号。 -
_sectionIndex
: 道路中特定路段的索引,用于标识道路的不同部分。 -
_laneId
: 车道编号,在每个路段中独一无二。
-
例如:
-
"1_0_-1"
表示道路编号为 1 的路段索引 0 上的右侧第一条车道( 负号表示右侧 )。 -
"1_0_2"
表示同一路段上左侧的第二条车道( 正号表示左侧 )。
-
-
坐标转换 :LocalENU(x,y,z) 坐标和 [s,t] 坐标相互转换
-
Road 参考线体系下的 [s,t] 坐标
-
定义: 以 道路参考线 为基准线,参考线右侧 t 值为负,左侧 t 值为正
-
例子: * *P(-51.5,-73.5)对应 Road 1 的[s,t]坐标系的值是(7,-5.25)
-
-
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)
-
-
-
定位障碍物 :使用 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
|
第三方中间件 Simulink
1. SimOneModule 介绍
1.1 时间同步模块
连接 SimOne 与 Simulink,SimOneAPI 接口初始化,联合仿真时必需的模块。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
IP | int* | 四位长的数组,每一位对应 SimOne 所在的 IP 地址的一节 |
FrameSync | int | 0 或 1,是否启用帧同步,0 表示不启用,1 表示启用 |
输出
无
1.2 主车模块
基于 SimOne 动力学的控制方式,输入油门刹车方向盘等信号,输出车辆位置姿态等信息。
输入
参数 | 类型 | 备注 |
---|---|---|
throttleMode | enum | 油门输入模式,0 百分比,1 发动机扭矩,2 速度,3 加速度,4 发动机转速,5 轮胎扭矩。2、3 模式下忽略刹车输入 |
throttleIn | float | 油门输入,不同模式下输入范围不一致,仅提供单位作为参考,0[0 1],1Nm,2m/s,3m/s^2 ,4rpm,5Nm |
brakeMode | enum | 刹车输入模式,0 百分比,1 主缸压力,2 踏板力,3 轮缸压力,4 轮胎扭矩 |
brakeIn | float | 刹车输入,不同模式下输入范围不一致,仅提供单位作为参考,0[0 1],1MPa,2N,3MPa,4Nm |
steeringMode | enum | 方向盘输入模式,0 百分比,1 角度,2 力矩,3 角速度,4 轮胎角度,5 轮胎角速度 |
steeringIn | float | 方向盘输入,负值左转,正值右转,不同模式下输入范围不一致,仅提供单位作为参考,0[-1 1],1deg,2Nm,3deg/s,4deg,5deg/s |
handbrake | bool | 手刹,默认 false,即没拉手刹 |
isMaunualGear | bool | 是否手动档,默认 false,即自动档 |
gearIn | int | 档位模式输入,0 空挡,1 前进档,2 倒挡 |
throttle_input_data | float* | 油门输入模式 5 模式下的输入数据,此时会忽略 throttleIn 中的数据 |
brake_input_data | float* | 刹车输入模式 3、4 模式下的输入数据,此时会忽略 brakeIn 中的数据 |
steering_input_data | float* | 方向盘输入模式 4、5 模式下的输入数据,此时会忽略 steeringIn 中的数据 |
参数
参数 | 类型 | 备注 |
---|---|---|
DataSize | int | throttle_input_data、brake_input_data、steering_input_data 的数据长度,默认为 0 |
输出
参数 | 类型 | 备注 |
---|---|---|
posXYZ | float | 主车位置 XYZ,单位 m |
oriXYZ | float | 主车旋转 XYZ,单位 rad |
velXYZ | float | 主车速度 XYZ,单位 m/s |
throttleOut | float | 油门输出,百分比模式,[0 1] |
brakeOut | float | 刹车输出,百分比模式,[0 1] |
steeringOut | float | 方向盘输出,百分比模式,[-1 1] |
gearOut | int | 档位输出,-2 驻车档,-1 倒车档,0 空档,1、2 等参照真实车辆档位 |
accelXYZ | float | 主车加速度 XYZ,单位 m/s^2 |
angvelXYZ | float | 主车角速度 XYZ,单位 rad/s |
wheelSpeed | float* | 主车轮速,依次为 FL 前左,FR 前右,RL 后左,RR 后右,单位 m/s |
engineRpm | float | 发动机转速,单位 rpm |
odometer | float | 里程计,单位 m |
1.3 主车模块(位置控制)
无视 SimOne 动力学的控制方式,直接输入车辆的位置姿态,输出车辆位置姿态等信息。
输入
参数 | 类型 | 备注 |
---|---|---|
posIn | float | 主车位置 XYZ,单位 m |
oriIn | float | 主车旋转 XYZ,单位 rad |
autoZ | bool | 根据场景自动设置车辆高度,默认 false |
输出
输出等同于主车模块
1.4 驾驶员模块
输入
无
参数
无
输出
参数 | 类型 | 备注 |
---|---|---|
throttle | float | 油门输出,[0 1] |
brake | float | 刹车输出,[0 1] |
steeringMode | enum | 方向盘模式,0 百分比,1 角度,2 力矩,3 角速度,4 轮胎角度,5 轮胎角速度 |
steering | float | 方向盘输出,负值左转,正值右转,[-1 1] |
handbrake | bool | 手刹,默认 false,即没拉手刹 |
isMaunualGear | bool | 是否手动档,默认 false,即自动档 |
gear | int | 档位输出,-2 驻车档,-1 倒车档,0 空档,1、2 等参照真实车辆档位 |
1.5 障碍物模块(GroundTruth,不需配置传感器)
注意:目前障碍物检测距离为 100m
获取障碍物的真实信息,采用读取内部数据的方式获取障碍物。
输入
无
参数
参数 | 备注 |
---|---|
ObstacleNum | 最多检测障碍物个数 |
ObstacleId | 障碍物检测 ID,从 1 开始 |
输出
参数 | 类型 | 备注 |
---|---|---|
id | int | 障碍物在 SimOne 中的 ID,从 11 开始 |
type | enum | 参见下面障碍物种类说明 |
theta | float | 障碍物绕 Z 轴旋转角度,单位 rad |
posXYZ | float | 障碍物位置 XYZ,单位 m |
velXYZ | float | 障碍物速度 XYZ,单位 m/s |
length | float | 障碍物 BoundingBox 长度,单位 m |
width | float | 障碍物 BoundingBox 宽度,单位 m |
height | float | 障碍物 BoundingBox 高度,单位 m |
accelXYZ | float | 障碍物加速度 XYZ,单位 m/s^2 |
障碍物种类说明
enum SimOne_Obstacle_Type {
ESimOne_Obstacle_Type_Unknown = 0,
ESimOne_Obstacle_Type_Pedestrian = 4,
ESimOne_Obstacle_Type_Pole = 5,
ESimOne_Obstacle_Type_Car = 6,
ESimOne_Obstacle_Type_Static = 7,
ESimOne_Obstacle_Type_Bicycle = 8,
ESimOne_Obstacle_Type_Fence = 9,
ESimOne_Obstacle_Type_RoadMark = 12,
ESimOne_Obstacle_Type_TrafficSign = 13,
ESimOne_Obstacle_Type_TrafficLight = 15,
ESimOne_Obstacle_Type_Rider = 17,
ESimOne_Obstacle_Type_Truck = 18,
ESimOne_Obstacle_Type_Bus = 19,
ESimOne_Obstacle_Type_SpecialVehicle = 20,
ESimOne_Obstacle_Type_Motorcycle = 21,
ESimOne_Obstacle_Type_Dynamic = 22,
ESimOne_Obstacle_Type_GuardRail = 23,
ESimOne_Obstacle_Type_SpeedLimitSign = 26,
ESimOne_Obstacle_Type_BicycleStatic = 27,
ESimOne_Obstacle_Type_RoadObstacle = 29
};
1.6 摄像头模块(配置摄像头传感器)
对应 SimOne 的物理级摄像头,可以获取到摄像头中的数据。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
IP | int* | 4 位数组对应 4 节 IP 地址,与 SimOne 页面传感器设置匹配 |
Port | int | 端口号,与 SimOne 页面传感器设置匹配 |
CameraId | int | 摄像头 ID,SimOne 页面赋予传感器的 ID,已内置 ID 的英文部分 |
HorizontalResolution | int | 摄像头图像水平分辨率,与 SimOne 页面传感器设置匹配 |
VerticalResolution | int | 摄像头图像垂直分辨率,与 SimOne 页面传感器设置匹配 |
输出
参数 | 类型 | 备注 |
---|---|---|
format | int | 图像格式,0forRGB,现只支持 RGB |
width | int | 图像宽度,SimOne 传感器设置,1920max |
length | int | 图像长度,SimOne 传感器设置,1080max |
R、G、B | uint8 | 图像数据,VideoViewer 可以查看摄像头图像数据 |
1.7 激光雷达模块(配置激光雷达传感器)
对应 SimOne 的物理级激光雷达,可以获取到点云数据。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
IP | int* | 4 位数组对应 4 节 IP 地址,与 SimOne 页面传感器设置匹配 |
Port | int* | 2 位数组对应 2 节端口号,与 SimOne 页面传感器设置匹配 |
LidarId | int | 激光雷达 ID,SimOne 页面赋予传感器的 ID,已内置 ID 的英文部分 |
PointCloudDataSize | int | 点云数据大小,与 SimOne 网页传感器设置匹配 |
输出
参数 | 类型 | 备注 |
---|---|---|
width | int | 点云图像宽度,SimOne 传感器配置 |
length | int | 点云图像长度,SimOne 传感器配置 |
pointStep | int | 单个点云所占字节,SimOne 传感器配置 |
pointCloudData | uint8* | 点云数据数组,3686400max |
1.8 毫米波雷达模块(配置毫米波雷达传感器)
对应 SimOne 的目标级毫米波雷达,可以获取到探测范围内的障碍物信息,输出毫米波雷达索引对应的障碍物信息。
输入
无
参数
参数 | 备注 |
---|---|
RadarId | 毫米波雷达 ID |
RadarDetectNum | 毫米波雷达目标检测数量上限 |
RadarDetectionsId | 毫米波雷达检测目标索引,从 1 开始 |
输出
参数 | 类型 | 备注 |
---|---|---|
id | int | 目标在 SimOne 中的 ID |
subId | int | 目标 SubID |
type | int | 参见障碍物模块种类说明 |
posXYZ | float | 目标位置 XYZ,单位 m |
velXYZ | float | 目标速度 XYZ,单位 m/s |
range | float | 目标距离,单位 m |
rangeRate | float | 目标相对速度,单位 m/s |
azimuth | float | 目标方位角,单位 rad |
vertical | float | 目标高度角,单位 rad |
snrdb | float | 信噪比,单位 db |
rcsdb | float | 目标散射截面,单位 db |
probability | float | 目标检测概率 |
1.9 超声波雷达模块(配置超声波雷达传感器)
对应 SimOne 的目标级毫米波雷达,可以获取到探测范围内所有的障碍物信息,输出所有障碍物的信息。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
UltrasonicRadarId | int | 超声波雷达 ID |
UltrasonicDetectNum | int | 超声波雷达目标检测数量上限 |
输出
参数 | 类型 | 备注 |
---|---|---|
obstacleRanges | float* | 目标相对距离,单位 m |
1.10 V2X 模块(配置 OBU 传感器)
对应 SimOne 的目标级 OBU 传感器,可以获取并输出 V2X 信息。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
SensorId | int | OBU 传感器 ID |
InfoType | enum | V2X 信息类型,1BSM,2MAP,3RSM,4SPAT,5RSI |
MaxDataSize | int | V2X 消息字节上限 |
输出
参数 | 类型 | 备注 |
---|---|---|
V2XMsgFrameSize | int | V2X 消息实际字节数 |
MsgFrameData | int* | V2X 消息的 ASCII 码 |
1.11 传感器配置信息模块
获取全部传感器信息,输出传感器索引对应的传感器信息。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
SensorNum | int | 传感器数量上限 |
SensorConfigld | int | 传感器索引,从 1 开始 |
输出
参数 | 类型 | 备注 |
---|---|---|
index | int | 传感器总 ID |
mainVehicle | int | 装配此传感器的主车 ID |
sensorld | int | 传感器 ID,数字部分的 ASCII 码 |
sensorType | int8* | 传感器种类,英文部分的 ASCII 码 |
posXYZ | float | 传感器位置 XYZ,单位 m |
oriXYZ | float | 传感器旋转 XYZ,单位 rad |
hz | int | 传感器频率 |
1.12 传感器检测模块
获取指定传感器的检测信息,输出传感器检测目标索引对应的障碍物信息。
输入
无
参数
参数 | 类型 | 备注 |
---|---|---|
Sensorld | int | 传感器 ID |
SensorDetectNum | int | 传感器检测数量上限 |
SensorDetectionsld | int | 传感器检测目标索引,从 1 开始 |
输出
参数 | 类型 | 备注 |
---|---|---|
id | int | 目标在 SimOne 中的 ID,从 1 开始 |
type | int | 参见障碍物模块种类说明 |
posXYZ | float | 目标位置 XYZ,单位 m |
oriXYZ | float | 目标旋转 XYZ,单位 rad |
length | float | 目标 BoundingBox 长度,单位 m |
width | float | 目标 BoundingBox 宽度,单位 m |
height | float | 目标 BoundingBox 高度,单位 m |
range | float | 目标相对距离,单位 m |
velXYZ | float | 目标速度 XYZ,单位 m/s |
probability | float | 目标检测概率 |
relativePosXYZ | float | 目标相对位置 XYZ,单位 m |
relativeVelXYZ | float | 目标相对速度 XYZ,单位 m/s |
2. HDMapModule 介绍
HDMapModule 各个模块,可满足联合仿真对于高精地图信息的需求。
关于各个模块功能,双击模块即可详见模块介绍:
3. Simulink 联合仿真代码生成
在现有 SimOne 与 Simulink 联合仿真的基础上,用户可以将 Simulink 联合仿真模型生成代码并编译成可执行文件,在本地或者云端运行。(注:此流程需要源码,如 有需求请咨询 SimOne 客服或销售人员)
3.1 Windows
注:下述打包过程需要本地安装 Visual Studio 或者相应的 C/C++编译器
在 Windows 的 Matlab 上配置好联合仿真环境,加入
SimOneModule
和
HDMapMoudle
中的相应模块以及自定义的算法模块并确保能够正确仿真,下图是一个简单例子:
注意
在上述 Simulink Models 文件的所属路径下需要包含相应模块的 mex 文件以及 src 文件,含有参数的 S-function 还需要包含 Matlabtlc 文件。
从 Simulation 菜单打开 Model Configuration Parameters 界面
3.1.1 配置参数
在
Configuration
窗口,在左侧列表中选择
Code
Generation
标签并展开,进行如下配置:
-
选择
Code Generation
本身,-
将
Target selection
-
System target file
设置成grt.tlc(Create Visual C/C++ Solution File for Simulink Coder)
-
Language
选择C++
;
-
-
同时注意一下
Makefile configuration
下的Template makefile
是RTW.MSVCBuild
;
-
-
左侧选中
Optimization
标签,右侧选项Default parameter behavior
设置成Tunable
,方便在 VS 工程中调整 s-function 参数。
-
左侧选中
Code Generation
下的Interface
标签,右侧选项Code Interface
设置成Nonreusable function
因为打包成一个可执行文件,所以不存在代码复用。
-
左侧选中
Code Generation
下的Custom Code
标签,右侧选项Include directories
中添加头文件所在路径(SimOne 的 Matlab->Simulink 文件夹所在路径
和SDK->include 文件夹所在的路径
)
-
在
Source files
中输入SimOne s-function
模块对应的源文件(使用到的S-Function
的名字_wrapper.cpp
文件)
-
在
Libraries
中输入 Simulink 文件夹下的静态库文件(HDMapModule.lib、SSD.lib
和SimOneSMAPI.lib
)以及项目依赖的其它库。
-
左侧选中
Solver
标签,右侧选项Solver Selection
->Type
选择Fixed-step
,选项Fixed-step size
推荐设置为 0.01。
3.1.2 生成 Visual Studio 工程
完成上述 Simulink Coder 配置后,通过点击菜单
Code
->
C/C++
Code
选择
Build
Model
或使用快捷键
Ctrl+B
来生成代码。
-
Simulink 将自动生成对应的 Visual Studio 工程,并存储在路径
Simulink Models/grt_rtw
下。 -
如果代码生成成功,生成的 Visual Studio 工程将自动打开。
3.1.3 在 Visual Studio 中编译生成可执行程序
-
调整 Windows SDK 配置
根据需要针对不同的 Windows SDK 版本进行配置调整:
-
设置仿真参数
在 Visual Studio 的 Simulink 项目中,
-
使用与 Simulink 模型(
.slx
)同名的.cpp
文件中的rtmSetTFinal
函数来指定仿真运行时间。 -
在
slx文件名_data.cpp
中设置仿真所需要的参数和控制输入。
-
处理 S-function 输出
在
sfun_函数名.cpp
文件中实现该 S-function 模块,并输出模块结果。
-
关于可执行文件的运行 为了成功运行打包后的可执行文件,
-
确保在可执行文件所在路径下包括了所有必要的
.dll
文件,这些是联合仿真所依赖的动态库。
注意
在 Simulation 的
Model
Configuration
Parameters
->
Code
Generation
->
Target
selection
中也可以选择
grt.tlc
(Generic
Real-Time
Target)
,这样 Matlab 会直接调用编译器在
Simulink
Models
路径下直接编译生成对应的可执行文件。但是,这种方式不允许修改仿真时间和相应的输入输出参数。
3.2 Linux
在 Linux 上编译 Windows 生成的代码
-
拷贝源文件:
-
将在 Windows 环境下通过 Simulink 生成的代码(包括
.h
头文件和.cpp
源文件)复制到 Linux 系统上。 -
将这些源文件放到 SimOne 仿真环境的 Matlab 路径下,特别是放入自定义的
grt_rtw
文件夹中。
-
-
修改 Makefile:
-
使用 SimOne 提供的 Makefile 模板对原有的 Makefile 进行必要的修改,以适配 Linux 系统和编译环境。
-
-
在 Linux 进行编译:
-
在含有源代码和修改过的 Makefile 的目录下,运行
make
命令来编译代码,生成 Linux 平台的可执行文件。
-
-
运行可执行文件:
-
为了在 Linux 系统上运行编译好的可执行文件,需要确保可执行文件目录下包含了所需的
.so
动态链接库文件。这些文件提供了联合仿真必需的库和依赖。
-
注意
上述打包过程需要**本地安装 Matlab(Makefile 中的 Matlab 路径需要和安装路径匹配) 以及 gcc/g++**或者相应的 C/C++编译器
第三方中间件 ROS
1. 数据交互流程概述
-
获取仿真感知数据 :ROS API 负责从 SimOne 仿真平台中收集感知数据。
-
数据转换 :收集到的仿真感知数据被转换成标准的 ROS 消息格式。
-
发布消息到 ROS Topic :转换后的数据被发布到指定的 ROS 话题(Topic)上供进一步使用。
-
驾驶算法订阅处理 :驾驶算法模块订阅这些话题,并将数据传入规控/感知模块,进行算法训练和处理。
-
发布控制消息 :算法处理后,生成的控制消息被发布到仿真主车控制话题上。
-
通信闭环完成控制 :ROS API 捕捉这些控制消息,并将其作为参数传入 SimOne 仿真主车的动力学节点。这样便驱动了仿真场景中主车的具体行动。
-
算法验证和调试 :驾驶算法可以选择订阅特定的话题消息来验证局部模块的准确性。此外,通过在 ROS 环境中建立一个闭环系统,可以实现对驾驶算法整体性能的综合验证。
2. 数据通信流程简图
3. 软件环境
-
编程语言 :C++
4. 编译环境
4.1 ROS Msg 消息转换
将 SimOne API 数据格式转为 ROS 可发布/订阅的标准数据格式。
-
编写 ROS msg 消息文件
根据 SimOne API 接口数据,参照 C++数据类型与 ROS msg 数据类型的映射关系,编写对应的 ROS API msg 消息文件。
-
创建 ROS 工程 Workspace
执行以下命令创建 ROS 工程 Workspace:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
-
创建功能包
执行以下命令
cd ~/catkin_ws/src
catkin_create_pkg <package_name> roscpp std_msgs
-
添加 msg 消息文件至功能包
将编写好的 msg 消息文件放入功能包的指定目录下:
mkdir ~/catkin_ws/src/<package_name>/msg
-
添加功能依赖
在
~/catkin_ws/src/<package_name>/package.xml
文件中添加功能依赖:
<build_dependmessage_generation</build_depend<exec_dependmessage_runtime</exec_depend
-
修改 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
)
-
编译功能包
返回到 catkin_ws 目录并编译功能包:
cd ~/catkin_ws
catkin_make
-
编译整个工作空间
为确保整个工作空间构建成功,再次执行:
cd ~/catkin_ws
catkin_make
-
检查 C++头文件
检查 msg 文件生成的 C++头文件是否位于以下目录中:
~/catkin_ws/devel/include/<package_name>/
-
将生成的 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 接口工程需要完成以下几个步骤:
-
执行编译脚本 :
-
对于调试模式,运行
gen_make_debug.sh
脚本。 -
对于发布模式,运行
gen_make_release.sh
脚本。
-
-
进入构建目录 :
-
对于调试构建,请使用
cd build_debug
命令进入构建目录。 -
对于发布构建,请使用
cd build_release
命令进入构建目录。
-
-
开始构建项目 :
-
在命令行中输入
make
命令开始构建过程。构建完成后,ROS API 节点程序将生成在run/trans_node_ros
路径下。
-
5. 运行 ROS 通信节点
要启动并运行 ROS API 节点,请按照以下步骤操作:
-
启动 ROS 核心 :
-
在命令行中输入
roscore
来启动 ROS 核心服务。
-
-
执行 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 测试案例
-
SimOne 仿真端操作
-
启动 Sim-One,新建测试案例
-
新建测试主车(加载相关传感器,配置控制系统为 手动 / API 控制)
-
运行案例(选择主车为该主车)
-
-
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. 接口
-
通过 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);
-
通过 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);
-
通过 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);
-
通过 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 示例程序演示如何使用轨迹控制主车的运动。
-
如何运行该示例
由于示例程序中的轨迹为固定的,为了运行该示例,需要建立一个案例。
-
新建一个标准案例进行编辑,下图为案例的配置信息。地图使用 三车道路口 ,主车选择 API 控制 ,主车的初始位置设置为 轨迹开始的位置 ,初始速度为 轨迹第一个点的初始速度 。
-
编辑保存后,运行该案例,然后启动示例程序,可以看到车辆沿着程序中定义的轨迹运动,先直线前进 140 米左右向右变道,然后右拐。
-
-
通过轨迹控制主车的 API
-
轨迹控制主车的 API 原型如下:
bool SetDriveTrajectory(const char* mainVehicleId, SimOne_Data_Control_Trajectory *pControlTrajectory)
-
用户的 轨迹规划模块 根据主车当前的 位置朝向状态 ,规划出主车接下来的运动轨迹,轨迹包含一系列的 轨迹点 。规划出来的一条轨迹只需要通过 API 发送一次。
-
每一个 轨迹点 包含:① 车辆期望的位置和朝向(Yaw),② 当前主车的速度、加速度,以及 ③ 该轨迹点相对于当前轨迹起点的相对距离和相对时间。轨迹起点的相对距离和相对时间都为 0。
-
示例中的三条轨迹是依次连接的,但用户的轨迹可以有重叠的部分,这样也更能保证车辆运动的连贯性。
-
-
轨迹控制的内部实现
-
SimOne 内置了一个控制模块,根据用户轨迹得到车辆的控制信号,然后使用 动力学 控制车辆运动。在该示例中车辆速度恒定为 10 米/秒,所以右转时已经超出了车辆的控制极限,车辆右转时开到轨迹之外,然后由于 控制模块的纠偏 重新回到规划的轨迹上。
-
1.2 Autopilot 综合算法
1.2.1 CurveSample
算法构思
全局路径规划和局部路径调整,综合演示 SimOne API 的例子。
算法流程图
-
全局路径规划:
-
获取从起点至终点可能路线的道路编号集合(
naviRoadIdList
),等同于地图服务商提供的推荐路线。
-
-
局部路径规划(
GetReferencePath
函数)
该函数的目的是实时获取主车当前所在的道路编号,并与
naviRoadIdList
进行对比,从而在全局规划的基础上做出局部路径的规划和调整。
-
获取主车当前车道 :利用
GetNearMostLane
函数,获取车辆当前所在的车道laneName
。 -
添加中心线顶点 :使用
AddSamples
函数,将当前车道的中心线顶点加入到路径变量path
中,作为路径规划的一部分。 -
遍历和比较道路编号 :通过
while
循环遍历naviRoadIdList
中的每个道路编号。对于每个编号,使用GetValidSuccessor
函数寻找正确的后继道路编号,以实现连续的路径规划。 -
设计
GetValidSuccessor
函数 :该函数用于找到合适的后继道路编号,并与全局道路规划集合naviRoadIdList
中的道路编号进行对比,确定局部路径规划的方向。
-
路径规划实现细节(
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 的项目工程。
使用流程
-
运行案例和测试流程 :在 SimOne 中运行案例,在 VS 中运行算法。
-
测试结果保存 :如果指定结果保存路径,测试的结果将在路径下生产 CSV 文件,如果无指定路径,将在默认 exe 路径下保存。
-
测试内容 :测试中包含对转向系统的时域扫频测试,可以参照文件中包含的 PostProcessing.m 文件在 MATLAB 中进行频域后处理。
-
数据后处理 :在保存数据时,在执行 exe 文件后加上 *-csvPath “文件名.csv” *这样便会在相应路径下生成测试结果。
3.2 HDMap
算法构思
-
启动仿真案例 :当 SimOne 仿真案例启动时,系统会生成一个 URL 地址,并发送到 HDMap API 端。
-
加载地图文件 :HDMap API 使用接收到的 URL 地址发起 HTTP 请求,从数据平台中加载仿真案例运行时指定的
.xodr
地图文件。地图文件被加载到内存中以供后续使用。 -
实时数据提供 :基于主车在静态地图上的动态位置,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:
-
进入 Build 目录,运行
gen_vs_proj_debug.bat
或gen_vs_proj_release.bat
生成 Visual Studio 工程 -
打开 Visual Studio 示例工程, 选择 HDMap 工程编译
-
-
Linux:
-
cd Build
-
./gen_make_debug.sh
(或./gen_make_release.sh
) -
cd build_debug
(或cd build_release
) -
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:
-
进入 Build 目录,运行
gen_vs_proj_debug.bat
或gen_vs_proj_release.bat
生成 Visual Studio 工程 -
打开 Visual Studio 示例工程, 选择 HDMap 工程编译
-
-
Linux:
-
cd Build
-
./gen_make_debug.sh
(或./gen_make_release.sh
) -
cd build_debug
(或cd build_release
) -
make -j4
-
使用流程
-
API 测试:
-
启动 SimOne,新建测试案例
-
新建测试主车(配置控制系统为 手动 / API 控制)
-
运行案例(选择主车为该主车)
-
编译测试代码,bin 目录下生成可执行文件
-
运行示例程序 ,查看运行结果
-
3.4 Sensor
3.5 Traffic
算法构思
动态交通流 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:
-
进入 Build 目录,运行
gen_vs_proj_debug.bat
或gen_vs_proj_release.bat
生成 Visual Studio 工程 -
打开 Visual Studio 示例工程, 选择 V2X 工程编译
-
-
Linux:
-
cd Build
-
./gen_make_debug.sh
(或./gen_make_release.sh
) -
cd build_debug
(或cd build_release
) -
make -j4
-
使用流程
-
API 测试:
-
启动 SimOne,新建测试案例(案例交通参与者设置 OBU)
-
新建测试主车(启用 OBU 配置控制系统为 手动 / API 控制)
-
运行案例(选择主车为该主车)
-
编译测试代码,bin 目录下生成可执行文件
-
运行示例程序 ,查看运行结果
-