ds5-motion.h
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
3 
4 #pragma once
5 
6 #include "ds5-device.h"
7 
8 namespace librealsense
9 {
10  // Enforce complile-time verification of all the assigned FPS profiles
12  {
13  IMU_FPS_63 = 63,
14  IMU_FPS_100 = 100,
15  IMU_FPS_200 = 200,
16  IMU_FPS_250 = 250,
17  IMU_FPS_400 = 400
18  };
19 
21 
22 #ifdef _WIN32
23  static const std::string gyro_sensor_name = "HID Sensor Class Device: Gyroscope";
24  static const std::string accel_sensor_name = "HID Sensor Class Device: Accelerometer";
25  static const std::map<odr, uint16_t> hid_fps_translation =
26  { //FPS Value to send to the Driver
27  {odr::IMU_FPS_63, 1000},
28  {odr::IMU_FPS_100, 1000},
29  {odr::IMU_FPS_200, 500},
30  {odr::IMU_FPS_250, 400},
31  {odr::IMU_FPS_400, 250} };
32 
33 #else
34  static const std::string gyro_sensor_name = "gyro_3d";
35  static const std::string accel_sensor_name = "accel_3d";
36  static const std::map<IMU_OUTPUT_DATA_RATES, unsigned> hid_fps_translation =
37  { //FPS Value to send to the Driver
38  {odr::IMU_FPS_63, 1},
39  {odr::IMU_FPS_100, 1},
40  {odr::IMU_FPS_200, 2},
41  {odr::IMU_FPS_250, 3},
42  {odr::IMU_FPS_400, 4} };
43 #endif
44 
46  {
47  public:
48  virtual rs2_extrinsics get_extrinsic_to(rs2_stream) = 0; // Extrinsics are referenced to the Depth stream, except for TM1
49  virtual ds::imu_intrinsic get_intrinsic(rs2_stream) = 0; // With extrinsic from FE<->IMU only
50  virtual float3x3 imu_to_depth_alignment() = 0;
51  };
52 
54  {
55  public:
56  tm1_imu_calib_parser(const std::vector<uint8_t>& raw_data)
57  {
58  calib_table = *(ds::check_calib<ds::tm1_eeprom>(raw_data));
59  }
62 
63  float3x3 imu_to_depth_alignment() { return {{1,0,0},{0,1,0},{0,0,1}}; }
64 
66  {
67  if (!(RS2_STREAM_ACCEL == stream) && !(RS2_STREAM_GYRO == stream) && !(RS2_STREAM_FISHEYE == stream))
68  throw std::runtime_error(to_string() << "TM1 Calibration does not provide extrinsic for : " << rs2_stream_to_string(stream) << " !");
69 
70  auto fe_calib = calib_table.calibration_table.calib_model.fe_calibration;
71 
72  auto rot = fe_calib.fisheye_to_imu.rotation;
73  auto trans = fe_calib.fisheye_to_imu.translation;
74 
75  pose ex = { { { rot(0,0), rot(1,0),rot(2,0)},
76  { rot(0,1), rot(1,1),rot(2,1) },
77  { rot(0,2), rot(1,2),rot(2,2) } },
78  { trans[0], trans[1], trans[2] } };
79 
80  if (RS2_STREAM_FISHEYE == stream)
81  return inverse(from_pose(ex));
82  else
83  return from_pose(ex);
84  }
85 
87  {
88  ds::imu_intrinsics in_intr;
89  switch (stream)
90  {
91  case RS2_STREAM_ACCEL:
92  in_intr = calib_table.calibration_table.imu_calib_table.accel_intrinsics; break;
93  case RS2_STREAM_GYRO:
94  in_intr = calib_table.calibration_table.imu_calib_table.gyro_intrinsics; break;
95  default:
96  throw std::runtime_error(to_string() << "TM1 IMU Calibration does not support intrinsic for : " << rs2_stream_to_string(stream) << " !");
97  }
98  ds::imu_intrinsic out_intr{};
99  for (auto i = 0; i < 3; i++)
100  {
101  out_intr.sensitivity(i,i) = in_intr.scale[i];
102  out_intr.bias[i] = in_intr.bias[i];
103  }
104  return out_intr;
105  }
106 
107  private:
109  };
110 
112  {
113  public:
114  dm_v2_imu_calib_parser(const std::vector<uint8_t>& raw_data, uint16_t pid, bool valid = true)
115  {
116  // product id to identify platform specific parameters, imu models and physical location
117  _pid = pid;
118 
119  _calib_table.module_info.dm_v2_calib_table.extrinsic_valid = 0;
120  _calib_table.module_info.dm_v2_calib_table.intrinsic_valid = 0;
121 
122  _valid_intrinsic = false;
123  _valid_extrinsic = false;
124 
125  // default parser to be applied when no FW calibration is available
126  if (valid)
127  {
128  try
129  {
130  _calib_table = *(ds::check_calib<ds::dm_v2_eeprom>(raw_data));
131  _valid_intrinsic = (_calib_table.module_info.dm_v2_calib_table.intrinsic_valid == 1) ? true : false;
132  _valid_extrinsic = (_calib_table.module_info.dm_v2_calib_table.extrinsic_valid == 1) ? true : false;
133  }
134  catch (...)
135  {
136  _valid_intrinsic = false;
137  _valid_extrinsic = false;
138  }
139  }
140 
141  // TODO - review possibly refactor into a map if necessary
142  //
143  // predefined platform specific extrinsic, IMU assembly transformation based on mechanical drawing (meters)
144  rs2_extrinsics _def_extr;
145 
146  if (_pid == ds::RS435I_PID)
147  {
148  // D435i specific - Bosch BMI055
149  _def_extr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 }, { -0.00552f, 0.0051f, 0.01174f} };
150  _imu_2_depth_rot = { {-1,0,0},{0,1,0},{0,0,-1} };
151  }
152  else if (_pid == ds::RS455_PID)
153  {
154  // D455 specific - Bosch BMI055
155  _def_extr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ -0.03022f, 0.0074f, 0.01602f } };
156  _imu_2_depth_rot = { { -1,0,0 },{ 0,1,0 },{ 0,0,-1 } };
157  }
158  else if (_pid == ds::RS465_PID)
159  {
160  // D465 specific - Bosch BMI085
161  // TODO - verify with mechanical drawing
162  _def_extr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ -0.10125f, -0.00375f, -0.0013f } };
163  _imu_2_depth_rot = { { 1,0,0 },{ 0,1,0 },{ 0,0,1 } };
164  }
165  else // unmapped configurations
166  {
167  // IMU on new devices is oriented such that FW output is consistent with D435i
168  // use same rotation matrix as D435i so that librealsense output from unsupported
169  // devices will still be correctly aligned with depth coordinate system.
170  _def_extr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ 0.f, 0.f, 0.f } };
171  _imu_2_depth_rot = { { -1,0,0 },{ 0,1,0 },{ 0,0,-1 } };
172  LOG_ERROR("Undefined platform with IMU, use default intrinsic/extrinsic data, PID: " << _pid);
173  }
174 
175  // default intrinsic in case no valid calibration data is available
176  // scale = 1 and offset = 0
177  _def_intr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ 0.0, 0.0, 0.0 } };
178 
179  // handling extrinsic
180  if (_valid_extrinsic)
181  {
182  // extrinsic from calibration table, by user custom calibration, The extrinsic is stored as array of floats / little-endian
183  librealsense::copy(&_extr, &_calib_table.module_info.dm_v2_calib_table.depth_to_imu, sizeof(rs2_extrinsics));
184  }
185  else
186  {
187  LOG_INFO("IMU extrinsic table not found; using CAD values");
188  // default extrinsic based on mechanical drawing
189  _extr = _def_extr;
190  }
191  }
192 
195 
196  float3x3 imu_to_depth_alignment() { return _imu_2_depth_rot; }
197 
199  {
200  if (!(RS2_STREAM_ACCEL == stream) && !(RS2_STREAM_GYRO == stream))
201  throw std::runtime_error(to_string() << "Depth Module V2 does not support extrinsic for : " << rs2_stream_to_string(stream) << " !");
202 
203  return _extr;
204  }
205 
207  {
208  ds::dm_v2_imu_intrinsic in_intr;
209  switch (stream)
210  {
211  case RS2_STREAM_ACCEL:
212  if (_valid_intrinsic)
213  {
214  in_intr = _calib_table.module_info.dm_v2_calib_table.accel_intrinsic;
215  }
216  else
217  {
218  LOG_INFO("Depth Module V2 IMU " << rs2_stream_to_string(stream) << "no valid intrinsic available, use default values.");
219  in_intr = _def_intr;
220  }
221  break;
222  case RS2_STREAM_GYRO:
223  if (_valid_intrinsic)
224  {
225  in_intr = _calib_table.module_info.dm_v2_calib_table.gyro_intrinsic;
226  in_intr.bias = in_intr.bias * static_cast<float>(d2r); // The gyro bias is calculated in Deg/sec
227  }
228  else
229  {
230  LOG_INFO("Depth Module V2 IMU " << rs2_stream_to_string(stream) << "intrinsic not valid, use default values.");
231  in_intr = _def_intr;
232  }
233  break;
234  default:
235  throw std::runtime_error(to_string() << "Depth Module V2 does not provide intrinsic for stream type : " << rs2_stream_to_string(stream) << " !");
236  }
237 
238  return { in_intr.sensitivity, in_intr.bias, {0,0,0}, {0,0,0} };
239  }
240 
241  private:
249  };
250 
252  {
253  public:
254  l500_imu_calib_parser(const std::vector<uint8_t>& raw_data, bool valid = true)
255  {
256  // default parser to be applied when no FW calibration is available
257  _valid_intrinsic = false;
258  _valid_extrinsic = false;
259 
260  // in case calibration table is provided but with incorrect header and CRC, both intrinsic and extrinsic will use default values
261  // calibration table has flags to indicate if it contains valid intrinsic and extrinsic, use this as further indication if the data is valid
262  // currently, the imu calibration script only calibrates intrinsic so only the intrinsic_valid field is set during calibration, extrinsic
263  // will use default values derived from mechanical CAD drawing, however, if the calibration script in the future or user calibration provide
264  // valid extrinsic, the extrinsic_valid field should be set in the table and detected here so the values from the table can be used.
265  if (valid)
266  {
267  try
268  {
269  imu_calib_table = *(ds::check_calib<ds::dm_v2_calibration_table>(raw_data));
270  _valid_intrinsic = (imu_calib_table.intrinsic_valid == 1) ? true : false;
271  _valid_extrinsic = (imu_calib_table.extrinsic_valid == 1) ? true : false;
272  }
273  catch (...)
274  {
275  _valid_intrinsic = false;
276  _valid_extrinsic = false;
277  }
278  }
279 
280  // L515 specific
281  // Bosch BMI085 assembly transformation based on mechanical drawing (meters)
282  // device thickness 26 mm from front glass to back surface
283  // depth ground zero is 4.5mm from front glass into the device
284  // IMU reference in z direction is at 20.93mm from back surface
285  //
286  // IMU offset in Z direction = 4.5 mm - (26 mm - 20.93 mm) = 4.5 mm - 5.07mm = - 0.57mm
287  // IMU offset in x and Y direction (12.45mm, -16.42mm) from center
288  //
289  // coordinate system as reference, looking from back of the camera towards front,
290  // the positive x-axis points to the right, the positive y-axis points down, and the
291  // positive z-axis points forward.
292  // origin in the center but z-direction 4.5mm from front glass into the device
293  // the matrix below is such that output of motion data is consistent with convention
294  // that positive direction aligned with gravity leads to -1g and opposite direction
295  // leads to +1g, for example, positive z_aixs points forward away from front glass of
296  // the device, 1) if place the device flat on a table, facing up, positive z-axis points
297  // up, z-axis acceleration is around +1g; 2) facing down, positive z-axis points down,
298  // z-axis accleration would be around -1g
299  rs2_extrinsics _def_extr;
300  _def_extr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ -0.01245f, 0.01642f, 0.00057f } };
301  _imu_2_depth_rot = { { -1, 0, 0 },{ 0, 1, 0 },{ 0, 0, -1 } };
302 
303  // default intrinsic in case no valid calibration data is available
304  // scale = 1 and offset = 0
305  _def_intr = { { 1, 0, 0, 0, 1, 0, 0, 0, 1 },{ 0.0, 0.0, 0.0 } };
306 
307 
308  // handling extrinsic
309  if (_valid_extrinsic)
310  {
311  // only in case valid extrinsic is available in calibration data by calibration script in future or user custom calibration
312  librealsense::copy(&_extr, &imu_calib_table.depth_to_imu, sizeof(rs2_extrinsics));
313  }
314  else
315  {
316  // L515 - BMI085 assembly transformation based on mechanical drawing
317  LOG_INFO("IMU extrinsic using CAD values");
318  _extr = _def_extr;
319  }
320  }
321 
323 
324  float3x3 imu_to_depth_alignment() { return _imu_2_depth_rot; }
325 
327  {
328  ds::dm_v2_imu_intrinsic in_intr;
329  switch (stream)
330  {
331  case RS2_STREAM_ACCEL:
332  if (_valid_intrinsic)
333  {
334  in_intr = imu_calib_table.accel_intrinsic;
335  }
336  else
337  {
338  LOG_INFO("L515 IMU " << rs2_stream_to_string(stream) << "no valid intrinsic available, use default values.");
339  in_intr = _def_intr;
340  }
341  break;
342  case RS2_STREAM_GYRO:
343  if (_valid_intrinsic)
344  {
345  in_intr = imu_calib_table.gyro_intrinsic;
346  in_intr.bias = in_intr.bias * static_cast<float>(d2r); // The gyro bias is calculated in Deg/sec
347  }
348  else
349  {
350  LOG_INFO("L515 IMU " << rs2_stream_to_string(stream) << "no valid intrinsic available, use default values.");
351  in_intr = _def_intr;
352  }
353  break;
354  default:
355  throw std::runtime_error(to_string() << "L515 does not provide intrinsic for stream type : " << rs2_stream_to_string(stream) << " !");
356  }
357 
358  return{ in_intr.sensitivity, in_intr.bias,{ 0,0,0 },{ 0,0,0 } };
359  }
360 
362  {
363  if (!(RS2_STREAM_ACCEL == stream) && !(RS2_STREAM_GYRO == stream))
364  throw std::runtime_error(to_string() << "L515 does not support extrinsic for : " << rs2_stream_to_string(stream) << " !");
365 
366  return _extr;
367  }
368 
369  private:
376  };
377 
379  {
380  public:
381  mm_calib_handler(std::shared_ptr<hw_monitor> hw_monitor, uint16_t pid);
383 
384  ds::imu_intrinsic get_intrinsic(rs2_stream);
385  rs2_extrinsics get_extrinsic(rs2_stream); // The extrinsic defined as Depth->Stream rigid-body transfom.
386  const std::vector<uint8_t> get_fisheye_calib_raw();
387  float3x3 imu_to_depth_alignment() { return (*_calib_parser)->imu_to_depth_alignment(); }
388  private:
389  std::shared_ptr<hw_monitor> _hw_monitor;
392  std::vector<uint8_t> get_imu_eeprom_raw() const;
393  std::vector<uint8_t> get_imu_eeprom_raw_l515() const;
396  };
397 
398  class ds5_motion : public virtual ds5_device
399  {
400  public:
401  std::shared_ptr<synthetic_sensor> create_hid_device(std::shared_ptr<context> ctx,
402  const std::vector<platform::hid_device_info>& all_hid_infos,
403  const firmware_version& camera_fw_version);
404 
405  ds5_motion(std::shared_ptr<context> ctx,
407 
408  rs2_motion_device_intrinsic get_motion_intrinsics(rs2_stream) const;
409 
410  std::shared_ptr<auto_exposure_mechanism> register_auto_exposure_options(synthetic_sensor* ep,
412 
413  private:
414 
415  friend class ds5_fisheye_sensor;
416  friend class ds5_hid_sensor;
417 
418  void initialize_fisheye_sensor(std::shared_ptr<context> ctx, const platform::backend_device_group& group);
419 
422 
423  std::shared_ptr<mm_calib_handler> _mm_calib;
424  std::shared_ptr<lazy<ds::imu_intrinsic>> _accel_intrinsic;
425  std::shared_ptr<lazy<ds::imu_intrinsic>> _gyro_intrinsic;
427  std::shared_ptr<lazy<rs2_extrinsics>> _depth_to_imu; // Mechanical installation pose
428 
429  uint16_t _pid; // product PID
430 
431  // Bandwidth parameters required for HID sensors
432  // The Acceleration configuration will be resolved according to the IMU sensor type at run-time
433  std::vector<std::pair<std::string, stream_profile>> sensor_name_and_hid_profiles =
436 
437  // Translate frequency to SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL.
438  std::map<rs2_stream, std::map<unsigned, unsigned>> fps_and_sampling_frequency_per_rs2_stream =
439  { { RS2_STREAM_GYRO, {{unsigned(odr::IMU_FPS_200), hid_fps_translation.at(odr::IMU_FPS_200)},
440  { unsigned(odr::IMU_FPS_400), hid_fps_translation.at(odr::IMU_FPS_400)}}} };
441 
442  protected:
443  std::shared_ptr<stream_interface> _fisheye_stream;
444  std::shared_ptr<stream_interface> _accel_stream;
445  std::shared_ptr<stream_interface> _gyro_stream;
446  };
447 }
dm_v2_imu_calib_parser(const std::vector< uint8_t > &raw_data, uint16_t pid, bool valid=true)
Definition: ds5-motion.h:114
std::shared_ptr< lazy< ds::imu_intrinsic > > _accel_intrinsic
Definition: ds5-motion.h:424
ds::dm_v2_imu_intrinsic _def_intr
Definition: ds5-motion.h:373
rs2_extrinsics from_pose(pose a)
Definition: src/types.h:602
static const std::string gyro_sensor_name
Definition: ds5-motion.h:34
optional_value< uint8_t > _motion_module_device_idx
Definition: ds5-motion.h:421
ds::imu_intrinsic get_intrinsic(rs2_stream stream)
Definition: ds5-motion.h:86
std::shared_ptr< lazy< rs2_extrinsics > > _depth_to_imu
Definition: ds5-motion.h:427
tm1_imu_calib_parser(const std::vector< uint8_t > &raw_data)
Definition: ds5-motion.h:56
std::shared_ptr< stream_interface > _gyro_stream
Definition: ds5-motion.h:445
ds::dm_v2_imu_intrinsic _def_intr
Definition: ds5-motion.h:245
unsigned short uint16_t
Definition: stdint.h:79
l500_imu_calib_parser(const std::vector< uint8_t > &raw_data, bool valid=true)
Definition: ds5-motion.h:254
GLsizei const GLchar *const * string
rs2_extrinsics get_extrinsic_to(rs2_stream stream)
Definition: ds5-motion.h:361
lazy< std::vector< uint8_t > > _fisheye_calibration_table_raw
Definition: ds5-motion.h:426
pose inverse(const pose &a)
Definition: src/types.h:592
static const std::map< IMU_OUTPUT_DATA_RATES, unsigned > hid_fps_translation
Definition: ds5-motion.h:36
const uint16_t RS455_PID
Definition: ds5-private.h:48
ds::imu_intrinsic get_intrinsic(rs2_stream stream)
Definition: ds5-motion.h:326
optional_value< uint8_t > _fisheye_device_idx
Definition: ds5-motion.h:420
lazy< std::shared_ptr< mm_calib_parser > > _calib_parser
Definition: ds5-motion.h:390
GLboolean GLuint group
Definition: glext.h:5688
ds::dm_v2_calibration_table imu_calib_table
Definition: ds5-motion.h:370
rs2_extrinsics get_extrinsic_to(rs2_stream stream)
Definition: ds5-motion.h:198
lazy< std::vector< uint8_t > > _fisheye_calibration_table_raw
Definition: ds5-motion.h:394
#define LOG_ERROR(...)
Definition: src/types.h:242
std::shared_ptr< hw_monitor > _hw_monitor
Definition: ds5-motion.h:389
rs2_stream
Streams are different types of data provided by RealSense devices.
Definition: rs_sensor.h:42
static const std::string accel_sensor_name
Definition: ds5-motion.h:35
rs2_extrinsics get_extrinsic_to(rs2_stream stream)
Definition: ds5-motion.h:65
static const double d2r
Definition: src/types.h:58
Cross-stream extrinsics: encodes the topology describing how the different devices are oriented...
Definition: rs_sensor.h:96
LOG_INFO("Log message using LOG_INFO()")
const uint16_t RS435I_PID
Definition: ds5-private.h:42
const char * rs2_stream_to_string(rs2_stream stream)
Definition: rs.cpp:1262
const platform::extension_unit fisheye_xu
Definition: ds5-private.h:162
std::shared_ptr< lazy< ds::imu_intrinsic > > _gyro_intrinsic
Definition: ds5-motion.h:425
Motion device intrinsics: scale, bias, and variances.
Definition: rs_types.h:103
lazy< std::vector< uint8_t > > _imu_eeprom_raw
Definition: ds5-motion.h:391
int i
ds::imu_intrinsic get_intrinsic(rs2_stream stream)
Definition: ds5-motion.h:206
const uint16_t RS465_PID
Definition: ds5-private.h:45
std::shared_ptr< mm_calib_handler > _mm_calib
Definition: ds5-motion.h:423
std::shared_ptr< stream_interface > _accel_stream
Definition: ds5-motion.h:444
std::shared_ptr< stream_interface > _fisheye_stream
Definition: ds5-motion.h:443
void copy(void *dst, void const *src, size_t size)
Definition: types.cpp:836
std::string to_string(T value)


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:12