#include #include #include #include #include #include "common/timing.h" #include "common/params.h" #include "driving.h" #define MIN_VALID_LEN 10.0 #define TRAJECTORY_SIZE 33 #define TRAJECTORY_TIME 10.0 #define TRAJECTORY_DISTANCE 192.0 #define PLAN_IDX 0 #define LL_IDX PLAN_IDX + PLAN_MHP_N*(PLAN_MHP_GROUP_SIZE) #define LL_PROB_IDX LL_IDX + 4*2*2*33 #define RE_IDX LL_PROB_IDX + 4 #define LEAD_IDX RE_IDX + 2*2*2*33 #define LEAD_PROB_IDX LEAD_IDX + LEAD_MHP_N*(LEAD_MHP_GROUP_SIZE) #define DESIRE_STATE_IDX LEAD_PROB_IDX + 3 #define META_IDX DESIRE_STATE_IDX + DESIRE_LEN #define POSE_IDX META_IDX + OTHER_META_SIZE + DESIRE_PRED_SIZE #define OUTPUT_SIZE POSE_IDX + POSE_SIZE #ifdef TEMPORAL #define TEMPORAL_SIZE 512 #else #define TEMPORAL_SIZE 0 #endif // #define DUMP_YUV Eigen::Matrix vander; float X_IDXS[TRAJECTORY_SIZE]; float T_IDXS[TRAJECTORY_SIZE]; void model_init(ModelState* s, cl_device_id device_id, cl_context context, int temporal) { frame_init(&s->frame, MODEL_WIDTH, MODEL_HEIGHT, device_id, context); s->input_frames = (float*)calloc(MODEL_FRAME_SIZE * 2, sizeof(float)); const int output_size = OUTPUT_SIZE + TEMPORAL_SIZE; s->output = (float*)calloc(output_size, sizeof(float)); s->m = new DefaultRunModel("../../models/supercombo.dlc", s->output, output_size, USE_GPU_RUNTIME); #ifdef TEMPORAL assert(temporal); s->m->addRecurrent(&s->output[OUTPUT_SIZE], TEMPORAL_SIZE); #endif #ifdef DESIRE s->prev_desire = std::make_unique(DESIRE_LEN); s->pulse_desire = std::make_unique(DESIRE_LEN); s->m->addDesire(s->pulse_desire.get(), DESIRE_LEN); #endif #ifdef TRAFFIC_CONVENTION s->traffic_convention = std::make_unique(TRAFFIC_CONVENTION_LEN); s->m->addTrafficConvention(s->traffic_convention.get(), TRAFFIC_CONVENTION_LEN); bool is_rhd = Params().read_db_bool("IsRHD"); if (is_rhd) { s->traffic_convention[1] = 1.0; } else { s->traffic_convention[0] = 1.0; } #endif // Build Vandermonde matrix for(int i = 0; i < TRAJECTORY_SIZE; i++) { for(int j = 0; j < POLYFIT_DEGREE - 1; j++) { X_IDXS[i] = (TRAJECTORY_DISTANCE/1024.0) * (pow(i,2)); T_IDXS[i] = (TRAJECTORY_TIME/1024.0) * (pow(i,2)); vander(i, j) = pow(X_IDXS[i], POLYFIT_DEGREE-j-1); } } } ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform, void* sock, 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"); float *new_frame_buf = frame_prepare(&s->frame, q, yuv_cl, width, height, transform); memmove(&s->input_frames[0], &s->input_frames[MODEL_FRAME_SIZE], sizeof(float)*MODEL_FRAME_SIZE); memmove(&s->input_frames[MODEL_FRAME_SIZE], new_frame_buf, sizeof(float)*MODEL_FRAME_SIZE); s->m->execute(s->input_frames, MODEL_FRAME_SIZE*2); #ifdef DUMP_YUV FILE *dump_yuv_file = fopen("/sdcard/dump.yuv", "wb"); fwrite(new_frame_buf, MODEL_HEIGHT*MODEL_WIDTH*3/2, sizeof(float), dump_yuv_file); fclose(dump_yuv_file); assert(1==2); #endif clEnqueueUnmapMemObject(q, s->frame.net_input, (void*)new_frame_buf, 0, NULL, NULL); // 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) { free(s->output); free(s->input_frames); frame_free(&s->frame); delete s->m; } void poly_fit(float *in_pts, float *in_stds, float *out, int valid_len) { // References to inputs Eigen::Map > pts(in_pts, valid_len); Eigen::Map > std(in_stds, valid_len); Eigen::Map > p(out, POLYFIT_DEGREE - 1); float y0 = pts[0]; pts = pts.array() - y0; // Build Least Squares equations Eigen::Matrix lhs = vander.topRows(valid_len).array().colwise() / std.array(); Eigen::Matrix rhs = pts.array() / std.array(); // Improve numerical stability Eigen::Matrix scale = 1. / (lhs.array()*lhs.array()).sqrt().colwise().sum(); lhs = lhs * scale.asDiagonal(); // Solve inplace p = lhs.colPivHouseholderQr().solve(rhs); // Apply scale to output p = p.transpose() * scale.asDiagonal(); out[3] = y0; } void fill_path(cereal::ModelData::PathData::Builder path, const float * data, float valid_len, int valid_len_idx) { float points_arr[TRAJECTORY_SIZE]; float stds_arr[TRAJECTORY_SIZE]; float poly_arr[POLYFIT_DEGREE]; float std; for (int i=0; i= 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]; } //kj::ArrayPtr x_std(x_std_arr, TRAJECTORY_SIZE); //kj::ArrayPtr y_std(y_std_arr, TRAJECTORY_SIZE); //kj::ArrayPtr z_std(z_std_arr, TRAJECTORY_SIZE); xyzt.setX(x_arr); xyzt.setY(y_arr); xyzt.setZ(z_arr); //xyzt.setXStd(x_std); //xyzt.setYStd(y_std); //xyzt.setZStd(z_std); xyzt.setT(t_arr); } void model_publish_v2(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &net_outputs, const float* raw_pred, uint64_t timestamp_eof, float model_execution_time) { // make msg MessageBuilder msg; auto framed = msg.initEvent().initModelV2(); uint32_t frame_age = (frame_id > vipc_frame_id) ? (frame_id - vipc_frame_id) : 0; 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.setRawPred(kj::arrayPtr((const uint8_t*)raw_pred, (OUTPUT_SIZE+TEMPORAL_SIZE)*sizeof(float))); } // plan int plan_mhp_max_idx = 0; for (int i=1; i net_outputs.plan[(plan_mhp_max_idx + 1)*(PLAN_MHP_GROUP_SIZE) - 1]) { plan_mhp_max_idx = i; } } float * best_plan = &net_outputs.plan[plan_mhp_max_idx*(PLAN_MHP_GROUP_SIZE)]; float plan_t_arr[TRAJECTORY_SIZE]; for (int i=0; i net_outputs.lead[(mdn_max_idx + 1)*(LEAD_MHP_GROUP_SIZE) + t_offset - LEAD_MHP_SELECTION]) { mdn_max_idx = i; fill_lead_v2(leads[t_offset], &net_outputs.lead[mdn_max_idx*(LEAD_MHP_GROUP_SIZE)], sigmoid(net_outputs.lead_prob[t_offset]), t_offsets[t_offset]); } } } pm.send("modelV2", msg); } void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, uint32_t vipc_dropped_frames, float frame_drop, const ModelDataRaw &net_outputs, const float* raw_pred, uint64_t timestamp_eof, float model_execution_time) { uint32_t frame_age = (frame_id > vipc_frame_id) ? (frame_id - vipc_frame_id) : 0; MessageBuilder msg; auto framed = msg.initEvent().initModel(); 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.setRawPred(kj::arrayPtr((const uint8_t*)raw_pred, (OUTPUT_SIZE+TEMPORAL_SIZE)*sizeof(float))); } // Find the distribution that corresponds to the most probable plan int plan_mhp_max_idx = 0; for (int i=1; i net_outputs.plan[(plan_mhp_max_idx + 1)*(PLAN_MHP_GROUP_SIZE) - 1]) { plan_mhp_max_idx = i; } } // x pos at 10s is a good valid_len float valid_len = 0; float valid_len_candidate; for (int i=1; i= valid_len){ valid_len = valid_len_candidate; } } // clamp to 10 and MODEL_PATH_DISTANCE valid_len = fmin(MODEL_PATH_DISTANCE, fmax(MIN_VALID_LEN, valid_len)); int valid_len_idx = 0; for (int i=1; i= X_IDXS[valid_len_idx]){ valid_len_idx = i; } } auto lpath = framed.initPath(); fill_path(lpath, &net_outputs.plan[plan_mhp_max_idx*(PLAN_MHP_GROUP_SIZE)], valid_len, valid_len_idx); auto left_lane = framed.initLeftLane(); int ll_idx = 1; fill_lane_line(left_lane, net_outputs.lane_lines, ll_idx, valid_len, valid_len_idx, sigmoid(net_outputs.lane_lines_prob[ll_idx])); auto right_lane = framed.initRightLane(); ll_idx = 2; fill_lane_line(right_lane, net_outputs.lane_lines, ll_idx, valid_len, valid_len_idx, sigmoid(net_outputs.lane_lines_prob[ll_idx])); // Find the distribution that corresponds to the current lead int mdn_max_idx = 0; int t_offset = 0; for (int i=1; i net_outputs.lead[(mdn_max_idx + 1)*(LEAD_MHP_GROUP_SIZE) + t_offset - 3]) { mdn_max_idx = i; } } fill_lead(framed.initLead(), &net_outputs.lead[mdn_max_idx*(LEAD_MHP_GROUP_SIZE)], sigmoid(net_outputs.lead_prob[t_offset])); // Find the distribution that corresponds to the lead in 2s mdn_max_idx = 0; t_offset = 1; for (int i=1; i net_outputs.lead[(mdn_max_idx + 1)*(LEAD_MHP_GROUP_SIZE) + t_offset - 3]) { mdn_max_idx = i; } } fill_lead(framed.initLeadFuture(), &net_outputs.lead[mdn_max_idx*(LEAD_MHP_GROUP_SIZE)], sigmoid(net_outputs.lead_prob[t_offset])); fill_meta(framed.initMeta(), net_outputs.meta); pm.send("model", msg); } void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, uint32_t vipc_dropped_frames, float frame_drop, 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); }