5 \author Satofumi KAMIMURA
7 $Id: urg_ctrl.c 1714 2010-02-21 20:53:28Z satofumi $
10 #include "math_utils.h"
12 #include "scip_handler.h"
13 #include "urg_errno.h"
14 #include "serial_ctrl.h"
15 #include "serial_utils.h"
16 #include "serial_errno.h"
23 #if defined(WINDOWS_OS)
24 #define snprintf _snprintf
29 ScipTimeout = 1000, /*!< [msec] */
30 EachTimeout = 100 * 2, /*!< URG series timeout x 2 [msec] */
36 void urg_initialize(urg_t *urg)
38 serial_initialize(&urg->serial_);
39 urg->errno_ = UrgNoError;
40 urg->last_timestamp_ = 0;
44 static int urg_firstConnection(urg_t *urg, long baudrate)
46 long try_baudrates[] = { 115200, 19200, 38400 };
47 int try_size = sizeof(try_baudrates) / sizeof(try_baudrates[0]);
53 /* The baud rate to be connected is replaced with the first element
55 for (i = 1; i < try_size; ++i) {
56 if (baudrate == try_baudrates[i]) {
57 long swap_tmp = try_baudrates[i];
58 try_baudrates[i] = try_baudrates[0];
59 try_baudrates[0] = swap_tmp;
64 /* Try to connect with the specified baudrate , and check for response */
65 for (i = 0; i < try_size; ++i) {
67 /* Change host side baudrate */
68 ret = serial_setBaudrate(&urg->serial_, try_baudrates[i]);
73 serial_clear(&urg->serial_);
76 ret = scip_qt(&urg->serial_, &reply, ScipWaitReply);
77 if (ret == UrgSerialRecvFail) {
78 /* If there is no response, consider that there is mismatch in baudrate */
82 if ((ret == UrgMismatchResponse) && (reply != -0xE)) {
83 /* Process when response from MD/MS command is received */
84 /* Read out all data and then proceed for the next one */
85 /* (reply == -0xE) means SCIP1.1 error 'E' */
86 serial_clear(&urg->serial_);
87 serial_skip(&urg->serial_, ScipTimeout, EachTimeout);
91 /* If the response is returned, consider that sensor is already in SCIP2.0
92 mode and no need to send SCIP2.0 */
94 if ((ret = scip_scip20(&urg->serial_)) < 0) {
95 /* If there is no response , continue with other baudrate */
99 /* SCIP1.1 protocol */
104 /* Returns if there is no need to change baudrate */
105 if (baudrate == try_baudrates[i]) {
109 /* Change the baud rate as specified by URG */
111 if (scip_ss(&urg->serial_, baudrate) < 0) {
115 /* In case of serial communication, it is necessary to wait for
116 one scan after baud rate is changed. */
117 int reply_msec = ticks() - pre_ticks;
118 delay((reply_msec * 4 / 3) + 10);
120 return serial_setBaudrate(&urg->serial_, baudrate);
124 return UrgAdjustBaudrateFail;
128 static void urg_t_initialize(urg_t *urg)
130 urg->parameters_.area_max_ = 0;
131 urg->parameters_.scan_rpm_ = 0;
132 urg->parameters_.sensor_type[0] = '\0';
133 urg->remain_byte_ = 0;
137 /* Open serial device and initialize URG */
138 int urg_connect(urg_t *urg, const char *device, long baudrate)
141 urg_t_initialize(urg);
143 /* Open serial communication */
144 ret = serial_connect(&urg->serial_, device, baudrate);
146 urg->errno_ = UrgSerialConnectionFail;
149 // change timestamp resolution in Windows OS
153 ret = urg_firstConnection(urg, baudrate);
156 serial_disconnect(&urg->serial_);
160 /* Update parameter information, nothing but an initialization */
161 ret = scip_pp(&urg->serial_, &urg->parameters_);
164 serial_disconnect(&urg->serial_);
167 urg->skip_lines_ = 1;
168 urg->skip_frames_ = 0;
169 urg->capture_times_ = 0;
170 urg->is_laser_on_ = UrgLaserUnknown;
171 urg->remain_times_ = 0;
173 urg->errno_ = UrgNoError;
178 void urg_disconnect(urg_t *urg)
180 /* To stop MD/MS command */
182 serial_skip(&urg->serial_, ScipTimeout, EachTimeout);
184 /* Disconnect serial connection */
185 serial_disconnect(&urg->serial_);
189 int urg_isConnected(const urg_t *urg)
191 /* Return 0, if serial connectionis valid */
192 return serial_isConnected(&urg->serial_);
196 const char *urg_error(const urg_t *urg)
198 return urg_strerror(urg->errno_);
202 int urg_versionLines(urg_t *urg, char* lines[], int lines_max)
204 if (! urg_isConnected(urg)) {
207 return scip_vv(&urg->serial_, lines, lines_max);
211 /* Send PP command. Analyse and store the response */
212 int urg_parameters(urg_t *urg, urg_parameter_t* parameters)
216 if (urg_isConnected(urg)) {
217 *parameters = urg->parameters_;
219 ret = scip_pp(&urg->serial_, &urg->parameters_);
221 *parameters = urg->parameters_;
225 urg->errno_ = UrgNoError;
230 const char* urg_model(const urg_t *urg)
232 return urg->parameters_.sensor_type;
236 int urg_dataMax(const urg_t *urg)
238 return urg->parameters_.area_max_ + 1;
242 int urg_scanMsec(const urg_t *urg)
244 int scan_rpm = urg->parameters_.scan_rpm_;
245 return (scan_rpm <= 0) ? 1 : (1000 * 60 / scan_rpm);
249 long urg_maxDistance(const urg_t *urg)
251 return urg->parameters_.distance_max_;
255 long urg_minDistance(const urg_t *urg)
257 return urg->parameters_.distance_min_;
261 int urg_setSkipLines(urg_t *urg, int lines)
263 /* Register number of lines to be skipped */
267 if ((lines < 0) || (lines > 99)) {
271 urg->skip_lines_ = lines;
276 int urg_setSkipFrames(urg_t *urg, int frames)
278 /* Register number of frames to be skipped */
279 if ((frames < 0) || (frames > 9)) {
283 urg->skip_frames_ = frames;
288 int urg_setCaptureTimes(urg_t *urg, int times)
290 /* Register frequency at which MD/MS data is received */
291 if ((times < 0) || (times >= 100)) {
292 urg->capture_times_ = 0;
294 urg->capture_times_ = times;
301 int urg_remainCaptureTimes(const urg_t *urg)
303 if (urg->capture_times_ == 0) {
304 /* Get data infinitely */
308 return urg->remain_times_;
313 int urg_requestData(urg_t *urg,
314 urg_request_type request_type,
318 char buffer[] = "MDsssseeeellstt\n";
320 if (first_index == URG_FIRST) {
321 first_index = urg->parameters_.area_min_;
323 if (last_index == URG_LAST) {
324 last_index = urg->parameters_.area_max_;
327 if ((request_type == URG_GD) || (request_type == URG_GS) ||
328 (request_type == URG_GD_INTENSITY)) {
330 /* In case of GD/GS */
331 snprintf(buffer, 14, "G%c%04d%04d%02d\n",
332 (((request_type == URG_GD) ||
333 (request_type == URG_GD_INTENSITY)) ? 'D' : 'S'),
334 first_index, last_index,
337 /* Switch on the laser if laser is in off state */
338 if (urg->is_laser_on_ != UrgLaserOn) {
339 int ret = urg_laserOn(urg);
345 } else if ((request_type == URG_MD) || (request_type == URG_MS) ||
346 (request_type == URG_MD_INTENSITY)) {
347 char type = (request_type == URG_MS) ? 'S' : 'D';
349 /* In case of MD/MS */
350 snprintf(buffer, 17, "M%c%04d%04d%02d%d%02d\n",
352 first_index, last_index,
355 urg->capture_times_);
356 urg->remain_times_ = urg->capture_times_;
359 urg->errno_ = UrgInvalidArgs;;
363 if ((request_type == URG_GD_INTENSITY) ||
364 (request_type == URG_MD_INTENSITY)) {
365 if (! strcmp("UTM-30LX", urg->parameters_.sensor_type)) {
366 if (request_type == URG_GD_INTENSITY) {
367 urg->errno_ = UtmNoGDIntensity;
370 /* use ME command in TOF series */
385 return scip_send(&urg->serial_, buffer);
389 /* Decode 6bit data of URG */
390 static long decode(const char* data, int data_byte)
392 const char* p = data;
393 const char* last_p = p + data_byte;
399 value |= *p++ - 0x30;
405 static int convertRawData(long data[], int data_max,
406 const char* buffer, int buffer_size, int filled,
407 int is_me_type, int data_bytes, int skip_lines,
408 int store_last, urg_t* urg)
413 int remain_byte = urg->remain_byte_;
415 long *data_p = data + filled;
419 if (data_max > store_last) {
420 data_max = store_last;
424 /* Initialize the number of data, which are remained when the first time
429 if (buffer_size <= 0) {
433 /* If there is any data left, then process that data */
434 if (remain_byte > 0) {
435 memcpy(&urg->remain_data_[remain_byte], buffer, data_bytes - remain_byte);
437 if ((filled + n) > data_max) {
438 n = data_max - filled;
440 length = decode(urg->remain_data_, data_bytes);
441 for (j = 0; j < n; ++j) {
447 for (j = 0; j < skip_lines; ++j) {
454 /* Process one line of data */
455 n = buffer_size - data_bytes;
456 for (i = (data_bytes - remain_byte) % data_bytes; i <= n; i += data_bytes) {
457 length = decode(&buffer[i], data_bytes);
458 for (j = 0; j < skip_lines; ++j) {
459 if (filled >= data_max) {
468 for (j = 0; j < skip_lines; ++j) {
475 /* Save the remaining data */
476 urg->remain_byte_ = buffer_size - i;
477 memcpy(urg->remain_data_, &buffer[i], urg->remain_byte_);
483 static int checkSum(const char buffer[], int size, char actual_sum)
485 const char *p = buffer;
486 const char *last_p = p + size;
487 char expected_sum = 0x00;
490 expected_sum += *p++;
492 expected_sum = (expected_sum & 0x3f) + 0x30;
494 return (expected_sum == actual_sum) ? 0 : -1;
498 static int atoi_substr(const char *str, size_t len)
502 strncpy(buffer, str, len);
509 static int internal_receiveData(urg_t *urg, long data[], int data_max,
510 int store_first, int store_last,
521 MD_MS_Length = 15, /* Length of MD, MS */
522 GD_GS_Length = 12, /* Length of GD, GS */
526 char buffer[UrgLineWidth];
528 int is_echoback = False;
532 char current_type[] = "xx";
533 int current_first = -1;
534 int current_last = -1;
535 int current_skip_lines = -1;
536 int current_skip_frames = -1;
537 int current_capture_times = -1;
538 int current_data_bytes = 3;
540 int timeout = ScipTimeout;
542 /* Initialization of time stamp */
543 urg->last_timestamp_ = UrgInvalidTimestamp;
545 urg->errno_ = UrgNoResponse;
548 n = serial_getLine(&urg->serial_, buffer, ScipLineWidth, timeout);
551 //fprintf(stderr, "%d: %s\n", ticks(), buffer);
562 /* ignore echoback */
563 if (checkSum(buffer, n - 1, buffer[n - 1]) < 0) {
564 urg->errno_ = UrgInvalidResponse;
572 if (lines > Timestamp) {
574 filled = convertRawData(data, data_max, buffer, n - 1, filled,
575 is_me_type, current_data_bytes, skip_lines,
578 } else if (lines == EchoBack) {
580 if ((n != GD_GS_Length) && (n != MD_MS_Length)) {
581 /* Return if response is not GD/GS, MD/MS */
582 urg->errno_ = UrgInvalidResponse;
588 /* Response command */
589 current_type[0] = buffer[0];
590 current_type[1] = buffer[1];
591 if (! strncmp("ME", current_type, 2)) {
595 /* Initialisation of receiving settings */
596 current_first = atoi_substr(&buffer[2], 4);
597 current_last = atoi_substr(&buffer[6], 4);
598 current_skip_lines = atoi_substr(&buffer[10], 2);
600 if ((current_first - store_first) >= data_max) {
605 /* Arrangement of dummy data */
606 dummy_last = current_first - store_first;
607 for (filled = 0; filled < dummy_last; ++filled) {
608 data[filled] = InvalidRange;
611 if (n == GD_GS_Length) {
612 /* Ignore receive frame settings and number of frames settings for
614 urg->remain_times_ = 0;
617 current_skip_frames = atoi_substr(&buffer[12], 1);
618 current_capture_times = atoi_substr(&buffer[13], 2);
620 /* In case of MD/MS, store the remaining number of scans. */
621 urg->remain_times_ = atoi(&buffer[13]);
623 current_data_bytes = (current_type[1] == 'S') ? 2 : 3;
625 } else if (lines == ReplyCode) {
626 if (! strncmp(buffer, "10", 2)) {
627 urg->is_laser_on_ = UrgLaserOff;
630 /* If response is "0B", ignore all response. Because there is a
631 possibility that the correspondence of the response shifts. */
632 if (! strncmp(buffer, "0B", 2)) {
633 serial_skip(&urg->serial_, ScipTimeout, timeout);
636 /* In case of MD/MS, response = "00" means transition request and hence
637 readout one more line, and then reset the process */
638 if (current_type[0] == 'M' && (! strncmp(buffer, "00", 2))) {
642 } else if (lines == Timestamp) {
643 urg->last_timestamp_ = decode(buffer, 4);
647 timeout = EachTimeout;
654 // fill to urg->parameters_.area_max_ or data_max
655 int last_index = data_max;
656 if (urg->parameters_.area_max_ < last_index) {
657 last_index = urg->parameters_.area_max_;
659 for (; filled <= last_index; ++filled) {
660 data[filled] = InvalidRagne;
669 int urg_receiveData(urg_t *urg, long data[], int data_max)
671 if (! urg_isConnected(urg)) {
674 return internal_receiveData(urg, data, data_max,
675 0, data_max, urg->skip_lines_);
679 int urg_receiveDataWithIntensity(urg_t *urg, long data[], int data_max,
685 n = internal_receiveData(urg, data, data_max,
686 0, data_max, urg->skip_lines_);
688 for (i = 0; i < n; i += 2) {
689 long length = data[i];
691 if ((i + 1) < data_max) {
692 long intensity_value = data[i + 1];
693 intensity[i] = intensity_value;
694 intensity[i + 1] = intensity_value;
695 data[i + 1] = length;
702 int urg_receivePartialData(urg_t *urg, long data[], int data_max,
703 int first_index, int last_index)
705 return internal_receiveData(urg, data, data_max, first_index, last_index, 1);
709 long urg_recentTimestamp(const urg_t *urg)
711 /* Return latest time stamp */
712 return urg->last_timestamp_;
716 double urg_index2rad(const urg_t *urg, int index)
718 double radian = (2.0 * M_PI) *
719 (index - urg->parameters_.area_front_) / urg->parameters_.area_total_;
725 int urg_index2deg(const urg_t *urg, int index)
727 int degree = (int)floor((urg_index2rad(urg, index) * 180 / M_PI) + 0.5);
733 int urg_rad2index(const urg_t *urg, double radian)
736 (int)floor((((radian * urg->parameters_.area_total_) / (2.0*M_PI))
737 + urg->parameters_.area_front_) + 0.5);
741 } else if (index > urg->parameters_.area_max_) {
742 index = urg->parameters_.area_max_;
748 int urg_deg2index(const urg_t *urg, int degree)
750 return urg_rad2index(urg, M_PI * degree / 180.0);
754 int urg_laserOn(urg_t *urg)
756 /* send BM command */
757 int expected_ret[] = { 0, 2, -1 };
758 int send_n = scip_send(&urg->serial_, "BM\n");
760 /* !!! urg->errno = UrgSendFail; */
761 return SerialSendFail;
763 if (scip_recv(&urg->serial_, "BM", NULL, expected_ret, ScipTimeout) == 0) {
764 urg->is_laser_on_ = UrgLaserOn;
771 int urg_laserOff(urg_t *urg)
773 return scip_qt(&urg->serial_, NULL, ScipWaitReply);
777 int urg_reboot(urg_t *urg)
779 int expected_ret[][2] = {
790 for (i = 0; i < 2; ++i) {
791 send_n = scip_send(&urg->serial_, "RB\n");
793 return SerialSendFail;
796 recv_n = scip_recv(&urg->serial_, "RB", NULL,
797 expected_ret[i], ScipTimeout);
803 /* disconnect immediately */
810 int urg_reset(urg_t *urg)
812 return urg_reboot(urg);
816 int urg_enableTimestampMode(urg_t *urg)
819 int expected_ret[] = { 0, 2, -1 };
820 int send_n = scip_send(&urg->serial_, "TM0\n");
822 return SerialSendFail;
824 return scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
828 int urg_disableTimestampMode(urg_t *urg)
831 int expected_ret[] = { 0, 3, -1 };
832 int send_n = scip_send(&urg->serial_, "TM2\n");
834 return SerialSendFail;
836 return scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
840 long urg_currentTimestamp(urg_t *urg)
842 char buffer[ScipLineWidth];
848 int expected_ret[] = { 0, -1 };
849 int send_n = scip_send(&urg->serial_, "TM1\n");
851 return SerialSendFail;
853 ret = scip_recv(&urg->serial_, "TM", NULL, expected_ret, ScipTimeout);
858 /* Decode the timestamp and return */
859 n = serial_getLine(&urg->serial_, buffer, ScipLineWidth, ScipTimeout);
861 timestamp = decode(buffer, 4);
864 /* Read and throw the last response */
865 n = serial_recv(&urg->serial_, buffer, 1, ScipTimeout);
866 if (! serial_isLF(buffer[0])) {
867 serial_ungetc(&urg->serial_, buffer[0]);