Main MRPT website > C++ reference for MRPT 1.9.9
test.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 /*
11  Example : kinect-to-2d-laser-demo
12  Web page : http://www.mrpt.org/Example_Kinect_To_2D_laser_scan (includes video
13  demo)
14 
15  Purpose : Demonstrate grabbing from CKinect, multi-threading
16  and converting the 3D range data into an equivalent
17  2D planar scan.
18 */
19 
20 #include <mrpt/hwdrivers/CKinect.h>
22 #include <mrpt/system/filesystem.h>
23 #include <mrpt/system/CTicTac.h>
27 #include <mrpt/opengl/CFrustum.h>
30 #include <mrpt/img/TColor.h>
31 #include <iostream>
32 
33 using namespace mrpt;
34 using namespace mrpt::hwdrivers;
35 using namespace mrpt::math;
36 using namespace mrpt::gui;
37 using namespace mrpt::obs;
38 using namespace mrpt::maps;
39 using namespace mrpt::opengl;
40 using namespace mrpt::system;
41 using namespace mrpt::img;
42 using namespace std;
43 
44 // Thread for grabbing: Do this is another thread so we divide rendering and
45 // grabbing
46 // and exploit multicore CPUs.
47 struct TThreadParam
48 {
49  TThreadParam() : quit(false), pushed_key(0), Hz(0) {}
50  volatile bool quit;
51  volatile int pushed_key;
52  volatile double Hz;
53 
54  CObservation3DRangeScan::Ptr new_obs; // RGB+D (+3D points)
55  CObservationIMU::Ptr new_obs_imu; // Accelerometers
56 };
57 
59 {
60  try
61  {
62  CKinect kinect;
63 
64  // Set params:
65  // kinect.enableGrab3DPoints(true);
66  // kinect.enablePreviewRGB(true);
67  //...
68  const std::string cfgFile = "kinect_calib.cfg";
69  if (mrpt::system::fileExists(cfgFile))
70  {
71  cout << "Loading calibration from: " << cfgFile << endl;
72  kinect.loadConfig(mrpt::config::CConfigFile(cfgFile), "KINECT");
73  }
74  else
75  cerr << "Warning: Calibration file [" << cfgFile
76  << "] not found -> Using default params.\n";
77 
78  // Open:
79  cout << "Calling CKinect::initialize()...";
80  kinect.initialize();
81  cout << "OK\n";
82 
83  CTicTac tictac;
84  int nImgs = 0;
85  bool there_is_obs = true, hard_error = false;
86 
87  while (!hard_error && !p.quit)
88  {
89  // Grab new observation from the camera:
91  CObservation3DRangeScan>(); // Smart pointers to observations
92  CObservationIMU::Ptr obs_imu =
93  mrpt::make_aligned_shared<CObservationIMU>();
94 
95  kinect.getNextObservation(*obs, *obs_imu, there_is_obs, hard_error);
96 
97  if (!hard_error && there_is_obs)
98  {
99  std::atomic_store(&p.new_obs, obs);
100  std::atomic_store(&p.new_obs_imu, obs_imu);
101  }
102 
103  if (p.pushed_key != 0)
104  {
105  switch (p.pushed_key)
106  {
107  case 27:
108  p.quit = true;
109  break;
110  }
111 
112  // Clear pushed key flag:
113  p.pushed_key = 0;
114  }
115 
116  nImgs++;
117  if (nImgs > 10)
118  {
119  p.Hz = nImgs / tictac.Tac();
120  nImgs = 0;
121  tictac.Tic();
122  }
123  }
124  }
125  catch (std::exception& e)
126  {
127  cout << "Exception in Kinect thread: " << e.what() << endl;
128  p.quit = true;
129  }
130 }
131 
132 // ------------------------------------------------------
133 // Test_Kinect
134 // ------------------------------------------------------
135 void Test_Kinect()
136 {
137  // Launch grabbing thread:
138  // --------------------------------------------------------
139  TThreadParam thrPar;
140  std::thread thHandle(thread_grabbing, std::ref(thrPar));
141 
142  // Wait until data stream starts so we can say for sure the sensor has been
143  // initialized OK:
144  cout << "Waiting for sensor initialization...\n";
145  do
146  {
147  CObservation3DRangeScan::Ptr possiblyNewObs =
148  std::atomic_load(&thrPar.new_obs);
149  if (possiblyNewObs && possiblyNewObs->timestamp != INVALID_TIMESTAMP)
150  break;
151  else
152  std::this_thread::sleep_for(10ms);
153  } while (!thrPar.quit);
154 
155  // Check error condition:
156  if (thrPar.quit) return;
157 
158  // Create window and prepare OpenGL object in the scene:
159  // --------------------------------------------------------
160  mrpt::gui::CDisplayWindow3D win3D("Kinect 3D -> 2D laser scan", 800, 600);
161 
162  win3D.setCameraAzimuthDeg(140);
163  win3D.setCameraElevationDeg(30);
164  win3D.setCameraZoom(10.0);
165  win3D.setFOV(90);
166  win3D.setCameraPointingToPoint(2.5, 0, 0);
167 
168  // The 3D point cloud OpenGL object:
170  mrpt::make_aligned_shared<mrpt::opengl::CPointCloudColoured>();
171  gl_points->setPointSize(2.5);
172 
173  // The 2D "laser scan" OpenGL object:
175  mrpt::make_aligned_shared<mrpt::opengl::CPlanarLaserScan>();
176  gl_2d_scan->enablePoints(true);
177  gl_2d_scan->enableLine(true);
178  gl_2d_scan->enableSurface(true);
179  gl_2d_scan->setSurfaceColor(0, 0, 1, 0.3); // RGBA
180 
181  mrpt::opengl::CFrustum::Ptr gl_frustum =
182  mrpt::make_aligned_shared<mrpt::opengl::CFrustum>(
183  0.2f, 5.0f, 90.0f, 5.0f, 2.0f, true, true);
184 
185  const double aspect_ratio =
186  480.0 / 640.0; // kinect.rows() / double( kinect.cols() );
187 
189  viewInt; // Extra viewports for the RGB & D images.
190  {
191  mrpt::opengl::COpenGLScene::Ptr& scene = win3D.get3DSceneAndLock();
192 
193  // Create the Opengl object for the point cloud:
194  scene->insert(gl_points);
195  scene->insert(gl_2d_scan);
196  scene->insert(gl_frustum);
197 
198  {
200  mrpt::make_aligned_shared<mrpt::opengl::CGridPlaneXY>();
201  gl_grid->setColor(0.6, 0.6, 0.6);
202  scene->insert(gl_grid);
203  }
204  {
207  gl_corner->setScale(0.2);
208  scene->insert(gl_corner);
209  }
210 
211  const int VW_WIDTH =
212  250; // Size of the viewport into the window, in pixel units.
213  const int VW_HEIGHT = aspect_ratio * VW_WIDTH;
214  const int VW_GAP = 30;
215 
216  // Create the Opengl objects for the planar images, as textured planes,
217  // each in a separate viewport:
218  win3D.addTextMessage(
219  30, -25 - 1 * (VW_GAP + VW_HEIGHT), "Range data", TColorf(1, 1, 1),
221  viewRange = scene->createViewport("view2d_range");
222  viewRange->setViewportPosition(
223  5, -10 - 1 * (VW_GAP + VW_HEIGHT), VW_WIDTH, VW_HEIGHT);
224 
225  win3D.addTextMessage(
226  30, -25 - 2 * (VW_GAP + VW_HEIGHT), "Intensity data",
228  viewInt = scene->createViewport("view2d_int");
229  viewInt->setViewportPosition(
230  5, -10 - 2 * (VW_GAP + VW_HEIGHT), VW_WIDTH, VW_HEIGHT);
231 
232  win3D.unlockAccess3DScene();
233  win3D.repaint();
234  }
235 
237  CObservationIMU::Ptr last_obs_imu;
238 
239  while (win3D.isOpen() && !thrPar.quit)
240  {
241  CObservation3DRangeScan::Ptr possiblyNewObs =
242  std::atomic_load(&thrPar.new_obs);
243  if (possiblyNewObs && possiblyNewObs->timestamp != INVALID_TIMESTAMP &&
244  (!last_obs || possiblyNewObs->timestamp != last_obs->timestamp))
245  {
246  // It IS a new observation:
247  last_obs = possiblyNewObs;
248  last_obs_imu = std::atomic_load(&thrPar.new_obs_imu);
249 
250  // Update visualization ---------------------------------------
251  bool do_refresh = false;
252 
253  // Show 2D ranges as a grayscale image:
254  if (last_obs->hasRangeImage)
255  {
257 
258  // Normalize the image
259  static CMatrixFloat range2D; // Static to save time allocating
260  // the matrix in every iteration
261  range2D = last_obs->rangeImage *
262  (1.0 / 5.0); // kinect.getMaxRange());
263 
264  img.setFromMatrix(range2D);
265 
266  win3D.get3DSceneAndLock();
267  viewRange->setImageView_fast(img);
268  win3D.unlockAccess3DScene();
269  do_refresh = true;
270  }
271 
272  // Convert ranges to an equivalent 2D "fake laser" scan:
273  if (last_obs->hasRangeImage)
274  {
275  // Convert to scan:
277  mrpt::make_aligned_shared<CObservation2DRangeScan>();
278  const float vert_FOV = DEG2RAD(gl_frustum->getVertFOV());
279 
281  sp.angle_inf = .5f * vert_FOV;
282  sp.angle_sup = .5f * vert_FOV;
283  sp.sensorLabel = "KINECT_2D_SCAN";
284 
285  last_obs->convertTo2DScan(*obs_2d, sp);
286 
287  // And load scan in the OpenGL object:
288  gl_2d_scan->setScan(*obs_2d);
289  }
290 
291  // Show intensity image:
292  if (last_obs->hasIntensityImage)
293  {
294  win3D.get3DSceneAndLock();
295  viewInt->setImageView(
296  last_obs->intensityImage); // This is not "_fast" since the
297  // intensity image is used below
298  // in the coloured point cloud.
299  win3D.unlockAccess3DScene();
300  do_refresh = true;
301  }
302 
303  // Show 3D points:
304  if (last_obs->hasPoints3D)
305  {
306  win3D.get3DSceneAndLock();
309 
310  last_obs->project3DPointsFromDepthImageInto(*gl_points, pp);
311  win3D.unlockAccess3DScene();
312  do_refresh = true;
313  }
314 
315  // Some text messages:
316  win3D.get3DSceneAndLock();
317  // Estimated grabbing rate:
318  win3D.addTextMessage(
319  -100, -20, format("%.02f Hz", thrPar.Hz), TColorf(1, 1, 1),
320  "sans", 15, mrpt::opengl::FILL, 100);
321 
322  win3D.addTextMessage(
323  10, 10,
324  "'o'/'i'-zoom out/in, '2'/'3'/'f':show/hide 2D/3D/frustum "
325  "data, mouse: orbit 3D, ESC: quit",
326  TColorf(1, 1, 1), "sans", 10, mrpt::opengl::FILL, 110);
327 
328  win3D.addTextMessage(
329  10, 25, format(
330  "Show: 3D=%s 2D=%s Frustum=%s (vert. FOV=%.1fdeg)",
331  gl_points->isVisible() ? "YES" : "NO",
332  gl_2d_scan->isVisible() ? "YES" : "NO",
333  gl_frustum->isVisible() ? "YES" : "NO",
334  gl_frustum->getVertFOV()),
335  TColorf(1, 1, 1), "sans", 10, mrpt::opengl::FILL, 111);
336  win3D.unlockAccess3DScene();
337 
338  // Do we have accelerometer data?
339  if (last_obs_imu && last_obs_imu->dataIsPresent[IMU_X_ACC])
340  {
341  win3D.get3DSceneAndLock();
342  win3D.addTextMessage(
343  10, 65, format(
344  "Acc: x=%.02f y=%.02f z=%.02f",
345  last_obs_imu->rawMeasurements[IMU_X_ACC],
346  last_obs_imu->rawMeasurements[IMU_Y_ACC],
347  last_obs_imu->rawMeasurements[IMU_Z_ACC]),
348  TColorf(.7, .7, .7), "sans", 10, mrpt::opengl::FILL, 102);
349  win3D.unlockAccess3DScene();
350  do_refresh = true;
351  }
352 
353  // Force opengl repaint:
354  if (do_refresh) win3D.repaint();
355 
356  } // end update visualization:
357 
358  // Process possible keyboard commands:
359  // --------------------------------------
360  if (win3D.keyHit() && thrPar.pushed_key == 0)
361  {
362  const int key = tolower(win3D.getPushedKey());
363 
364  switch (key)
365  {
366  // Some of the keys are processed in this thread:
367  case 'o':
368  win3D.setCameraZoom(win3D.getCameraZoom() * 1.2);
369  win3D.repaint();
370  break;
371  case 'i':
372  win3D.setCameraZoom(win3D.getCameraZoom() / 1.2);
373  win3D.repaint();
374  break;
375  case '2':
376  gl_2d_scan->setVisibility(!gl_2d_scan->isVisible());
377  break;
378  case '3':
379  gl_points->setVisibility(!gl_points->isVisible());
380  break;
381  case 'F':
382  case 'f':
383  gl_frustum->setVisibility(!gl_frustum->isVisible());
384  break;
385  case '+':
386  gl_frustum->setVertFOV(gl_frustum->getVertFOV() + 1);
387  break;
388  case '-':
389  gl_frustum->setVertFOV(gl_frustum->getVertFOV() - 1);
390  break;
391  // ...and the rest in the kinect thread:
392  default:
393  thrPar.pushed_key = key;
394  break;
395  };
396  }
397 
398  std::this_thread::sleep_for(1ms);
399  }
400 
401  cout << "Waiting for grabbing thread to exit...\n";
402  thrPar.quit = true;
403  thHandle.join();
404  cout << "Bye!\n";
405 }
406 
407 int main(int argc, char** argv)
408 {
409  try
410  {
411  Test_Kinect();
412 
413  std::this_thread::sleep_for(50ms);
414  return 0;
415  }
416  catch (std::exception& e)
417  {
418  std::cout << "EXCEPCION: " << e.what() << std::endl;
419  return -1;
420  }
421  catch (...)
422  {
423  printf("Another exception!!");
424  return -1;
425  }
426 }
mrpt::opengl::CGridPlaneXY::Ptr
std::shared_ptr< CGridPlaneXY > Ptr
Definition: CGridPlaneXY.h:34
filesystem.h
mrpt::obs::T3DPointsTo2DScanParams::sensorLabel
std::string sensorLabel
The sensor label that will have the newly created observation.
Definition: CObservation3DRangeScan.h:63
mrpt::obs::T3DPointsProjectionParams
Used in CObservation3DRangeScan::project3DPointsFromDepthImageInto()
Definition: CObservation3DRangeScan.h:30
mrpt::system::CTicTac
A high-performance stopwatch, with typical resolution of nanoseconds.
Definition: system/CTicTac.h:19
mrpt::hwdrivers::CKinect::getNextObservation
void getNextObservation(mrpt::obs::CObservation3DRangeScan &out_obs, bool &there_is_obs, bool &hardware_error)
The main data retrieving function, to be called after calling loadConfig() and initialize().
Definition: CKinect.cpp:539
INVALID_TIMESTAMP
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Definition: datetime.h:15
CConfigFile.h
CPointCloudColoured.h
mrpt::make_aligned_shared
std::shared_ptr< T > make_aligned_shared(Args &&... args)
Creates a shared_ptr with aligned memory via aligned_allocator_cpp11<>.
Definition: aligned_allocator.h:78
mrpt::hwdrivers
Contains classes for various device interfaces.
Definition: C2DRangeFinderAbstract.h:22
mrpt::obs::T3DPointsTo2DScanParams::angle_sup
double angle_sup
(Default=5 degrees) [Only if use_origin_sensor_pose=false] The upper & lower half-FOV angle (in radia...
Definition: CObservation3DRangeScan.h:66
mrpt
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Definition: CKalmanFilterCapable.h:30
stock_objects.h
p
GLfloat GLfloat p
Definition: glext.h:6305
mrpt::opengl::CPointCloudColoured::Ptr
std::shared_ptr< CPointCloudColoured > Ptr
Definition: CPointCloudColoured.h:49
TThreadParam
Definition: vision_stereo_rectify/test.cpp:56
mrpt::opengl::MRPT_GLUT_BITMAP_HELVETICA_12
@ MRPT_GLUT_BITMAP_HELVETICA_12
Definition: opengl_fonts.h:31
mrpt::system::fileExists
bool fileExists(const std::string &fileName)
Test if a given file (or directory) exists.
Definition: filesystem.cpp:127
mrpt::obs::T3DPointsTo2DScanParams
Used in CObservation3DRangeScan::convertTo2DScan()
Definition: CObservation3DRangeScan.h:60
mrpt::obs
This namespace contains representation of robot actions and observations.
Definition: CParticleFilter.h:17
CDisplayWindow3D.h
mrpt::opengl::CFrustum::Ptr
std::shared_ptr< CFrustum > Ptr
Definition: CFrustum.h:56
mrpt::system::CTicTac::Tac
double Tac() noexcept
Stops the stopwatch.
Definition: CTicTac.cpp:90
mrpt::math::CMatrixTemplateNumeric
A matrix of dynamic size.
Definition: CMatrixTemplateNumeric.h:37
vert_FOV
const float vert_FOV
Definition: vision_stereo_rectify/test.cpp:25
main
int main()
Definition: vision_stereo_rectify/test.cpp:78
mrpt::obs::T3DPointsTo2DScanParams::angle_inf
double angle_inf
Definition: CObservation3DRangeScan.h:66
TThreadParam::new_obs_imu
CObservationIMU::Ptr new_obs_imu
Definition: vision_stereo_rectify/test.cpp:55
mrpt::img
Definition: CCanvas.h:17
mrpt::hwdrivers::CKinect
A class for grabing "range images", intensity images (either RGB or IR) and other information from an...
Definition: CKinect.h:268
mrpt::obs::CObservation3DRangeScan
Declares a class derived from "CObservation" that encapsules a 3D range scan measurement,...
Definition: CObservation3DRangeScan.h:224
Test_Kinect
void Test_Kinect()
Definition: vision_stereo_rectify/test.cpp:135
mrpt::obs::IMU_Z_ACC
@ IMU_Z_ACC
z-axis acceleration (local/vehicle frame) (m/sec2)
Definition: CObservationIMU.h:33
mrpt::format
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
TThreadParam::quit
volatile bool quit
In/Out variable: Forces the thread to exit or indicates an error in the thread that caused it to end.
Definition: vision_stereo_rectify/test.cpp:80
mrpt::obs::CObservationIMU::Ptr
std::shared_ptr< CObservationIMU > Ptr
Definition: CObservationIMU.h:110
mrpt::img::TColorf
A RGB color - floats in the range [0,1].
Definition: TColor.h:79
TThreadParam::new_obs
CObservation3DRangeScan::Ptr new_obs
RGB+D (+ optionally, 3D point cloud)
Definition: vision_stereo_rectify/test.cpp:85
mrpt::obs::IMU_X_ACC
@ IMU_X_ACC
x-axis acceleration (local/vehicle frame) (m/sec2)
Definition: CObservationIMU.h:29
mrpt::system::CTicTac::Tic
void Tic() noexcept
Starts the stopwatch.
Definition: CTicTac.cpp:79
mrpt::opengl::CPlanarLaserScan::Ptr
std::shared_ptr< CPlanarLaserScan > Ptr
Definition: CPlanarLaserScan.h:59
mrpt::opengl::CSetOfObjects::Ptr
std::shared_ptr< CSetOfObjects > Ptr
Definition: CSetOfObjects.h:30
mrpt::gui
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:16
mrpt::opengl::FILL
@ FILL
renders glyphs as filled polygons
Definition: opengl_fonts.h:38
mrpt::img::CImage
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:130
mrpt::obs::CObservation2DRangeScan::Ptr
std::shared_ptr< CObservation2DRangeScan > Ptr
Definition: CObservation2DRangeScan.h:58
mrpt::hwdrivers::CKinect::initialize
virtual void initialize()
Initializes the 3D camera - should be invoked after calling loadConfig() or setting the different par...
Definition: CKinect.cpp:150
mrpt::obs::IMU_Y_ACC
@ IMU_Y_ACC
y-axis acceleration (local/vehicle frame) (m/sec2)
Definition: CObservationIMU.h:31
mrpt::opengl::stock_objects::CornerXYZ
CSetOfObjects::Ptr CornerXYZ(float scale=1.0)
Returns three arrows representing a X,Y,Z 3D corner.
Definition: StockObjects.cpp:209
img
GLint GLvoid * img
Definition: glext.h:3763
CTicTac.h
CKinect.h
thread_grabbing
void thread_grabbing(TThreadParam &p)
Definition: vision_stereo_rectify/test.cpp:97
TThreadParam::pushed_key
volatile int pushed_key
Definition: vision_stereo_rectify/test.cpp:51
mrpt::obs::CObservation3DRangeScan::Ptr
std::shared_ptr< CObservation3DRangeScan > Ptr
Definition: CObservation3DRangeScan.h:226
mrpt::config::CConfigFile
This class allows loading and storing values and vectors of different types from "....
Definition: config/CConfigFile.h:33
mrpt::math
This base provides a set of functions for maths stuff.
Definition: math/include/mrpt/math/bits_math.h:13
CFrustum.h
ref
GLenum GLint ref
Definition: glext.h:4050
string
GLsizei const GLchar ** string
Definition: glext.h:4101
mrpt::opengl::COpenGLScene::Ptr
std::shared_ptr< COpenGLScene > Ptr
Definition: COpenGLScene.h:61
mrpt::hwdrivers::CGenericSensor::loadConfig
void loadConfig(const mrpt::config::CConfigFileBase &configSource, const std::string &section)
Loads the generic settings common to any sensor (See CGenericSensor), then call to "loadConfig_sensor...
Definition: CGenericSensor.cpp:132
mrpt::maps
Definition: CBeacon.h:24
CPlanarLaserScan.h
TThreadParam::Hz
volatile double Hz
Out variable: Approx.
Definition: vision_stereo_rectify/test.cpp:82
mrpt::obs::T3DPointsProjectionParams::takeIntoAccountSensorPoseOnRobot
bool takeIntoAccountSensorPoseOnRobot
(Default: false) If false, local (sensor-centric) coordinates of points are generated.
Definition: CObservation3DRangeScan.h:36
CGridPlaneXY.h
mrpt::opengl
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
mrpt::opengl::COpenGLViewport::Ptr
std::shared_ptr< COpenGLViewport > Ptr
Definition: COpenGLViewport.h:63
mrpt::gui::CDisplayWindow3D
A graphical user interface (GUI) for efficiently rendering 3D scenes in real-time.
Definition: CDisplayWindow3D.h:117
TColor.h
mrpt::system
This namespace provides a OS-independent interface to many useful functions: filenames manipulation,...
Definition: math_frwds.h:25
mrpt::DEG2RAD
double DEG2RAD(const double x)
Degrees to radians.
Definition: core/include/mrpt/core/bits_math.h:42



Page generated by Doxygen 1.8.17 for MRPT 1.9.9 Git: ad3a9d8ae Tue May 1 23:10:22 2018 -0700 at miƩ 12 jul 2023 10:03:34 CEST