# include "selfdrive/modeld/models/driving.h"
# include <fcntl.h>
# include <unistd.h>
# include <cassert>
# include <cstring>
# include <eigen3/Eigen/Dense>
# include "selfdrive/common/clutil.h"
# include "selfdrive/common/params.h"
# include "selfdrive/common/timing.h"
constexpr int DESIRE_PRED_SIZE = 32 ;
constexpr int OTHER_META_SIZE = 48 ;
constexpr int NUM_META_INTERVALS = 5 ;
constexpr int META_STRIDE = 7 ;
constexpr int PLAN_MHP_N = 5 ;
constexpr int PLAN_MHP_COLUMNS = 15 ;
constexpr int PLAN_MHP_VALS = 15 * 33 ;
constexpr int PLAN_MHP_SELECTION = 1 ;
constexpr int PLAN_MHP_GROUP_SIZE = ( 2 * PLAN_MHP_VALS + PLAN_MHP_SELECTION ) ;
constexpr int LEAD_MHP_N = 2 ;
constexpr int LEAD_TRAJ_LEN = 6 ;
constexpr int LEAD_PRED_DIM = 4 ;
constexpr int LEAD_MHP_VALS = LEAD_PRED_DIM * LEAD_TRAJ_LEN ;
constexpr int LEAD_MHP_SELECTION = 3 ;
constexpr int LEAD_MHP_GROUP_SIZE = ( 2 * LEAD_MHP_VALS + LEAD_MHP_SELECTION ) ;
constexpr int POSE_SIZE = 12 ;
constexpr int PLAN_IDX = 0 ;
constexpr int LL_IDX = PLAN_IDX + PLAN_MHP_N * PLAN_MHP_GROUP_SIZE ;
constexpr int LL_PROB_IDX = LL_IDX + 4 * 2 * 2 * 33 ;
constexpr int RE_IDX = LL_PROB_IDX + 8 ;
constexpr int LEAD_IDX = RE_IDX + 2 * 2 * 2 * 33 ;
constexpr int LEAD_PROB_IDX = LEAD_IDX + LEAD_MHP_N * ( LEAD_MHP_GROUP_SIZE ) ;
constexpr int DESIRE_STATE_IDX = LEAD_PROB_IDX + 3 ;
constexpr int META_IDX = DESIRE_STATE_IDX + DESIRE_LEN ;
constexpr int POSE_IDX = META_IDX + OTHER_META_SIZE + DESIRE_PRED_SIZE ;
constexpr int OUTPUT_SIZE = POSE_IDX + POSE_SIZE ;
# ifdef TEMPORAL
constexpr int TEMPORAL_SIZE = 512 ;
# else
constexpr int TEMPORAL_SIZE = 0 ;
# endif
constexpr float FCW_THRESHOLD_5MS2_HIGH = 0.15 ;
constexpr float FCW_THRESHOLD_5MS2_LOW = 0.05 ;
constexpr float FCW_THRESHOLD_3MS2 = 0.7 ;
float prev_brake_5ms2_probs [ 5 ] = { 0 , 0 , 0 , 0 , 0 } ;
float prev_brake_3ms2_probs [ 3 ] = { 0 , 0 , 0 } ;
// #define DUMP_YUV
void model_init ( ModelState * s , cl_device_id device_id , cl_context context ) {
s - > frame = new ModelFrame ( device_id , context ) ;
constexpr int output_size = OUTPUT_SIZE + TEMPORAL_SIZE ;
s - > output . resize ( output_size ) ;
# ifdef USE_THNEED
s - > m = std : : make_unique < ThneedModel > ( " ../../models/supercombo.thneed " , & s - > output [ 0 ] , output_size , USE_GPU_RUNTIME ) ;
# elif USE_ONNX_MODEL
s - > m = std : : make_unique < ONNXModel > ( " ../../models/supercombo.onnx " , & s - > output [ 0 ] , output_size , USE_GPU_RUNTIME ) ;
# else
s - > m = std : : make_unique < SNPEModel > ( " ../../models/supercombo.dlc " , & s - > output [ 0 ] , output_size , USE_GPU_RUNTIME ) ;
# endif
# ifdef TEMPORAL
s - > m - > addRecurrent ( & s - > output [ OUTPUT_SIZE ] , TEMPORAL_SIZE ) ;
# endif
# ifdef DESIRE
s - > m - > addDesire ( s - > pulse_desire , DESIRE_LEN ) ;
# endif
# ifdef TRAFFIC_CONVENTION
const int idx = Params ( ) . getBool ( " IsRHD " ) ? 1 : 0 ;
s - > traffic_convention [ idx ] = 1.0 ;
s - > m - > addTrafficConvention ( s - > traffic_convention , TRAFFIC_CONVENTION_LEN ) ;
# endif
}
ModelDataRaw model_eval_frame ( ModelState * s , cl_mem yuv_cl , int width , int height ,
const mat3 & transform , float * desire_in ) {
# ifdef DESIRE
if ( desire_in ! = NULL ) {
for ( int i = 1 ; i < DESIRE_LEN ; i + + ) {
// Model decides when action is completed
// so desire input is just a pulse triggered on rising edge
if ( desire_in [ i ] - s - > prev_desire [ i ] > .99 ) {
s - > pulse_desire [ i ] = desire_in [ i ] ;
} else {
s - > pulse_desire [ i ] = 0.0 ;
}
s - > prev_desire [ i ] = desire_in [ i ] ;
}
}
# endif
//for (int i = 0; i < OUTPUT_SIZE + TEMPORAL_SIZE; i++) { printf("%f ", s->output[i]); } printf("\n");
// if getInputBuf is not NULL, net_input_buf will be
auto net_input_buf = s - > frame - > prepare ( yuv_cl , width , height , transform , static_cast < cl_mem * > ( s - > m - > getInputBuf ( ) ) ) ;
s - > m - > execute ( net_input_buf , s - > frame - > buf_size ) ;
// net outputs
ModelDataRaw net_outputs ;
net_outputs . plan = & s - > output [ PLAN_IDX ] ;
net_outputs . lane_lines = & s - > output [ LL_IDX ] ;
net_outputs . lane_lines_prob = & s - > output [ LL_PROB_IDX ] ;
net_outputs . road_edges = & s - > output [ RE_IDX ] ;
net_outputs . lead = & s - > output [ LEAD_IDX ] ;
net_outputs . lead_prob = & s - > output [ LEAD_PROB_IDX ] ;
net_outputs . meta = & s - > output [ DESIRE_STATE_IDX ] ;
net_outputs . pose = & s - > output [ POSE_IDX ] ;
return net_outputs ;
}
void model_free ( ModelState * s ) {
delete s - > frame ;
}
static const float * get_best_data ( const float * data , int size , int group_size , int offset ) {
int max_idx = 0 ;
for ( int i = 1 ; i < size ; i + + ) {
if ( data [ ( i + 1 ) * group_size + offset ] >
data [ ( max_idx + 1 ) * group_size + offset ] ) {
max_idx = i ;
}
}
return & data [ max_idx * group_size ] ;
}
static const float * get_plan_data ( float * plan ) {
return get_best_data ( plan , PLAN_MHP_N , PLAN_MHP_GROUP_SIZE , - 1 ) ;
}
static const float * get_lead_data ( const float * lead , int t_offset ) {
return get_best_data ( lead , LEAD_MHP_N , LEAD_MHP_GROUP_SIZE , t_offset - LEAD_MHP_SELECTION ) ;
}
void fill_sigmoid ( const float * input , float * output , int len , int stride ) {
for ( int i = 0 ; i < len ; i + + ) {
output [ i ] = sigmoid ( input [ i * stride ] ) ;
}
}
void fill_lead_v3 ( cereal : : ModelDataV2 : : LeadDataV3 : : Builder lead , const float * lead_data , const float * prob , int t_offset , float prob_t ) {
float t [ LEAD_TRAJ_LEN ] = { 0.0 , 2.0 , 4.0 , 6.0 , 8.0 , 10.0 } ;
const float * data = get_lead_data ( lead_data , t_offset ) ;
lead . setProb ( sigmoid ( prob [ t_offset ] ) ) ;
lead . setProbTime ( prob_t ) ;
float x_arr [ LEAD_TRAJ_LEN ] ;
float y_arr [ LEAD_TRAJ_LEN ] ;
float v_arr [ LEAD_TRAJ_LEN ] ;
float a_arr [ LEAD_TRAJ_LEN ] ;
float x_stds_arr [ LEAD_TRAJ_LEN ] ;
float y_stds_arr [ LEAD_TRAJ_LEN ] ;
float v_stds_arr [ LEAD_TRAJ_LEN ] ;
float a_stds_arr [ LEAD_TRAJ_LEN ] ;
for ( int i = 0 ; i < LEAD_TRAJ_LEN ; i + + ) {
x_arr [ i ] = data [ i * LEAD_PRED_DIM + 0 ] ;
y_arr [ i ] = data [ i * LEAD_PRED_DIM + 1 ] ;
v_arr [ i ] = data [ i * LEAD_PRED_DIM + 2 ] ;
a_arr [ i ] = data [ i * LEAD_PRED_DIM + 3 ] ;
x_stds_arr [ i ] = exp ( data [ LEAD_MHP_VALS + i * LEAD_PRED_DIM + 0 ] ) ;
y_stds_arr [ i ] = exp ( data [ LEAD_MHP_VALS + i * LEAD_PRED_DIM + 1 ] ) ;
v_stds_arr [ i ] = exp ( data [ LEAD_MHP_VALS + i * LEAD_PRED_DIM + 2 ] ) ;
a_stds_arr [ i ] = exp ( data [ LEAD_MHP_VALS + i * LEAD_PRED_DIM + 3 ] ) ;
}
lead . setT ( t ) ;
lead . setX ( x_arr ) ;
lead . setY ( y_arr ) ;
lead . setV ( v_arr ) ;
lead . setA ( a_arr ) ;
lead . setXStd ( x_stds_arr ) ;
lead . setYStd ( y_stds_arr ) ;
lead . setVStd ( v_stds_arr ) ;
lead . setAStd ( a_stds_arr ) ;
}
void fill_meta ( cereal : : ModelDataV2 : : MetaData : : Builder meta , const float * meta_data ) {
float desire_state_softmax [ DESIRE_LEN ] ;
float desire_pred_softmax [ 4 * DESIRE_LEN ] ;
softmax ( & meta_data [ 0 ] , desire_state_softmax , DESIRE_LEN ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
softmax ( & meta_data [ DESIRE_LEN + OTHER_META_SIZE + i * DESIRE_LEN ] ,
& desire_pred_softmax [ i * DESIRE_LEN ] , DESIRE_LEN ) ;
}
float gas_disengage_sigmoid [ NUM_META_INTERVALS ] ;
float brake_disengage_sigmoid [ NUM_META_INTERVALS ] ;
float steer_override_sigmoid [ NUM_META_INTERVALS ] ;
float brake_3ms2_sigmoid [ NUM_META_INTERVALS ] ;
float brake_4ms2_sigmoid [ NUM_META_INTERVALS ] ;
float brake_5ms2_sigmoid [ NUM_META_INTERVALS ] ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 1 ] , gas_disengage_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 2 ] , brake_disengage_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 3 ] , steer_override_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 4 ] , brake_3ms2_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 5 ] , brake_4ms2_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
fill_sigmoid ( & meta_data [ DESIRE_LEN + 6 ] , brake_5ms2_sigmoid , NUM_META_INTERVALS , META_STRIDE ) ;
//fill_sigmoid(&meta_data[DESIRE_LEN+7], GAS PRESSED, NUM_META_INTERVALS, META_STRIDE);
std : : memmove ( prev_brake_5ms2_probs , & prev_brake_5ms2_probs [ 1 ] , 4 * sizeof ( float ) ) ;
std : : memmove ( prev_brake_3ms2_probs , & prev_brake_3ms2_probs [ 1 ] , 2 * sizeof ( float ) ) ;
prev_brake_5ms2_probs [ 4 ] = brake_5ms2_sigmoid [ 0 ] ;
prev_brake_3ms2_probs [ 2 ] = brake_3ms2_sigmoid [ 0 ] ;
bool above_fcw_threshold = true ;
for ( int i = 0 ; i < 5 ; i + + ) {
float threshold = i < 2 ? FCW_THRESHOLD_5MS2_LOW : FCW_THRESHOLD_5MS2_HIGH ;
above_fcw_threshold = above_fcw_threshold & & prev_brake_5ms2_probs [ i ] > threshold ;
}
for ( int i = 0 ; i < 3 ; i + + ) {
above_fcw_threshold = above_fcw_threshold & & prev_brake_3ms2_probs [ i ] > FCW_THRESHOLD_3MS2 ;
}
auto disengage = meta . initDisengagePredictions ( ) ;
disengage . setT ( { 2 , 4 , 6 , 8 , 10 } ) ;
disengage . setGasDisengageProbs ( gas_disengage_sigmoid ) ;
disengage . setBrakeDisengageProbs ( brake_disengage_sigmoid ) ;
disengage . setSteerOverrideProbs ( steer_override_sigmoid ) ;
disengage . setBrake3MetersPerSecondSquaredProbs ( brake_3ms2_sigmoid ) ;
disengage . setBrake4MetersPerSecondSquaredProbs ( brake_4ms2_sigmoid ) ;
disengage . setBrake5MetersPerSecondSquaredProbs ( brake_5ms2_sigmoid ) ;
meta . setEngagedProb ( sigmoid ( meta_data [ DESIRE_LEN ] ) ) ;
meta . setDesirePrediction ( desire_pred_softmax ) ;
meta . setDesireState ( desire_state_softmax ) ;
meta . setHardBrakePredicted ( above_fcw_threshold ) ;
}
void fill_xyzt ( cereal : : ModelDataV2 : : XYZTData : : Builder xyzt , const float * data ,
int columns , int column_offset , float * plan_t_arr , bool fill_std ) {
float x_arr [ TRAJECTORY_SIZE ] = { } ;
float y_arr [ TRAJECTORY_SIZE ] = { } ;
float z_arr [ TRAJECTORY_SIZE ] = { } ;
float x_std_arr [ TRAJECTORY_SIZE ] ;
float y_std_arr [ TRAJECTORY_SIZE ] ;
float z_std_arr [ TRAJECTORY_SIZE ] ;
float t_arr [ TRAJECTORY_SIZE ] ;
for ( int i = 0 ; i < TRAJECTORY_SIZE ; i + + ) {
// column_offset == -1 means this data is X indexed not T indexed
if ( column_offset > = 0 ) {
t_arr [ i ] = T_IDXS [ i ] ;
x_arr [ i ] = data [ i * columns + 0 + column_offset ] ;
x_std_arr [ i ] = data [ columns * ( TRAJECTORY_SIZE + i ) + 0 + column_offset ] ;
} else {
t_arr [ i ] = plan_t_arr [ i ] ;
x_arr [ i ] = X_IDXS [ i ] ;
x_std_arr [ i ] = NAN ;
}
y_arr [ i ] = data [ i * columns + 1 + column_offset ] ;
y_std_arr [ i ] = data [ columns * ( TRAJECTORY_SIZE + i ) + 1 + column_offset ] ;
z_arr [ i ] = data [ i * columns + 2 + column_offset ] ;
z_std_arr [ i ] = data [ columns * ( TRAJECTORY_SIZE + i ) + 2 + column_offset ] ;
}
xyzt . setX ( x_arr ) ;
xyzt . setY ( y_arr ) ;
xyzt . setZ ( z_arr ) ;
xyzt . setT ( t_arr ) ;
if ( fill_std ) {
xyzt . setXStd ( x_std_arr ) ;
xyzt . setYStd ( y_std_arr ) ;
xyzt . setZStd ( z_std_arr ) ;
}
}
void fill_model ( cereal : : ModelDataV2 : : Builder & framed , const ModelDataRaw & net_outputs ) {
// plan
const float * best_plan = get_plan_data ( net_outputs . plan ) ;
float plan_t_arr [ TRAJECTORY_SIZE ] ;
std : : fill_n ( plan_t_arr , TRAJECTORY_SIZE , NAN ) ;
plan_t_arr [ 0 ] = 0.0 ;
for ( int xidx = 1 , tidx = 0 ; xidx < TRAJECTORY_SIZE ; xidx + + ) {
// increment tidx until we find an element that's further away than the current xidx
while ( tidx < TRAJECTORY_SIZE - 1 & & best_plan [ ( tidx + 1 ) * PLAN_MHP_COLUMNS ] < X_IDXS [ xidx ] ) {
tidx + + ;
}
float current_x_val = best_plan [ tidx * PLAN_MHP_COLUMNS ] ;
float next_x_val = best_plan [ ( tidx + 1 ) * PLAN_MHP_COLUMNS ] ;
if ( next_x_val < X_IDXS [ xidx ] ) {
// if the plan doesn't extend far enough, set plan_t to the max value (10s), then break
plan_t_arr [ xidx ] = T_IDXS [ TRAJECTORY_SIZE - 1 ] ;
break ;
} else {
// otherwise, interpolate to find `t` for the current xidx
float p = ( X_IDXS [ xidx ] - current_x_val ) / ( next_x_val - current_x_val ) ;
plan_t_arr [ xidx ] = p * T_IDXS [ tidx + 1 ] + ( 1 - p ) * T_IDXS [ tidx ] ;
}
}
fill_xyzt ( framed . initPosition ( ) , best_plan , PLAN_MHP_COLUMNS , 0 , plan_t_arr , true ) ;
fill_xyzt ( framed . initVelocity ( ) , best_plan , PLAN_MHP_COLUMNS , 3 , plan_t_arr , false ) ;
fill_xyzt ( framed . initOrientation ( ) , best_plan , PLAN_MHP_COLUMNS , 9 , plan_t_arr , false ) ;
fill_xyzt ( framed . initOrientationRate ( ) , best_plan , PLAN_MHP_COLUMNS , 12 , plan_t_arr , false ) ;
// lane lines
auto lane_lines = framed . initLaneLines ( 4 ) ;
float lane_line_probs_arr [ 4 ] ;
float lane_line_stds_arr [ 4 ] ;
for ( int i = 0 ; i < 4 ; i + + ) {
fill_xyzt ( lane_lines [ i ] , & net_outputs . lane_lines [ i * TRAJECTORY_SIZE * 2 ] , 2 , - 1 , plan_t_arr , false ) ;
lane_line_probs_arr [ i ] = sigmoid ( net_outputs . lane_lines_prob [ i * 2 + 1 ] ) ;
lane_line_stds_arr [ i ] = exp ( net_outputs . lane_lines [ 2 * TRAJECTORY_SIZE * ( 4 + i ) ] ) ;
}
framed . setLaneLineProbs ( lane_line_probs_arr ) ;
framed . setLaneLineStds ( lane_line_stds_arr ) ;
// road edges
auto road_edges = framed . initRoadEdges ( 2 ) ;
float road_edge_stds_arr [ 2 ] ;
for ( int i = 0 ; i < 2 ; i + + ) {
fill_xyzt ( road_edges [ i ] , & net_outputs . road_edges [ i * TRAJECTORY_SIZE * 2 ] , 2 , - 1 , plan_t_arr , false ) ;
road_edge_stds_arr [ i ] = exp ( net_outputs . road_edges [ 2 * TRAJECTORY_SIZE * ( 2 + i ) ] ) ;
}
framed . setRoadEdgeStds ( road_edge_stds_arr ) ;
// meta
fill_meta ( framed . initMeta ( ) , net_outputs . meta ) ;
// leads
auto leads = framed . initLeadsV3 ( LEAD_MHP_SELECTION ) ;
float t_offsets [ LEAD_MHP_SELECTION ] = { 0.0 , 2.0 , 4.0 } ;
for ( int t_offset = 0 ; t_offset < LEAD_MHP_SELECTION ; t_offset + + ) {
fill_lead_v3 ( leads [ t_offset ] , net_outputs . lead , net_outputs . lead_prob , t_offset , t_offsets [ t_offset ] ) ;
}
}
void model_publish ( PubMaster & pm , uint32_t vipc_frame_id , uint32_t frame_id , float frame_drop ,
const ModelDataRaw & net_outputs , uint64_t timestamp_eof ,
float model_execution_time , kj : : ArrayPtr < const float > raw_pred ) {
const uint32_t frame_age = ( frame_id > vipc_frame_id ) ? ( frame_id - vipc_frame_id ) : 0 ;
MessageBuilder msg ;
auto framed = msg . initEvent ( ) . initModelV2 ( ) ;
framed . setFrameId ( vipc_frame_id ) ;
framed . setFrameAge ( frame_age ) ;
framed . setFrameDropPerc ( frame_drop * 100 ) ;
framed . setTimestampEof ( timestamp_eof ) ;
framed . setModelExecutionTime ( model_execution_time ) ;
if ( send_raw_pred ) {
framed . setRawPredictions ( raw_pred . asBytes ( ) ) ;
}
fill_model ( framed , net_outputs ) ;
pm . send ( " modelV2 " , msg ) ;
}
void posenet_publish ( PubMaster & pm , uint32_t vipc_frame_id , uint32_t vipc_dropped_frames ,
const ModelDataRaw & net_outputs , uint64_t timestamp_eof ) {
float trans_arr [ 3 ] ;
float trans_std_arr [ 3 ] ;
float rot_arr [ 3 ] ;
float rot_std_arr [ 3 ] ;
for ( int i = 0 ; i < 3 ; i + + ) {
trans_arr [ i ] = net_outputs . pose [ i ] ;
trans_std_arr [ i ] = exp ( net_outputs . pose [ 6 + i ] ) ;
rot_arr [ i ] = net_outputs . pose [ 3 + i ] ;
rot_std_arr [ i ] = exp ( net_outputs . pose [ 9 + i ] ) ;
}
MessageBuilder msg ;
auto posenetd = msg . initEvent ( vipc_dropped_frames < 1 ) . initCameraOdometry ( ) ;
posenetd . setTrans ( trans_arr ) ;
posenetd . setRot ( rot_arr ) ;
posenetd . setTransStd ( trans_std_arr ) ;
posenetd . setRotStd ( rot_std_arr ) ;
posenetd . setTimestampEof ( timestamp_eof ) ;
posenetd . setFrameId ( vipc_frame_id ) ;
pm . send ( " cameraOdometry " , msg ) ;
}