96 int n_cams = vcc_read_vio_cam_conf_file(vio_cams,
MAX_CAM_CNT, 1);
101 Eigen::Matrix4d T_imu_body = Eigen::Matrix4d::Identity();
104 vcc_extrinsic_t body_imu_ext;
106 if (vcc_fetch_extrinsic(
"body", vio_cams[0].imu, &body_imu_ext) != 0)
108 fprintf(stderr,
"Failed to fetch body->%s extrinsic. IMU body mode requires this extrinsic to be defined.\n", vio_cams[0].imu);
113 printf(
"\n[INFO] IMU body mode enabled - loading body->%s transformation\n", vio_cams[0].imu);
114 printExtrinsic(body_imu_ext);
118 Eigen::Vector3d t_imu_wrt_body(
119 body_imu_ext.T_child_wrt_parent[0],
120 body_imu_ext.T_child_wrt_parent[1],
121 body_imu_ext.T_child_wrt_parent[2]
123 const Eigen::Matrix<double,3,3,Eigen::RowMajor> R_imu_to_body(&body_imu_ext.R_child_to_parent[0][0]);
126 T_imu_body.block<3,3>(0,0) = R_imu_to_body.transpose();
127 T_imu_body.block<3,1>(0,3) = -R_imu_to_body.transpose() * t_imu_wrt_body;
130 printf(
"\n[INFO] T_imu_body transformation matrix (body->imu):\n");
131 std::cout << T_imu_body << std::endl;
136 for (
int i = 0; i < n_cams; i++)
138 if (!vio_cams[i].is_extrinsic_present)
140 fprintf(stderr,
"failed to find extrinsic config for vio cam %s\n", vio_cams[i].name);
143 if (!vio_cams[i].is_cal_present)
145 fprintf(stderr,
"failed to find cam cal for vio cam %s\n", vio_cams[i].name);
158 for (
int i = 1; i < n_cams; i++)
160 if (strcmp(vio_cams[i].imu,
imu_name) != 0)
162 fprintf(stderr,
"vio cam %s has a different imu than vio cam %s\n", vio_cams[i].name, vio_cams[0].name);
171 size_t current_len = strlen(
imu_name);
172 const char* suffix =
"_body";
173 size_t suffix_len = strlen(suffix);
175 if (current_len + suffix_len >=
sizeof(
imu_name))
177 fprintf(stderr,
"Error: IMU name '%s' is too long to append '_body' suffix\n",
imu_name);
184 printf(
"[INFO] IMU body mode: subscribing to '%s' instead of '%s'\n",
191 cJSON *imu_json = pipe_get_info_json(vio_cams[0].imu);
193 cJSON *model = cJSON_GetObjectItem(imu_json,
"imu_model");
194 if (model && cJSON_IsString(model) && model->valuestring) {
195 if (strcmp(model->valuestring,
"ICM42688") == 0) {
197 }
else if (strcmp(model->valuestring,
"BMI270") == 0) {
201 fprintf(stderr,
"WARNING: unrecognized IMU model: %s\n", model->valuestring);
203 printf(
"IMU model detected: %s\n", model->valuestring);
206 fprintf(stderr,
"WARNING: imu_model field not found in pipe info\n");
208 cJSON_Delete(imu_json);
211 fprintf(stderr,
"WARNING: could not read IMU pipe info JSON for '%s'\n", vio_cams[0].imu);
216 std::string yaml_estimator_path = std::string(
folder_base) +
"/estimator_config.yaml";
220 config = YAML::LoadFile(yaml_estimator_path);
222 catch (
const std::exception &e)
224 fprintf(stderr,
"Failed to load estimator YAML: %s\n", e.what());
225 fprintf(stderr,
"Creating new estimator config file\n");
227 config[
"max_cameras"] = n_cams;
232 case IMU_MODEL_ICM42688:
233 config[
"prop_window"] = 0.1;
234 config[
"zupt_prop_window"] = 0.1;
236 case IMU_MODEL_BMI270:
237 config[
"prop_window"] = 0.075;
238 config[
"zupt_prop_window"] = 0.1;
241 config[
"prop_window"] = 0.075;
242 config[
"zupt_prop_window"] = 0.1;
247 config[
"max_cameras"] = n_cams;
253 std::ofstream fout(yaml_estimator_path);
254 fout <<
"%YAML:1.0" << std::endl << std::endl;
257 catch (
const std::exception &e)
259 std::cerr <<
"Failed to write estimator YAML: " << e.what() << std::endl;
266 std::string yaml_camchain_path = std::string(
folder_base) +
"/kalibr_imucam_chain.yaml";
267 YAML::Node camchain_config;
270 camchain_config = YAML::LoadFile(yaml_camchain_path);
272 catch (
const std::exception &e)
274 fprintf(stderr,
"Failed to load YAML: %s\n", e.what());
277 int is_there_an_occlluded_cam = 0;
278 for (
int i = 0; i < n_cams; i++)
281 std::string cam_key =
"cam" + std::to_string(i);
285 strncpy(cam.
name, vio_cams[i].name,
sizeof(cam.
name) - 1);
286 cam.
name[
sizeof(cam.
name) - 1] =
'\0';
298 if (
takeoff_cam < 0 && !vio_cams[i].is_occluded_on_ground)
302 printf(
"vio cam: %d is occluded: %d\n", i, vio_cams[i].is_occluded_on_ground);
303 if (!vio_cams[i].is_occluded_on_ground)
308 if (vio_cams[i].is_occluded_on_ground){
309 is_there_an_occlluded_cam = 1;
316 cam.
width = vio_cams[i].cal.width;
317 cam.
height = vio_cams[i].cal.height;
327 if (vio_cams[i].cal.is_fisheye)
334 YAML::Node intrinsics;
335 intrinsics.push_back(vio_cams[i].cal.fx);
336 intrinsics.push_back(vio_cams[i].cal.fy);
337 intrinsics.push_back(vio_cams[i].cal.cx);
338 intrinsics.push_back(vio_cams[i].cal.cy);
339 camchain_config[cam_key][
"intrinsics"] = intrinsics;
342 YAML::Node distortion_coeffs;
343 distortion_coeffs.push_back(vio_cams[i].cal.D[0]);
344 distortion_coeffs.push_back(vio_cams[i].cal.D[1]);
345 distortion_coeffs.push_back(vio_cams[i].cal.D[2]);
346 distortion_coeffs.push_back(vio_cams[i].cal.D[3]);
347 camchain_config[cam_key][
"distortion_coeffs"] = distortion_coeffs;
350 YAML::Node resolution;
351 resolution.push_back(vio_cams[i].cal.width);
352 resolution.push_back(vio_cams[i].cal.height);
353 camchain_config[cam_key][
"resolution"] = resolution;
355 camchain_config[cam_key][
"distortion_model"] = vio_cams[i].cal.is_fisheye ?
"equidistant" :
"radtan";
358 YAML::Node extrinsics = YAML::Node(YAML::NodeType::Sequence);
360 vcc_extrinsic_t ext = vio_cams[i].extrinsic;
361 Eigen::Vector3d t_pc_p(
362 ext.T_child_wrt_parent[0],
363 ext.T_child_wrt_parent[1],
364 ext.T_child_wrt_parent[2]
366 const Eigen::Matrix<double,3,3,Eigen::RowMajor> R_cp(&ext.R_child_to_parent[0][0]);
369 Eigen::Matrix4d T_cam_imu = Eigen::Matrix4d::Identity();
370 T_cam_imu.block<3,3>(0,0) = R_cp.transpose();
371 T_cam_imu.block<3,1>(0,3) = -R_cp.transpose() * t_pc_p;
374 Eigen::Matrix4d T_final;
379 T_final = T_cam_imu * T_imu_body;
382 printf(
"\n[INFO] Camera %d (%s) - Applied body transformation\n", i, vio_cams[i].name);
383 printf(
" T_cam_body (body->cam):\n");
384 std::cout << T_final << std::endl;
392 for (
int row = 0; row < 4; ++row) {
393 YAML::Node row_node = YAML::Node(YAML::NodeType::Sequence);
394 for (
int col = 0; col < 4; ++col) {
395 row_node.push_back(T_final(row, col));
397 extrinsics.push_back(row_node);
401 camchain_config[cam_key][
"T_cam_imu"] = extrinsics;
410 printf(
"Writing synced camera chain YAML to %s\n", yaml_camchain_path.c_str());
412 printf(
"[INFO] IMU body mode enabled\n");
414 std::ofstream fout(yaml_camchain_path);
416 fout <<
"%YAML:1.0" << std::endl
418 fout << camchain_config;
420 catch (
const std::exception &e)
422 std::cerr <<
"Failed to write YAML: " << e.what() << std::endl;
434 if (!is_there_an_occlluded_cam)
473 fprintf(stderr,
"Creating new OV server config file: %s\n",
CONFIG_FILE);
481 json_fetch_bool_with_default(parent,
"en_auto_reset", &
en_auto_reset, 1);
491 json_fetch_bool_with_default(parent,
"en_cont_yaw_checks", (
int *)&
en_cont_yaw_checks, 0);
492 json_fetch_float_with_default(parent,
"fast_yaw_thresh", &
fast_yaw_thresh, 5.0f);
493 json_fetch_float_with_default(parent,
"fast_yaw_timeout_s", &
fast_yaw_timeout_s, 1.75f);
494 json_fetch_string_with_default(parent,
"yaml_folder",
folder_base,
CHAR_BUF_SIZE,
"/usr/share/modalai/voxl-open-vins/VoxlConfig/starling2");
495 json_fetch_int_with_default(parent,
"using_stereo", &
using_stereo, 0);
497 json_fetch_bool_with_default(parent,
"takeoff_occlude_stereo_left", (
int *)&
occlude_stereo_left, 0);
498 json_fetch_bool_with_default(parent,
"takeoff_occlude_stereo_right", (
int *)&
occlude_stereo_right, 0);
499 json_fetch_bool_with_default(parent,
"sync_config", (
int *)&
sync_config, 1);
500 json_fetch_float_with_default(parent,
"fusion_rate_dt_ms", &
fusion_rate_dt_ms, 20.0f);
501 json_fetch_bool_with_default(parent,
"imu_body_frame_mode", (
int *)&
en_imu_body, 1);
512 if (json_get_parse_error_flag())
514 fprintf(stderr,
"failed to parse config file %s\n",
CONFIG_FILE);
515 cJSON_Delete(parent);
520 if (json_get_modified_flag())
522 printf(
"The config file was modified during parsing, saving the changes to disk\n");
525 cJSON_Delete(parent);