Technical Architecture¶
3.1 Technical Architecture Diagram¶
3.2 Basic Workflow for Autonomous Driving Algorithm Integration¶
Taking Apollo as an example, you can design a bridge program CybertronBridgeApollo to control the start and stop of the Apollo algorithm, automatically configure certain Apollo parameters, and combine it with the SimOne Use Case library to achieve the goal of automated testing.
The main work of the CybertronBridgeApollo bridge program consists of two parts: information to be loaded in advance and data to be transmitted in real time.
-
Control Flow:
-
Before a Use Case runs, certain information must be loaded — for example, specific vehicle parameters, camera configuration parameters, and map data. This type of information varies with different Use Cases or changes to the Ego Vehicle settings, but remains constant during the execution of a Use Case.
-
This type of information is referred to as the "control flow." It must be configured and passed to Apollo before the Use Case starts.
-
-
Data Flow:
-
During Use Case execution, other data is generated in real time — for example, GPS information, Ego Vehicle chassis data, image data, and point cloud data.
-
This type of information is referred to as the "data flow." It must be continuously transmitted to the Apollo algorithm for processing in real time.
-
In this way, CybertronBridgeApollo ensures that the Apollo autonomous driving platform receives all required information and real-time data during test Use Case execution, so that automated testing is carried out correctly. The specific implementation workflow is as follows:
3.3 Algorithm Integration Scenarios Supported by SimOne¶
3.3.1 Decision and Planning Only¶
- Example pseudocode: C++
// Ego Vehicle Id
const char* mv_id = "0";
// Whether to join frame synchronization
bool isJoinTimeLoop = false;
// BridgeIO service IP
const char* serverIP = "127.0.0.1";
// Initialize SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);
// Callback mode: retrieve chassis/GPS data
if (IsCallBackMode)
{
auto function = [](const char* mainVehicleId, SimOne_Data_Gps *pGps){
output_gps(pGps);
};
SetGpsUpdateCB(function);
}
// Non-frame-sync mode: retrieve chassis/GPS data
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));
}
}
// Get Use Case end status
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
// Shut down SimOneAPI
if (!SimOneAPI::TerminateSimOneAPI())
{
std::cout << "TerminateSimOneAPI Failed!" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
// GPS data:
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;
}
// Invoke the third-party decision/planning algorithm to compute control and pose from the retrieved data
{
// Method 1: Move the Ego Vehicle by setting a position point (no dynamics)
std::unique_ptr<SimOne_Data_Pose_Control> pPose = std::make_unique<SimOne_Data_Pose_Control>();
// The following is pseudocode for illustration; not guaranteed to compile
callback(pPose.get())
{
// Generate Ego Vehicle trajectory point, e.g.:
// Position X on Opendrive (by meter)
pPose->posX = m_gps.posX + cos(m_gps.oriZ); // Move 1 meter in X direction from current Ego Vehicle position
// 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;
};
// Method 2: Drive the Ego Vehicle via throttle, brake, and steering messages (with dynamics)
std::unique_ptr<SimOne_Data_Control> pCtrl = std::make_unique<SimOne_Data_Control>();
// The following is pseudocode for illustration; not guaranteed to compile
[](pCtrl.get())
{
// Generate control message, e.g.:
pCtrl->timestamp = getCurrentTime(); // uint64 timestamp in microseconds
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 throttle opening 0-100. 100 means maximum throttle drive
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
}
// Method 3: Drive the Ego Vehicle via planned trajectory points (with dynamics)
std::unique_ptr<SimOne_Data_Control_Trajectory> pTraj = std::make_unique<SimOne_Data_Control_Trajectory>();
// The following is pseudocode for illustration; not guaranteed to compile
[](pTraj.get())
{
// Generate planned trajectory, e.g.:
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;
}
}
/* Control Method 1: Set Ego Vehicle position 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;
}
/* Control Method 2: Ego Vehicle control (drive via throttle, brake, steering, etc. (with dynamics); control parameters provided by the algorithm)
* 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;
}
/* Control Method 3: Ego Vehicle control (drive via planned trajectory points (with dynamics); cannot be used simultaneously with 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 Perception Algorithm Training¶
- Example pseudocode: C++
// Ego Vehicle Id
const char* mv_id = "0";
// Whether to join frame synchronization
bool isJoinTimeLoop = false;
// BridgeIO service IP
const char* serverIP = "YOUR_SERVER_IP"; // Please replace with the actual server address
// Initialize SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);
// Callback mode: retrieve ground truth data
if (IsCallBackMode)
{
auto function = [](const char* mainVehicleId, SimOne_Data_Obstacle *pObstacle) {
output_ground_truth(pObstacle);
};
SetGroundTruthUpdateCB(function);
}
// Non-frame-sync mode: retrieve ground truth data
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));
}
}
// Ground truth data:
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;
}
}
// Get Use Case end status
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
// Shut down SimOneAPI
if (!SimOneAPI::TerminateSimOneAPI())
{
std::cout << "TerminateSimOneAPI Failed!" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
// Camera Node UDP server IP
const char* img_ip = "127.0.0.1";
// Camera Node UDP server port
unsigned short img_port = 123456;
// Callback mode: retrieve physical-level camera sensor data
if (IsCallBackMode)
{
auto function = [](SimOne_Streaming_Image* pImage) {
output_image(pImage);
};
SetStreamingImageUpdateCB(img_ip, img_port, function);
}
// Non-frame-sync mode: retrieve physical-level camera sensor data
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));
}
}
// Image data:
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;
}
}
// LiDAR Node UDP server IP
const char* pcd_ip = "127.0.0.1";
// LiDAR Node UDP server port
unsigned short pcd_port = 123456;
// LiDAR Node UDP server info_port
unsigned short pcd_info_port = 654321;
// Callback mode: retrieve physical-level LiDAR sensor data
if (IsCallBackMode)
{
auto function = [](SimOne_Streaming_Point_Cloud* pPointcloud) {
output_point_cloud(pPointcloud);
};
SetStreamingPointCloudUpdateCB(pcd_ip, pcd_port, pcd_info_port, function);
}
// Non-frame-sync mode: retrieve physical-level LiDAR sensor data
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));
}
}
// Point cloud data:
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
}
// Invoke the third-party perception algorithm to perform perception training on ground truth data and physical-level data
// The following is pseudocode for illustration; not guaranteed to compile
[](pObstacle, pImage, pPointCloud)
{
// Perception training
}
3.3.3 Fusion Algorithm Training¶
- Example pseudocode: C++
// Ego Vehicle Id
const char* mv_id = "0";
// Whether to join frame synchronization
bool isJoinTimeLoop = false;
// BridgeIO service IP
const char* serverIP = "YOUR_SERVER_IP"; // Please replace with the actual server address
// Initialize SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);
// Callback mode: retrieve all ultrasonic radar data
if (IsCallBackMode)
{
auto function = [](const char* mainVehicleId, SimOne_Data_UltrasonicRadars* pUltrasonics)
{
output_ultrasonic_radars(pUltrasonics);
};
SetUltrasonicRadarsCB(function);
}
// Non-frame-sync mode: retrieve all ultrasonic radar data
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));
}
}
// Ultrasonic radar data
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;
}
}
}
// Callback mode: retrieve all millimeter-wave radar data
if (IsCallBackMode)
{
auto function = [](const char* mainVehicleId, const char* sensorId, SimOne_Data_RadarDetection* pRadarData)
{
output_radar_detection(pRadarData);
};
SetRadarDetectionsUpdateCB(function);
}
// Non-frame-sync mode: retrieve all millimeter-wave radar data
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));
}
}
// Millimeter-wave radar data
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;
}
}
// Callback mode: retrieve object-level sensor perception ground truth
if (IsCallBackMode)
{
auto function = [](const char* MainVehicleID, const char* sensorId, SimOne_Data_SensorDetections* pGroundtruth)
{
output_sensor_detections(pGroundtruth);
};
SetSensorDetectionsUpdateCB(function);
}
// Non-frame-sync mode: retrieve object-level sensor perception ground truth
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));
}
}
// Object-level sensor ground truth data
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;
}
}
// Invoke the third-party fusion algorithm to perform fusion processing on object-level data
[](pUltrasonicData, pRadarData, pSensorData)
{
// Fusion processing
}
// Get Use Case end status
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
// Shut down SimOneAPI
if (!SimOneAPI::TerminateSimOneAPI())
{
std::cout << "TerminateSimOneAPI Failed!" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
3.3.4 Closed-Loop Perception, Decision, and Planning¶
- Example pseudocode: C++
// Ego Vehicle Id
const char* mv_id = "0";
// Whether to join frame synchronization
bool isJoinTimeLoop = false;
// BridgeIO service IP
const char* serverIP = "10.66.9.194";
// Initialize SimOneAPI
InitSimOneAPI("0", isJoinTimeLoop, serverIP);
// Invoke the third-party perception algorithm to perform perception training on ground truth data and physical-level data
perception_result = [](pObstacle, pImage, pPointCloud)
{
// Perception training
}
// Invoke the third-party fusion algorithm to perform fusion processing on object-level data
fusion_result = [](perception_result)
{
// Fusion processing
}
// Invoke the third-party decision/planning algorithm to compute control and pose from the retrieved data
{
// Method 1: Move the Ego Vehicle by setting a position point (no dynamics)
[](fusion_result)
{
SimOne_Data_Pose_Control pose_ctl;
...
SimOneAPI::SetPose(0, &pose_ctl))
};
// Method 2: Drive the Ego Vehicle via throttle, brake, steering, etc. (with dynamics)
[](fusion_result)
{
SimOne_Data_Control ctrl;
...
SetDrive(0, &ctrl);
}
// Method 3: Drive the Ego Vehicle via planned trajectory points (with dynamics)
[](pTraj.get())
{
SimOne_Data_Control_Trajectory traj;
...
SetDriveTrajectory("0", &traj);
}
}
// Get Use Case end status
if (SimOneAPI::GetCaseRunStatus() == ESimOne_Case_Status::ESimOne_Case_Status_Stop)
// Shut down SimOneAPI
if (!SimOneAPI::TerminateSimOneAPI())
{
std::cout << "TerminateSimOneAPI Failed!" << std::endl;
}
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}





