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