File: SickLDMRS-Process.cpp

package info (click to toggle)
visp 3.6.0-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 119,296 kB
  • sloc: cpp: 500,914; ansic: 52,904; xml: 22,642; python: 7,365; java: 4,247; sh: 482; makefile: 237; objc: 145
file content (374 lines) | stat: -rw-r--r-- 12,202 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
/****************************************************************************
 *
 * ViSP, open source Visual Servoing Platform software.
 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
 *
 * This software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * See the file LICENSE.txt at the root directory of this source
 * distribution for additional information about the GNU GPL.
 *
 * For using ViSP with software that can not be combined with the GNU
 * GPL, please contact Inria about acquiring a ViSP Professional
 * Edition License.
 *
 * See https://visp.inria.fr for more information.
 *
 * This software was developed at:
 * Inria Rennes - Bretagne Atlantique
 * Campus Universitaire de Beaulieu
 * 35042 Rennes Cedex
 * France
 *
 * If you have questions regarding the use of this file, please contact
 * Inria at visp@inria.fr
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Description:
 * Sick LD-MRS laser driver.
 *
*****************************************************************************/

/*!
  \example SickLDMRS-Process.cpp

  \brief Example that shows how to acquire Sick LD-MRS laser measurements.

  This example shows by multithreading how to:
  - acquire Sick LD-MRS laser measurements
  - how to process the data in order to display the laser scans and how
    to save the scan data in a file
  - and how to acquire and display images from a firewire camera if connected.

  \warning For the moment, this example is only working on UNIX
  platforms since the Sick LD-MRS driver was not ported to Windows.

  Concerning the laser, layer 1 is displayed in red, layer 2 in green,
  l ayer 3 in blue and layer 4 in yellow.

  Thanks to the -layer command line option, this example allows to
  select the layers to proceed.

*/
#include <visp3/core/vpDebug.h>
#include <visp3/core/vpDisplay.h>
#include <visp3/core/vpImage.h>
#include <visp3/core/vpImagePoint.h>
#include <visp3/io/vpImageIo.h>
#include <visp3/sensor/vpSickLDMRS.h>
#ifdef VISP_HAVE_MODULE_GUI
#include <visp3/gui/vpDisplayGTK.h>
#include <visp3/gui/vpDisplayX.h>
#endif
#include <visp3/core/vpIoTools.h>
#include <visp3/io/vpParseArgv.h>
#include <visp3/sensor/vp1394TwoGrabber.h>

#if (!defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))) &&       \
    (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK))

static int save = 0;
static int layerToDisplay = 0xF; // 0xF = 1111 => all the layers are selected
static vpLaserScan shm_laserscan[4];
double time_offset = 0;
#ifdef VISP_HAVE_PTHREAD
pthread_mutex_t shm_mutex;
#endif
std::string output_path;

void *laser_display_and_save_loop(void *);
void *laser_acq_loop(void *);
void *camera_acq_and_display_loop(void *);

void *laser_display_and_save_loop(void *)
{
  vpImage<unsigned char> map(700, 300);
  map = 0;
  unsigned int width = map.getWidth();
  unsigned int height = map.getHeight();
  vpImagePoint O; // Beam origin
  O.set_i(height);
  O.set_j(width / 2.);
  vpScanPoint p;
  vpColor color[4]; // one color per layer
  char filename[FILENAME_MAX];
  std::ofstream fdscan;
  vpLaserScan laserscan[4];

  for (int layer = 0; layer < 4; layer++) {
    switch (layer) {
    case 0:
      color[layer] = vpColor::red;
      break;
    case 1:
      color[layer] = vpColor::green;
      break;
    case 2:
      color[layer] = vpColor::blue;
      break;
    case 3:
      color[layer] = vpColor::yellow;
      break;
    }
  }

  vpDisplay *display = NULL;
#ifdef VISP_HAVE_MODULE_GUI
#if defined(VISP_HAVE_X11)
  display = new vpDisplayX;
#elif defined(VISP_HAVE_GTK)
  display = new vpDisplayGTK;
#endif
  display->init(map, 10, 10, "Laser scan");
#endif

  unsigned int iter = 0;
  for (;;) {

#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
    vpDisplay::display(map);
#endif

#ifdef VISP_HAVE_PTHREAD
    pthread_mutex_lock(&shm_mutex);
#endif
    for (int layer = 0; layer < 4; layer++)
      laserscan[layer] = shm_laserscan[layer];
#ifdef VISP_HAVE_PTHREAD
    pthread_mutex_unlock(&shm_mutex);
#endif

    // Parse the four layers
    for (int layer = 0; layer < 4; layer++) {
      if (!((0x1 << layer) & layerToDisplay)) {
        std::cout << "Layer " << layer + 1 << " is not displayed" << std::endl;
        continue;
      }

      std::vector<vpScanPoint> pointsLayer = laserscan[layer].getScanPoints();

      if (save) {
        // Set the scan data filename to store the measures
        snprintf(filename, FILENAME_MAX, "%s/scan%04u-layer%d.txt", output_path.c_str(), iter, layer + 1);
        fdscan.open(filename);

        // Write the file header
        fdscan << "# Scan layer [1 to 4] : " << layer + 1 << std::endl
               << "# Start timestamp (s) : " << laserscan[layer].getStartTimestamp() - time_offset << std::endl
               << "# End timestamp (s)   : " << laserscan[layer].getEndTimestamp() - time_offset << std::endl
               << "# Data : \"radial distance (m)\" \"horizontal angle "
                  "(rad)\" \"vertical angle (rad)\" \"X (m)\" \"Y (m)\" \"Z "
                  "(m)\""
               << std::endl;
      }

      vpImagePoint E;        // Beam echo
      double resolution = 5; // 100 pixels = 1 meter - increase this value to
                             // see better near info
      for (unsigned int i = 0; i < pointsLayer.size(); i++) {
        p = pointsLayer[i];
        E.set_i(height - resolution * p.getRadialDist() * cos(p.getHAngle()));
        E.set_j(width / 2. - resolution * p.getRadialDist() * sin(p.getHAngle()));
// std::cout << "E: " << E << std::endl;
#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
        vpDisplay::displayLine(map, O, E, color[layer]);
#endif
        if (save) {
          // Save the measures in the file
          fdscan << p << std::endl;
        }
      }
      if (save) {
        fdscan.close();
      }
    }
#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
    vpDisplay::flush(map);
#endif
    iter++;
    // std::cout << "display time: " << vpTime::measureTimeMs() - t1 <<
    // std::endl;
  }
  delete display;
  return NULL;
}

void *laser_acq_loop(void *)
{
  std::string ip = "131.254.12.119";

  vpSickLDMRS laser;
  laser.setIpAddress(ip);
  laser.setup();
  vpLaserScan laserscan[4];

  for (;;) {
    double t1 = vpTime::measureTimeMs();
    if (laser.measure(laserscan) == false)
      continue;

#ifdef VISP_HAVE_PTHREAD
    pthread_mutex_lock(&shm_mutex);
#endif
    for (int layer = 0; layer < 4; layer++)
      shm_laserscan[layer] = laserscan[layer];
#ifdef VISP_HAVE_PTHREAD
    pthread_mutex_unlock(&shm_mutex);
#endif

    std::cout << "laser acq time: " << vpTime::measureTimeMs() - t1 << std::endl;
  }

  return NULL;
}

void *camera_acq_and_display_loop(void *)
{
#ifdef VISP_HAVE_DC1394
  try {
    // Initialize the firewire framegrabber
    vp1394TwoGrabber g; // Create a grabber based on libdc1394-2.x third party lib

    // If no camera found return
    if (g.getNumCameras() == 0)
      return NULL;

    //     g.setVideoMode(vp1394TwoGrabber::vpVIDEO_MODE_640x480_MONO8);
    //     g.setFramerate(vp1394TwoGrabber::vpFRAMERATE_60);

    vpImage<unsigned char> I; // Create a gray level image container
    vpImage<unsigned char> Q; // Create a quarter size gray level image container
    g.acquire(I);             // Acquire an image
    I.quarterSizeImage(Q);

    vpDisplay *display = NULL;
#ifdef VISP_HAVE_MODULE_GUI
#if defined(VISP_HAVE_X11)
    display = new vpDisplayX;
#elif defined(VISP_HAVE_GTK)
    display = new vpDisplayGTK;
#endif
    display->init(Q, 320, 10, "Camera");
#endif

    // Create a file with cameraimage time stamps
    std::ofstream fdimage_ts;
    if (save) {
      std::string filename = output_path + "/image_timestamp.txt";
      fdimage_ts.open(filename.c_str());
      fdimage_ts << "# [image name] [time stamp in second]" << std::endl;
    }
    unsigned iter = 0;
    char filename[FILENAME_MAX];
    uint64_t timestamp;
    uint32_t id;
    for (;;) {
      dc1394video_frame_t *frame = g.dequeue(I, timestamp, id); // Acquire an image
      I.quarterSizeImage(Q);
      double image_timestamp = timestamp / 1000000. - time_offset;
      std::cout << "camera timestamp: " << image_timestamp << " s " << std::endl;
      if (save) {
        // Set the image filename
        snprintf(filename, FILENAME_MAX, "%s/image%04u.png", output_path.c_str(), iter);
        vpImageIo::write(Q, filename);
        fdimage_ts << filename << " " << image_timestamp << std::endl;
      }
#if (defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_GTK))
      vpDisplay::display(Q);
      vpDisplay::flush(Q);
#endif
      g.enqueue(frame);

      iter++;
    }
    delete display;
    if (save) {
      fdimage_ts.close();
    }
  } catch (...) {
  }
#endif
  return NULL;
}

int main(int argc, const char **argv)
{
  try {
    output_path = "data";
    // Test if the output path directory exist. If no try to create it
    if (vpIoTools::checkDirectory(output_path) == false) {
      try {
        // Create a directory with name "username"
        vpIoTools::makeDirectory(output_path);
      } catch (...) {
        std::cout << "Cannot create " << output_path << " directory" << std::endl;
        return EXIT_FAILURE;
      }
    }

    // Parse the command line to set the variables
    vpParseArgv::vpArgvInfo argTable[] = {
        {"-layer", vpParseArgv::ARGV_INT, (char *)NULL, (char *)&layerToDisplay,
         "The layer to display:\n"
         "\t\t. 0x1 for layer 1.\n"
         "\t\t. 0x2 for layer 2.\n"
         "\t\t. 0x4 for layer 3.\n"
         "\t\t. 0x8 for layer 4.\n"
         "\t\tTo display all the layers you should set 0xF value."},
        {"-save", vpParseArgv::ARGV_INT, (char *)NULL, (char *)&save, "Turn to 1 in order to save data."},
        {"-h", vpParseArgv::ARGV_HELP, (char *)NULL, (char *)NULL,
         "Display one or more measured layers form a Sick LD-MRS laser "
         "scanner."},
        {(char *)NULL, vpParseArgv::ARGV_END, (char *)NULL, (char *)NULL, (char *)NULL}};

    // Read the command line options
    if (vpParseArgv::parse(&argc, argv, argTable,
                           vpParseArgv::ARGV_NO_LEFTOVERS | vpParseArgv::ARGV_NO_ABBREV |
                               vpParseArgv::ARGV_NO_DEFAULTS)) {
      return (EXIT_FAILURE);
    }

    time_offset = vpTime::measureTimeSecond();
#ifdef VISP_HAVE_PTHREAD
    pthread_t thread_camera_acq;
    pthread_t thread_laser_acq;
    pthread_t thread_laser_display;
    pthread_create(&thread_camera_acq, NULL, &camera_acq_and_display_loop, NULL);
    pthread_create(&thread_laser_acq, NULL, &laser_acq_loop, NULL);
    pthread_create(&thread_laser_display, NULL, &laser_display_and_save_loop, NULL);
    pthread_join(thread_camera_acq, 0);
    pthread_join(thread_laser_acq, 0);
    pthread_join(thread_laser_display, 0);
#endif

    return EXIT_SUCCESS;
  } catch (const vpException &e) {
    std::cout << "Catch an exception: " << e << std::endl;
    return EXIT_FAILURE;
  }
}

#elif !(defined(VISP_HAVE_X11) || defined(VISP_HAVE_GTK))
int main()
{
  std::cout << "You do not have X11, or GTK functionalities to display images..." << std::endl;
  std::cout << "Tip if you are on a unix-like system:" << std::endl;
  std::cout << "- Install X11, configure again ViSP using cmake and build again this example" << std::endl;
  std::cout << "Tip if you are on a windows-like system:" << std::endl;
  std::cout << "- Install GTK, configure again ViSP using cmake and build again this example" << std::endl;
  return EXIT_SUCCESS;
}
#else // #ifdef UNIX and display

int main()
{
  std::cout << "This example is only working on unix-like platforms \n"
            << "since the Sick LD-MRS driver was not ported to Windows." << std::endl;
  return EXIT_SUCCESS;
}

#endif // #ifdef UNIX