YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
realsense2withIMUDriver.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3 * All rights reserved.
4 *
5 * This software may be modified and distributed under the terms of the
6 * BSD-3-Clause license. See the accompanying LICENSE file for details.
7 */
8
10
11#include <yarp/os/Value.h>
13
14#include <yarp/sig/ImageUtils.h>
15
17#include <yarp/math/Math.h>
18
19#include <algorithm>
20#include <cmath>
21#include <cstdint>
22#include <iomanip>
23#include <librealsense2/rsutil.h>
24#include <librealsense2/rs.hpp>
25#include <mutex>
26
27 /**********************************************************************************************************/
28 // This software module is experimental.
29 // It is provided with uncomplete documentation and it may be modified/renamed/removed without any notice.
30 /**********************************************************************************************************/
31
32using namespace yarp::dev;
33using namespace yarp::sig;
34using namespace yarp::os;
35
36using namespace std;
37
38namespace {
39YARP_LOG_COMPONENT(REALSENSE2WITHIMU, "yarp.device.realsense2withIMU")
40}
41
42
43struct float3 {
44 float x;
45 float y;
46 float z;
47
49 {
50 return { x * t, y * t, z * t };
51 }
52
54 {
55 return { x - t, y - t, z - t };
56 }
57
58 void operator*=(float t)
59 {
60 x = x * t;
61 y = y * t;
62 z = z * t;
63 }
64
65 void add(float t1, float t2, float t3)
66 {
67 x += t1;
68 y += t2;
69 z += t3;
70 }
71};
72
74{
75 // theta is the angle of camera rotation in x, y and z components
76 float3 theta;
77 std::mutex theta_mtx;
78 /* alpha indicates the part that gyro and accelerometer take in computation of theta; higher alpha gives more weight to gyro, but too high
79 values cause drift; lower alpha gives more weight to accelerometer, which is more sensitive to disturbances */
80 float alpha = 0.98;
81 bool first = true;
82 // Keeps the arrival time of previous gyro frame
83 double last_ts_gyro = 0;
84public:
85 // Function to calculate the change in angle of motion based on data from gyro
87 {
88 if (first) // On the first iteration, use only data from accelerometer to set the camera's initial position
89 {
90 last_ts_gyro = ts;
91 return;
92 }
93 // Holds the change in angle, as calculated from gyro
95
96 // Initialize gyro_angle with data from gyro
97 gyro_angle.x = gyro_data.x; // Pitch
98 gyro_angle.y = gyro_data.y; // Yaw
99 gyro_angle.z = gyro_data.z; // Roll
100
101 // Compute the difference between arrival times of previous and current gyro frames
102 double dt_gyro = (ts - last_ts_gyro) / 1000.0;
103 last_ts_gyro = ts;
104
105 // Change in angle equals gyro measures * time passed since last measurement
107
108 // Apply the calculated change of angle to the current angle (theta)
109 std::lock_guard<std::mutex> lock(theta_mtx);
110 theta.add(-gyro_angle.z, -gyro_angle.y, gyro_angle.x);
111 }
112
114 {
115 // Holds the angle as calculated from accelerometer data
117
118 // Calculate rotation angle from accelerometer data
121 accel_angle.y = 0; //ADDED by randaz81
122
123 // If it is the first iteration, set initial pose of camera according to accelerometer data (note the different handling for Y axis)
124 std::lock_guard<std::mutex> lock(theta_mtx);
125 if (first)
126 {
127 first = false;
128 theta = accel_angle;
129 // Since we can't infer the angle around Y axis using accelerometer data, we'll use PI as a convetion for the initial pose
130 theta.y = M_PI;
131 }
132 else
133 {
134 /*
135 Apply Complementary Filter:
136 - high-pass filter = theta * alpha: allows short-duration signals to pass through while filtering out signals
137 that are steady over time, is used to cancel out drift.
138 - low-pass filter = accel * (1- alpha): lets through long term changes, filtering out short term fluctuations
139 */
140 theta.x = theta.x * alpha + accel_angle.x * (1 - alpha);
141 theta.z = theta.z * alpha + accel_angle.z * (1 - alpha);
142 }
143 }
144
145 // Returns the current rotation angle
147 {
148 std::lock_guard<std::mutex> lock(theta_mtx);
149 return theta;
150 }
151};
152
153//---------------------------------------------------------------
154
155#if 0
156static std::string get_device_information(const rs2::device& dev)
157{
158
159 std::stringstream ss;
160 ss << "Device information: " << std::endl;
161
162 for (int i = 0; i < static_cast<int>(RS2_CAMERA_INFO_COUNT); i++) {
163 auto info_type = static_cast<rs2_camera_info>(i);
164 ss << " " << std::left << std::setw(20) << info_type << " : ";
165
166 if (dev.supports(info_type))
167 ss << dev.get_info(info_type) << std::endl;
168 else
169 ss << "N/A" << std::endl;
170 }
171 return ss.str();
172}
173
174static bool setOption(rs2_option option, const rs2::sensor* sensor, float value)
175{
176
177 if (!sensor) {
178 return false;
179 }
180
181 // First, verify that the sensor actually supports this option
182 if (!sensor->supports(option)) {
183 yCError(REALSENSE2WITHIMU) << "The option" << rs2_option_to_string(option) << "is not supported by this sensor";
184 return false;
185 }
186
187 // To set an option to a different value, we can call set_option with a new value
188 try {
189 sensor->set_option(option, value);
190 } catch (const rs2::error& e) {
191 // Some options can only be set while the camera is streaming,
192 // and generally the hardware might fail so it is good practice to catch exceptions from set_option
193 yCError(REALSENSE2WITHIMU) << "Failed to set option " << rs2_option_to_string(option) << ". (" << e.what() << ")";
194 return false;
195 }
196 return true;
197}
198
199static bool getOption(rs2_option option, const rs2::sensor* sensor, float& value)
200{
201 if (!sensor) {
202 return false;
203 }
204
205 // First, verify that the sensor actually supports this option
206 if (!sensor->supports(option)) {
207 yCError(REALSENSE2WITHIMU) << "The option" << rs2_option_to_string(option) << "is not supported by this sensor";
208 return false;
209 }
210
211 // To set an option to a different value, we can call set_option with a new value
212 try {
213 value = sensor->get_option(option);
214 } catch (const rs2::error& e) {
215 // Some options can only be set while the camera is streaming,
216 // and generally the hardware might fail so it is good practice to catch exceptions from set_option
217 yCError(REALSENSE2WITHIMU) << "Failed to get option " << rs2_option_to_string(option) << ". (" << e.what() << ")";
218 return false;
219 }
220 return true;
221}
222
223static void settingErrorMsg(const string& error, bool& ret)
224{
225 yCError(REALSENSE2WITHIMU) << error.c_str();
226 ret = false;
227}
228#endif
229
235
236#if 0
238{
239 try {
240 m_profile = m_pipeline.start(m_cfg);
241 } catch (const rs2::error& e) {
242 yCError(REALSENSE2WITHIMU) << "Failed to start the pipeline:"
243 << "(" << e.what() << ")";
244 m_lastError = e.what();
245 return false;
246 }
247 return true;
248}
249
251{
252 try {
253 m_pipeline.stop();
254 } catch (const rs2::error& e) {
255 yCError(REALSENSE2WITHIMU) << "Failed to stop the pipeline:"
256 << "(" << e.what() << ")";
257 m_lastError = e.what();
258 return false;
259 }
260 return true;
261}
262
264{
265 std::lock_guard<std::mutex> guard(m_mutex);
266 if (!pipelineShutdown())
267 return false;
268
269 return pipelineStartup();
270}
271
272
274{
277 yCWarning(REALSENSE2WITHIMU) << "Format not supported, use --verbose for more details. Setting the fallback format";
278 std::cout << "COLOR: " << m_color_intrin.width << "x" << m_color_intrin.height << " fps: " << m_fps << std::endl;
279 std::cout << "DEPTH: " << m_depth_intrin.width << "x" << m_depth_intrin.height << " fps: " << m_fps << std::endl;
280}
281#endif
282
284{
285 yCWarning(REALSENSE2WITHIMU) << "This software module is experimental.";
286 yCWarning(REALSENSE2WITHIMU) << "It is provided with uncomplete documentation and it may be modified/renamed/removed without any notice.";
287
288 string sensor_is = "d435i";
289 bool b = true;
290
291 if (sensor_is == "d435")
292 {
293 b &= realsense2Driver::open(config);
294 //m_sensor_has_pose_capabilities = false;
296 }
297 else if (sensor_is == "d435i")
298 {
299 b &= realsense2Driver::open(config);
300 //m_sensor_has_pose_capabilities = false;
304 b &= pipelineRestart();
305 }
306 /*
307 //T265 is very diffcukt to implement without major refactoring.
308 //here some infos, just for reference
309 else if(sensor_is == "t265")
310 {
311 b &= realsense2Driver::open(config);
312 m_sensor_has_pose_capabilities = true;
313 m_sensor_has_orientation_estimator = false;
314 m_cfg.enable_stream(RS2_STREAM_ACCEL, RS2_FORMAT_MOTION_XYZ32F);
315 m_cfg.enable_stream(RS2_STREAM_GYRO, RS2_FORMAT_MOTION_XYZ32F);
316 m_cfg.enable_stream(RS2_STREAM_POSE, RS2_FORMAT_6DOF);
317 b &= pipelineRestart();
318 }*/
319 else
320 {
321 yCError(REALSENSE2WITHIMU) << "Unkwnon device";
322 return false;
323 }
324
325 return b;
326}
327
329{
331 return true;
332}
333
334//---------------------------------------------------------------------------------------------------------------
335/* IThreeAxisGyroscopes methods */
337{
338 return 1;
339}
340
346
348{
349 if (sens_index != 0) { return false; }
351 return true;
352}
353
355{
356 if (sens_index != 0) { return false; }
357 frameName = m_gyroFrameName;
358 return true;
359}
360
362{
363 if (sens_index != 0) {
364 return false;
365 }
366
367 std::lock_guard<std::mutex> guard(realsense2Driver::m_mutex);
368 rs2::frameset dataframe;
369 try
370 {
371 dataframe = m_pipeline.wait_for_frames();
372 }
373 catch (const rs2::error& e)
374 {
375 yCError(REALSENSE2WITHIMU) << "m_pipeline.wait_for_frames() failed with error:"<< "(" << e.what() << ")";
376 m_lastError = e.what();
377 return false;
378 }
380 rs2::motion_frame gyro = fg.as<rs2::motion_frame>();
381 m_last_gyro = gyro.get_motion_data();
382 out.resize(3);
383 out[0] = m_last_gyro.x;
384 out[1] = m_last_gyro.y;
385 out[2] = m_last_gyro.z;
386 return true;
387}
388
389//-------------------------------------------------------------------------------------------------------
390
391/* IThreeAxisLinearAccelerometers methods */
396
402
404{
405 if (sens_index != 0) { return false; }
407 return true;
408}
409
411{
412 if (sens_index != 0) { return false; }
413 frameName = m_accelFrameName;
414 return true;
415}
416
418{
419 std::lock_guard<std::mutex> guard(m_mutex);
420 rs2::frameset dataframe;
421 try
422 {
423 dataframe = m_pipeline.wait_for_frames();
424 }
425 catch (const rs2::error& e)
426 {
427 yCError(REALSENSE2WITHIMU) << "m_pipeline.wait_for_frames() failed with error:"<< "(" << e.what() << ")";
428 m_lastError = e.what();
429 return false;
430 }
432 rs2::motion_frame accel = fa.as<rs2::motion_frame>();
433 m_last_accel = accel.get_motion_data();
434 out.resize(3);
435 out[0] = m_last_accel.x;
436 out[1] = m_last_accel.y;
437 out[2] = m_last_accel.z;
438 return true;
439}
440
441//-------------------------------------------------------------------------------------------------------
442
443/* IOrientationSensors methods */
445{
446 if (m_sensor_has_orientation_estimator) { return 1; }
447 return 0;
448}
449
456
458{
460 {
461 return false;
462 }
463 if (sens_index != 0) { return false; }
465 return true;
466}
467
469{
471 {
472 return false;
473 }
474 if (sens_index != 0) { return false; }
475 frameName = m_orientationFrameName;
476 return true;
477}
478
479
481{
482 if (sens_index != 0) { return false; }
484 {
485 std::lock_guard<std::mutex> guard(m_mutex);
486 rs2::frameset dataframe;
487 try
488 {
489 dataframe = m_pipeline.wait_for_frames();
490 }
491 catch (const rs2::error& e)
492 {
493 yCError(REALSENSE2WITHIMU) << "m_pipeline.wait_for_frames() failed with error:"<< "(" << e.what() << ")";
494 m_lastError = e.what();
495 return false;
496 }
497 auto motion = dataframe.as<rs2::motion_frame>();
498 if (motion && motion.get_profile().stream_type() == RS2_STREAM_GYRO &&
499 motion.get_profile().format() == RS2_FORMAT_MOTION_XYZ32F)
500 {
501 // Get the timestamp of the current frame
502 double ts = motion.get_timestamp();
503 // Get gyro measures
504 rs2_vector gyro_data = motion.get_motion_data();
505 // Call function that computes the angle of motion based on the retrieved measures
507 }
508 // If casting succeeded and the arrived frame is from accelerometer stream
509 if (motion && motion.get_profile().stream_type() == RS2_STREAM_ACCEL &&
510 motion.get_profile().format() == RS2_FORMAT_MOTION_XYZ32F)
511 {
512 // Get accelerometer measures
513 rs2_vector accel_data = motion.get_motion_data();
514 // Call function that computes the angle of motion based on the retrieved measures
516 }
518 rpy.resize(3);
519 rpy[0] = 0 + theta.x * 180.0 / M_PI; //here we can eventually adjust the sign and/or sum an offset
520 rpy[1] = 0 + theta.y * 180.0 / M_PI;
521 rpy[2] = 0 + theta.z * 180.0 / M_PI;
522 return true;
523 }
524 return false;
525}
#define M_PI
bool ret
rs2::pipeline m_pipeline
rs2_intrinsics m_color_intrin
rs2::pipeline_profile m_profile
rs2_intrinsics m_depth_intrin
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool getThreeAxisLinearAccelerometerMeasure(size_t sens_index, yarp::sig::Vector &out, double &timestamp) const override
Get the last reading of the specified sensor.
size_t getNrOfOrientationSensors() const override
Get the number of orientation sensors exposed by this device.
size_t getNrOfThreeAxisLinearAccelerometers() const override
Get the number of three axis linear accelerometers exposed by this device.
bool getThreeAxisLinearAccelerometerName(size_t sens_index, std::string &name) const override
Get the name of the specified sensor.
bool getThreeAxisGyroscopeName(size_t sens_index, std::string &name) const override
Get the name of the specified sensor.
yarp::dev::MAS_status getThreeAxisLinearAccelerometerStatus(size_t sens_index) const override
Get the status of the specified sensor.
bool getOrientationSensorName(size_t sens_index, std::string &name) const override
Get the name of the specified sensor.
bool getThreeAxisGyroscopeFrameName(size_t sens_index, std::string &frameName) const override
Get the name of the frame of the specified sensor.
bool close() override
Close the DeviceDriver.
bool getOrientationSensorFrameName(size_t sens_index, std::string &frameName) const override
Get the name of the frame of the specified sensor.
bool getThreeAxisGyroscopeMeasure(size_t sens_index, yarp::sig::Vector &out, double &timestamp) const override
Get the last reading of the gyroscope.
bool getThreeAxisLinearAccelerometerFrameName(size_t sens_index, std::string &frameName) const override
Get the name of the frame of the specified sensor.
rotation_estimator * m_rotation_estimator
size_t getNrOfThreeAxisGyroscopes() const override
Get the number of three axis gyroscopes exposed by this sensor.
bool getOrientationSensorMeasureAsRollPitchYaw(size_t sens_index, yarp::sig::Vector &rpy, double &timestamp) const override
Get the last reading of the orientation sensor as roll pitch yaw.
yarp::dev::MAS_status getOrientationSensorStatus(size_t sens_index) const override
Get the status of the specified sensor.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
const std::string m_orientation_sensor_tag
yarp::dev::MAS_status getThreeAxisGyroscopeStatus(size_t sens_index) const override
Get the status of the specified sensor.
void process_gyro(rs2_vector gyro_data, double ts)
void process_accel(rs2_vector accel_data)
A mini-server for performing network communication in the background.
A base class for nested structures that can be searched.
Definition Searchable.h:31
void resize(size_t size) override
Resize the vector.
Definition Vector.h:221
#define yCError(component,...)
#define yCWarning(component,...)
#define YARP_LOG_COMPONENT(name,...)
STL namespace.
For streams capable of holding different kinds of content, check what they actually have.
MAS_status
Status of a given analog sensor exposed by a multiple analog sensors interface.
@ MAS_UNKNOWN
The sensor is in an unknown state.
@ MAS_OK
The sensor is working correctly.
An interface to the operating system, including Port based communication.
static bool setOption(rs2_option option, const rs2::sensor *sensor, float value)
static bool getOption(rs2_option option, const rs2::sensor *sensor, float &value)
static std::string get_device_information(const rs2::device &dev)
static void settingErrorMsg(const string &error, bool &ret)
void operator*=(float t)
float3 operator-(float t)
void add(float t1, float t2, float t3)
float3 operator*(float t)