-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathLaserScan.h
189 lines (156 loc) · 5.03 KB
/
LaserScan.h
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
#include "rplidar.h" //RPLIDAR standard sdk, all-in-one header
#include "TelemetryPoint.h"
#include <math.h>
#define PI 3.14159265
#ifndef _countof
#define _countof(_Array) (int)(sizeof(_Array) / sizeof(_Array[0]))
#endif
using namespace rp::standalone::rplidar;
class LaserScan
{
public:
LaserScan(const char *com_port_arg, _u32 baudrate_arg);
int scan(TelemetryPoint result_buffer[], const int buffer_length);
bool start();
bool stop();
bool connect();
TelemetryPoint *scan();
private:
bool checkRPLIDARHealth(RPlidarDriver *drv);
float getAngle(const rplidar_response_measurement_node_hq_t &node);
bool is_connected;
const char *com_port;
_u32 baudrate;
RPlidarDriver *drv;
rplidar_response_measurement_node_hq_t nodes[8192];
size_t node_count;
};
LaserScan::LaserScan(const char *com_port_arg, _u32 baudrate_arg)
{
com_port = com_port_arg;
baudrate = baudrate_arg;
is_connected = false;
drv = RPlidarDriver::CreateDriver(DRIVER_TYPE_SERIALPORT);
node_count = _countof(nodes);
if (!drv)
{
fprintf(stderr, "insufficent memory, exit\n");
exit(-2);
}
}
int LaserScan::scan(TelemetryPoint result_buffer[], const int buffer_length)
{
int result_size = 0;
TelemetryPoint *cur = result_buffer;
u_result op_result = drv->grabScanDataHq(nodes, node_count);
if (IS_OK(op_result))
{
drv->ascendScanData(nodes, node_count);
for (int pos = 0; pos < (int)node_count && result_size < buffer_length; ++pos)
{
int16_t quality = round(nodes[pos].quality >> RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT);
if(quality > 0)
{
//convert to centi-meters by dividing by 10, millimeter resolution isn't useful
float distance = (nodes[pos].dist_mm_q2 / 4.0f)/10.0;
float angle = (getAngle(nodes[pos]) * 3.14159265 / 180);
int16_t x = roundf(sin (angle) * distance);
int16_t y = roundf(cos (angle) * distance);
//dedup points that are essentailly identical after we converted to centimeters, this reduces calculation costs
//later and allows fo even naive scoring algos to work well without worrying about deduping.
if(result_size < 1 || result_buffer[result_size-1].x != x || result_buffer[result_size-1].y != y){
cur->x = x;
cur->y = y;
//cur->quality = quality;
cur->distance = distance;
cur->angle = angle;
result_size++;
cur = result_buffer + result_size;
}
}
}
}
return result_size;
}
bool LaserScan::stop()
{
is_connected = false;
if(drv != NULL)
{
drv->stop();
drv->stopMotor();
RPlidarDriver::DisposeDriver(drv);
drv = NULL;
}
return true;
}
bool LaserScan::start()
{
u_result op_result;
rplidar_response_device_info_t devinfo;
if(!drv)
drv = RPlidarDriver::CreateDriver(DRIVER_TYPE_SERIALPORT);
if (IS_OK(drv->connect(com_port, baudrate)))
{
op_result = drv->getDeviceInfo(devinfo);
if (!IS_OK(op_result))
{
delete drv;
drv = NULL;
fprintf(stderr, "Error, cannot bind to the specified serial port %s.\n", com_port);
return false;
}
}
// print out the device serial number, firmware and hardware version number..
printf("RPLIDAR S/N: ");
for (int pos = 0; pos < 16 ; ++pos)
{
printf("%02X", devinfo.serialnum[pos]);
}
printf("\n"
"Firmware Ver: %d.%02d\n"
"Hardware Rev: %d\n"
, devinfo.firmware_version >> 8
, devinfo.firmware_version & 0xFF
, (int)devinfo.hardware_version);
// check health...
if (!checkRPLIDARHealth(drv))
{
return false;
}
drv->startMotor();
// start scan...
drv->startScan(0, 1);
is_connected = true;
return true;
}
bool LaserScan::checkRPLIDARHealth(RPlidarDriver *drv)
{
u_result op_result;
rplidar_response_device_health_t healthinfo;
op_result = drv->getHealth(healthinfo);
if (IS_OK(op_result)) // the macro IS_OK is the preperred way to judge whether the operation is succeed.
{
printf("RPLidar health status : %d\n", healthinfo.status);
if (healthinfo.status == RPLIDAR_STATUS_ERROR)
{
fprintf(stderr, "Error, rplidar internal error detected. Please reboot the device to retry.\n");
// enable the following code if you want rplidar to be reboot by software
// drv->reset();
return false;
}
else
{
return true;
}
}
else
{
fprintf(stderr, "Error, cannot retrieve the lidar health code: %x\n", op_result);
return false;
}
}
float LaserScan::getAngle(const rplidar_response_measurement_node_hq_t &node)
{
return node.angle_z_q14 * 90.f / 16384.f;
}