lidar code for ROC318
Dependencies: BufferedSerial mbed
Diff: rplidar/RPlidar.cpp
- Revision:
- 0:0791d48ee421
diff -r 000000000000 -r 0791d48ee421 rplidar/RPlidar.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rplidar/RPlidar.cpp Fri Oct 19 17:42:05 2018 +0000 @@ -0,0 +1,364 @@ +/* + * RoboPeak RPLIDAR Driver for Arduino + * RoboPeak.com + * + * Copyright (c) 2014, RoboPeak + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "rplidar.h" +//BufferedSerial _bined_serialdev( PA_11, PA_12); // tx, rx +Timer timers; +RPLidar::RPLidar() +{ + + _currentMeasurement.distance = 0; + _currentMeasurement.angle = 0; + _currentMeasurement.quality = 0; + _currentMeasurement.startBit = 0; +} + + +RPLidar::~RPLidar() +{ + end(); +} + +// open the given serial interface and try to connect to the RPLIDAR +/* +bool RPLidar::begin(BufferedSerial &serialobj) +{ + + //Serial.begin(115200); + + if (isOpen()) { + end(); + } + _bined_serialdev = &serialobj; + // _bined_serialdev->end(); + _bined_serialdev->baud(RPLIDAR_SERIAL_BAUDRATE); +} +*/ +void RPLidar::begin(BufferedSerial &serialobj) +{ + _bined_serialdev = &serialobj; + timers.start(); + _bined_serialdev->baud(RPLIDAR_SERIAL_BAUDRATE); +} +// close the currently opened serial interface +void RPLidar::end() +{/* + if (isOpen()) { + _bined_serialdev->end(); + _bined_serialdev = NULL; + }*/ +} + + +// check whether the serial interface is opened +/* +bool RPLidar::isOpen() +{ + return _bined_serialdev?true:false; +} +*/ +// ask the RPLIDAR for its health info + +u_result RPLidar::getHealth(rplidar_response_device_health_t & healthinfo, _u32 timeout) +{ + _u32 currentTs = timers.read_ms(); + _u32 remainingtime; + + _u8 *infobuf = (_u8 *)&healthinfo; + _u8 recvPos = 0; + + rplidar_ans_header_t response_header; + u_result ans; + + + // if (!isOpen()) return RESULT_OPERATION_FAIL; + + { + if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_DEVICE_HEALTH, NULL, 0))) { + return ans; + } + + if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) { + return ans; + } + + // verify whether we got a correct header + if (response_header.type != RPLIDAR_ANS_TYPE_DEVHEALTH) { + return RESULT_INVALID_DATA; + } + + if ((response_header.size) < sizeof(rplidar_response_device_health_t)) { + return RESULT_INVALID_DATA; + } + + while ((remainingtime=timers.read_ms() - currentTs) <= timeout) { + int currentbyte = _bined_serialdev->getc(); + if (currentbyte < 0) continue; + + infobuf[recvPos++] = currentbyte; + + if (recvPos == sizeof(rplidar_response_device_health_t)) { + return RESULT_OK; + } + } + } + return RESULT_OPERATION_TIMEOUT; +} +// ask the RPLIDAR for its device info like the serial number +u_result RPLidar::getDeviceInfo(rplidar_response_device_info_t & info, _u32 timeout ) +{ + _u8 recvPos = 0; + _u32 currentTs = timers.read_ms(); + _u32 remainingtime; + _u8 *infobuf = (_u8*)&info; + rplidar_ans_header_t response_header; + u_result ans; + + // if (!isOpen()) return RESULT_OPERATION_FAIL; + + { + if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_DEVICE_INFO,NULL,0))) { + return ans; + } + + if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) { + return ans; + } + + // verify whether we got a correct header + if (response_header.type != RPLIDAR_ANS_TYPE_DEVINFO) { + return RESULT_INVALID_DATA; + } + + if (response_header.size < sizeof(rplidar_response_device_info_t)) { + return RESULT_INVALID_DATA; + } + + while ((remainingtime=timers.read_ms() - currentTs) <= timeout) { + int currentbyte = _bined_serialdev->getc(); + if (currentbyte<0) continue; + infobuf[recvPos++] = currentbyte; + + if (recvPos == sizeof(rplidar_response_device_info_t)) { + return RESULT_OK; + } + } + } + + return RESULT_OPERATION_TIMEOUT; +} + +// stop the measurement operation +u_result RPLidar::stop() +{ +// if (!isOpen()) return RESULT_OPERATION_FAIL; + u_result ans = _sendCommand(RPLIDAR_CMD_STOP,NULL,0); + return ans; +} + +// start the measurement operation +u_result RPLidar::startScan(bool force, _u32 timeout) +{ + u_result ans; + +// if (!isOpen()) return RESULT_OPERATION_FAIL; + + stop(); //force the previous operation to stop + + + ans = _sendCommand(force?RPLIDAR_CMD_FORCE_SCAN:RPLIDAR_CMD_SCAN, NULL, 0); + if (IS_FAIL(ans)) return ans; + + // waiting for confirmation + rplidar_ans_header_t response_header; + if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) { + return ans; + } + + // verify whether we got a correct header + if (response_header.type != RPLIDAR_ANS_TYPE_MEASUREMENT) { + return RESULT_INVALID_DATA; + } + + if (response_header.size < sizeof(rplidar_response_measurement_node_t)) { + return RESULT_INVALID_DATA; + } + + return RESULT_OK; +} + +// wait for one sample point to arrive +u_result RPLidar::waitPoint(_u32 timeout) +{ + _u32 currentTs = timers.read_ms(); + _u32 remainingtime; + rplidar_response_measurement_node_t node; + _u8 *nodebuf = (_u8*)&node; + + _u8 recvPos = 0; + + while ((remainingtime = timers.read_ms() - currentTs) <= timeout) { + int currentbyte = _bined_serialdev->getc(); + if (currentbyte<0) continue; +//Serial.println(currentbyte); + switch (recvPos) { + case 0: // expect the sync bit and its reverse in this byte { + { + _u8 tmp = (currentbyte>>1); + if ( (tmp ^ currentbyte) & 0x1 ) { + // pass + } else { + continue; + } + + } + break; + case 1: // expect the highest bit to be 1 + { + if (currentbyte & RPLIDAR_RESP_MEASUREMENT_CHECKBIT) { + // pass + } else { + recvPos = 0; + continue; + } + } + break; + } + nodebuf[recvPos++] = currentbyte; + if (recvPos == sizeof(rplidar_response_measurement_node_t)) { + // store the data ... + _currentMeasurement.distance = node.distance_q2/4.0f; + _currentMeasurement.angle = (node.angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f; + _currentMeasurement.quality = (node.sync_quality>>RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT); + _currentMeasurement.startBit = (node.sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT); + ang = _currentMeasurement.angle; + dis = _currentMeasurement.distance; + + + if(ang>=angMin&&ang<=angMax)Data[ang] = dis; + + return RESULT_OK; + } + + + } + + return RESULT_OPERATION_TIMEOUT; +} + + +void RPLidar::setAngle(int min,int max){ + angMin = min; + angMax = max; +} +void RPLidar::get_lidar(){ + if (!IS_OK(waitPoint())) startScan(); +} +u_result RPLidar::_sendCommand(_u8 cmd, const void * payload, size_t payloadsize) +{ + + rplidar_cmd_packet_t pkt_header; + rplidar_cmd_packet_t * header = &pkt_header; + _u8 checksum = 0; + + if (payloadsize && payload) { + cmd |= RPLIDAR_CMDFLAG_HAS_PAYLOAD; + } + + header->syncByte = RPLIDAR_CMD_SYNC_BYTE; + header->cmd_flag = cmd; + + // send header first + _bined_serialdev->putc(header->syncByte ); + _bined_serialdev->putc(header->cmd_flag ); + + // _bined_serialdev->write( (uint8_t *)header, 2); + + if (cmd & RPLIDAR_CMDFLAG_HAS_PAYLOAD) { + checksum ^= RPLIDAR_CMD_SYNC_BYTE; + checksum ^= cmd; + checksum ^= (payloadsize & 0xFF); + + // calc checksum + for (size_t pos = 0; pos < payloadsize; ++pos) { + checksum ^= ((_u8 *)payload)[pos]; + } + + // send size + _u8 sizebyte = payloadsize; + _bined_serialdev->putc(sizebyte); + // _bined_serialdev->write((uint8_t *)&sizebyte, 1); + + // send payload + // _bined_serialdev.putc((uint8_t )payload); + // _bined_serialdev->write((uint8_t *)&payload, sizebyte); + + // send checksum + _bined_serialdev->putc(checksum); + // _bined_serialdev->write((uint8_t *)&checksum, 1); + + } + + return RESULT_OK; +} + +u_result RPLidar::_waitResponseHeader(rplidar_ans_header_t * header, _u32 timeout) +{ + _u8 recvPos = 0; + _u32 currentTs = timers.read_ms(); + _u32 remainingtime; + _u8 *headerbuf = (_u8*)header; + while ((remainingtime = timers.read_ms() - currentTs) <= timeout) { + + int currentbyte = _bined_serialdev->getc(); + if (currentbyte<0) continue; + switch (recvPos) { + case 0: + if (currentbyte != RPLIDAR_ANS_SYNC_BYTE1) { + continue; + } + break; + case 1: + if (currentbyte != RPLIDAR_ANS_SYNC_BYTE2) { + recvPos = 0; + continue; + } + break; + } + headerbuf[recvPos++] = currentbyte; + + if (recvPos == sizeof(rplidar_ans_header_t)) { + return RESULT_OK; + } + + + } + + return RESULT_OPERATION_TIMEOUT; +}