Visual Servoing Platform  version 3.6.1 under development (2024-05-18)
SickLDMRS-Process.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  *
31  * Description:
32  * Sick LD-MRS laser driver.
33  *
34 *****************************************************************************/
35 
57 #include <visp3/core/vpDebug.h>
58 #include <visp3/core/vpDisplay.h>
59 #include <visp3/core/vpImage.h>
60 #include <visp3/core/vpImagePoint.h>
61 #include <visp3/io/vpImageIo.h>
62 #include <visp3/sensor/vpSickLDMRS.h>
63 #ifdef VISP_HAVE_MODULE_GUI
64 #include <visp3/gui/vpDisplayGTK.h>
65 #include <visp3/gui/vpDisplayX.h>
66 #endif
67 #include <visp3/core/vpIoTools.h>
68 #include <visp3/io/vpParseArgv.h>
69 #include <visp3/sensor/vp1394TwoGrabber.h>
70 
71 #if (!defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))) && \
72  (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK)) && defined(VISP_HAVE_THREADS)
73 
74 #include <thread>
75 #include <mutex>
76 
77 static int save = 0;
78 static int layerToDisplay = 0xF; // 0xF = 1111 => all the layers are selected
79 static vpLaserScan shm_laserscan[4];
80 double time_offset = 0;
81 std::mutex shm_mutex;
82 std::string output_path;
83 
84 void laser_display_and_save_loop()
85 {
86  vpImage<unsigned char> map(700, 300);
87  map = 0;
88  unsigned int width = map.getWidth();
89  unsigned int height = map.getHeight();
90  vpImagePoint O; // Beam origin
91  O.set_i(height);
92  O.set_j(width / 2.);
93  vpScanPoint p;
94  vpColor color[4]; // one color per layer
95  char filename[FILENAME_MAX];
96  std::ofstream fdscan;
97  vpLaserScan laserscan[4];
98 
99  for (int layer = 0; layer < 4; layer++) {
100  switch (layer) {
101  case 0:
102  color[layer] = vpColor::red;
103  break;
104  case 1:
105  color[layer] = vpColor::green;
106  break;
107  case 2:
108  color[layer] = vpColor::blue;
109  break;
110  case 3:
111  color[layer] = vpColor::yellow;
112  break;
113  }
114  }
115 
116  vpDisplay *display = nullptr;
117 #ifdef VISP_HAVE_MODULE_GUI
118 #if defined(VISP_HAVE_X11)
119  display = new vpDisplayX;
120 #elif defined(VISP_HAVE_GTK)
121  display = new vpDisplayGTK;
122 #endif
123  display->init(map, 10, 10, "Laser scan");
124 #endif
125 
126  unsigned int iter = 0;
127  for (;;) {
128 
129 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
130  vpDisplay::display(map);
131 #endif
132 
133  shm_mutex.lock();
134  for (int layer = 0; layer < 4; layer++) {
135  laserscan[layer] = shm_laserscan[layer];
136  }
137  shm_mutex.unlock();
138 
139  // Parse the four layers
140  for (int layer = 0; layer < 4; layer++) {
141  if (!((0x1 << layer) & layerToDisplay)) {
142  std::cout << "Layer " << layer + 1 << " is not displayed" << std::endl;
143  continue;
144  }
145 
146  std::vector<vpScanPoint> pointsLayer = laserscan[layer].getScanPoints();
147 
148  if (save) {
149  // Set the scan data filename to store the measures
150  snprintf(filename, FILENAME_MAX, "%s/scan%04u-layer%d.txt", output_path.c_str(), iter, layer + 1);
151  fdscan.open(filename);
152 
153  // Write the file header
154  fdscan << "# Scan layer [1 to 4] : " << layer + 1 << std::endl
155  << "# Start timestamp (s) : " << laserscan[layer].getStartTimestamp() - time_offset << std::endl
156  << "# End timestamp (s) : " << laserscan[layer].getEndTimestamp() - time_offset << std::endl
157  << "# Data : \"radial distance (m)\" \"horizontal angle "
158  "(rad)\" \"vertical angle (rad)\" \"X (m)\" \"Y (m)\" \"Z "
159  "(m)\""
160  << std::endl;
161  }
162 
163  vpImagePoint E; // Beam echo
164  double resolution = 5; // 100 pixels = 1 meter - increase this value to
165  // see better near info
166  for (unsigned int i = 0; i < pointsLayer.size(); i++) {
167  p = pointsLayer[i];
168  E.set_i(height - resolution * p.getRadialDist() * cos(p.getHAngle()));
169  E.set_j(width / 2. - resolution * p.getRadialDist() * sin(p.getHAngle()));
170 // std::cout << "E: " << E << std::endl;
171 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
172  vpDisplay::displayLine(map, O, E, color[layer]);
173 #endif
174  if (save) {
175  // Save the measures in the file
176  fdscan << p << std::endl;
177  }
178  }
179  if (save) {
180  fdscan.close();
181  }
182  }
183 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
184  vpDisplay::flush(map);
185 #endif
186  iter++;
187  // std::cout << "display time: " << vpTime::measureTimeMs() - t1 <<
188  // std::endl;
189  }
190  delete display;
191 }
192 
193 void laser_acq_loop()
194 {
195  std::string ip = "131.254.12.119";
196 
197  vpSickLDMRS laser;
198  laser.setIpAddress(ip);
199  laser.setup();
200  vpLaserScan laserscan[4];
201 
202  for (;;) {
203  double t1 = vpTime::measureTimeMs();
204  if (laser.measure(laserscan) == false)
205  continue;
206 
207  shm_mutex.lock();
208  for (int layer = 0; layer < 4; layer++) {
209  shm_laserscan[layer] = laserscan[layer];
210  }
211  shm_mutex.unlock();
212 
213  std::cout << "laser acq time: " << vpTime::measureTimeMs() - t1 << std::endl;
214  }
215 }
216 
217 void camera_acq_and_display_loop()
218 {
219 #ifdef VISP_HAVE_DC1394
220  try {
221  // Initialize the firewire framegrabber
222  vp1394TwoGrabber g; // Create a grabber based on libdc1394-2.x third party lib
223 
224  // If no camera found return
225  if (g.getNumCameras() == 0) {
226  return;
227  }
228 
229  // g.setVideoMode(vp1394TwoGrabber::vpVIDEO_MODE_640x480_MONO8);
230  // g.setFramerate(vp1394TwoGrabber::vpFRAMERATE_60);
231 
232  vpImage<unsigned char> I; // Create a gray level image container
233  vpImage<unsigned char> Q; // Create a quarter size gray level image container
234  g.acquire(I); // Acquire an image
235  I.quarterSizeImage(Q);
236 
237  vpDisplay *display = nullptr;
238 #ifdef VISP_HAVE_MODULE_GUI
239 #if defined(VISP_HAVE_X11)
240  display = new vpDisplayX;
241 #elif defined(VISP_HAVE_GTK)
242  display = new vpDisplayGTK;
243 #endif
244  display->init(Q, 320, 10, "Camera");
245 #endif
246 
247  // Create a file with image time stamps
248  std::ofstream fdimage_ts;
249  if (save) {
250  std::string filename = output_path + "/image_timestamp.txt";
251  fdimage_ts.open(filename.c_str());
252  fdimage_ts << "# [image name] [time stamp in second]" << std::endl;
253  }
254  unsigned iter = 0;
255  char filename[FILENAME_MAX];
256  uint64_t timestamp;
257  uint32_t id;
258  for (;;) {
259  dc1394video_frame_t *frame = g.dequeue(I, timestamp, id); // Acquire an image
260  I.quarterSizeImage(Q);
261  double image_timestamp = timestamp / 1000000. - time_offset;
262  std::cout << "camera timestamp: " << image_timestamp << " s " << std::endl;
263  if (save) {
264  // Set the image filename
265  snprintf(filename, FILENAME_MAX, "%s/image%04u.png", output_path.c_str(), iter);
266  vpImageIo::write(Q, filename);
267  fdimage_ts << filename << " " << image_timestamp << std::endl;
268  }
269 #if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
271  vpDisplay::flush(Q);
272 #endif
273  g.enqueue(frame);
274 
275  iter++;
276  }
277  delete display;
278  if (save) {
279  fdimage_ts.close();
280  }
281  }
282  catch (...) {
283  }
284 #endif
285 }
286 
287 int main(int argc, const char **argv)
288 {
289  try {
290  output_path = "data";
291  // Test if the output path directory exist. If no try to create it
292  if (vpIoTools::checkDirectory(output_path) == false) {
293  try {
294  // Create a directory with name "username"
295  vpIoTools::makeDirectory(output_path);
296  }
297  catch (...) {
298  std::cout << "Cannot create " << output_path << " directory" << std::endl;
299  return EXIT_FAILURE;
300  }
301  }
302 
303  // Parse the command line to set the variables
304  vpParseArgv::vpArgvInfo argTable[] = {
305  {"-layer", vpParseArgv::ARGV_INT, (char *)nullptr, (char *)&layerToDisplay,
306  "The layer to display:\n"
307  "\t\t. 0x1 for layer 1.\n"
308  "\t\t. 0x2 for layer 2.\n"
309  "\t\t. 0x4 for layer 3.\n"
310  "\t\t. 0x8 for layer 4.\n"
311  "\t\tTo display all the layers you should set 0xF value."},
312  {"-save", vpParseArgv::ARGV_INT, (char *)nullptr, (char *)&save, "Turn to 1 in order to save data."},
313  {"-h", vpParseArgv::ARGV_HELP, (char *)nullptr, (char *)nullptr,
314  "Display one or more measured layers form a Sick LD-MRS laser "
315  "scanner."},
316  {(char *)nullptr, vpParseArgv::ARGV_END, (char *)nullptr, (char *)nullptr, (char *)nullptr} };
317 
318  // Read the command line options
319  if (vpParseArgv::parse(&argc, argv, argTable,
322  return (EXIT_FAILURE);
323  }
324  time_offset = vpTime::measureTimeSecond();
325 
326  std::thread thread_camera_acq(&camera_acq_and_display_loop);
327  std::thread thread_laser_acq(&laser_acq_loop);
328  std::thread thread_laser_display(&laser_display_and_save_loop);
329  thread_camera_acq.join();
330  thread_laser_acq.join();
331  thread_laser_display.join();
332 
333  return EXIT_SUCCESS;
334  }
335  catch (const vpException &e) {
336  std::cout << "Catch an exception: " << e << std::endl;
337  return EXIT_FAILURE;
338  }
339 }
340 
341 #elif !(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK))
342 int main()
343 {
344  std::cout << "You do not have X11, or GTK functionalities to display images..." << std::endl;
345  std::cout << "Tip if you are on a unix-like system:" << std::endl;
346  std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
347  std::cout << "Tip if you are on a windows-like system:" << std::endl;
348  std::cout << "- Install GTK, configure again ViSP using cmake and build again this example" << std::endl;
349  return EXIT_SUCCESS;
350 }
351 #else // #ifdef UNIX and display
352 
353 int main()
354 {
355  std::cout << "This example is only working on unix-like platforms \n"
356  << "since the Sick LD-MRS driver was not ported to Windows." << std::endl;
357  return EXIT_SUCCESS;
358 }
359 
360 #endif // #ifdef UNIX
Class for firewire ieee1394 video devices using libdc1394-2.x api.
void acquire(vpImage< unsigned char > &I)
void enqueue(dc1394video_frame_t *frame)
dc1394video_frame_t * dequeue()
void getNumCameras(unsigned int &ncameras) const
Class to define RGB colors available for display functionalities.
Definition: vpColor.h:152
static const vpColor red
Definition: vpColor.h:211
static const vpColor blue
Definition: vpColor.h:217
static const vpColor yellow
Definition: vpColor.h:219
static const vpColor green
Definition: vpColor.h:214
The vpDisplayGTK allows to display image using the GTK 3rd party library. Thus to enable this class G...
Definition: vpDisplayGTK.h:128
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition: vpDisplayX.h:128
Class that defines generic functionalities for display.
Definition: vpDisplay.h:173
static void display(const vpImage< unsigned char > &I)
static void displayLine(const vpImage< unsigned char > &I, const vpImagePoint &ip1, const vpImagePoint &ip2, const vpColor &color, unsigned int thickness=1, bool segment=true)
static void flush(const vpImage< unsigned char > &I)
error that can be emitted by ViSP classes.
Definition: vpException.h:59
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition: vpImageIo.cpp:287
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:82
void set_j(double jj)
Definition: vpImagePoint.h:305
void set_i(double ii)
Definition: vpImagePoint.h:294
void quarterSizeImage(vpImage< Type > &res) const
Definition: vpImage.h:1763
static bool checkDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:834
static void makeDirectory(const std::string &dirname)
Definition: vpIoTools.cpp:983
Implements a laser scan data structure that contains especially the list of scanned points that have ...
Definition: vpLaserScan.h:62
double getStartTimestamp()
Definition: vpLaserScan.h:111
std::vector< vpScanPoint > getScanPoints()
Definition: vpLaserScan.h:90
double getEndTimestamp()
Definition: vpLaserScan.h:113
void setIpAddress(std::string ip_address)
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
@ ARGV_NO_DEFAULTS
No default options like -help.
Definition: vpParseArgv.h:168
@ ARGV_NO_LEFTOVERS
Print an error message if an option is not in the argument list.
Definition: vpParseArgv.h:169
@ ARGV_INT
Argument is associated to an int.
Definition: vpParseArgv.h:152
@ ARGV_END
End of the argument list.
Definition: vpParseArgv.h:161
@ ARGV_HELP
Argument is for help displaying.
Definition: vpParseArgv.h:160
Class that defines a single laser scanner point.
Definition: vpScanPoint.h:73
double getRadialDist() const
Definition: vpScanPoint.h:113
double getHAngle() const
Definition: vpScanPoint.h:121
Driver for the Sick LD-MRS laser scanner.
Definition: vpSickLDMRS.h:103
bool setup(const std::string &ip, int port)
bool measure(vpLaserScan laserscan[4])
void display(vpImage< unsigned char > &I, const std::string &title)
Display a gray-scale image.
VISP_EXPORT double measureTimeSecond()
VISP_EXPORT double measureTimeMs()