rplidar_driver.cpp
Go to the documentation of this file.
00001 /*
00002  *  RPLIDAR SDK
00003  *
00004  *  Copyright (c) 2009 - 2014 RoboPeak Team
00005  *  http://www.robopeak.com
00006  *  Copyright (c) 2014 - 2016 Shanghai Slamtec Co., Ltd.
00007  *  http://www.slamtec.com
00008  *
00009  */
00010 /*
00011  * Redistribution and use in source and binary forms, with or without 
00012  * modification, are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice, 
00015  *    this list of conditions and the following disclaimer.
00016  *
00017  * 2. Redistributions in binary form must reproduce the above copyright notice, 
00018  *    this list of conditions and the following disclaimer in the documentation 
00019  *    and/or other materials provided with the distribution.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
00022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
00023  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
00024  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
00025  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00027  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00028  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00029  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00030  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
00031  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032  *
00033  */
00034 
00035 #include "sdkcommon.h"
00036 #include "hal/abs_rxtx.h"
00037 #include "hal/thread.h"
00038 #include "hal/locker.h"
00039 #include "hal/event.h"
00040 #include "rplidar_driver_serial.h"
00041 
00042 #ifndef min
00043 #define min(a,b)            (((a) < (b)) ? (a) : (b))
00044 #endif
00045 
00046 namespace rp { namespace standalone{ namespace rplidar {
00047 
00048 
00049 // Factory Impl
00050 RPlidarDriver * RPlidarDriver::CreateDriver(_u32 drivertype)
00051 {
00052     switch (drivertype) {
00053     case DRIVER_TYPE_SERIALPORT:
00054         return new RPlidarDriverSerialImpl();
00055     default:
00056         return NULL;
00057     }
00058 }
00059 
00060 
00061 void RPlidarDriver::DisposeDriver(RPlidarDriver * drv)
00062 {
00063     delete drv;
00064 }
00065 
00066 
00067 
00068 // Serial Driver Impl
00069 
00070 RPlidarDriverSerialImpl::RPlidarDriverSerialImpl() 
00071     : _isConnected(false)
00072     , _isScanning(false)
00073     , _isSupportingMotorCtrl(false)
00074 {
00075     _rxtx = rp::hal::serial_rxtx::CreateRxTx();
00076     _cached_scan_node_count = 0;
00077     _cached_sampleduration_std = LEGACY_SAMPLE_DURATION;
00078     _cached_sampleduration_express = LEGACY_SAMPLE_DURATION;
00079 }
00080 
00081 RPlidarDriverSerialImpl::~RPlidarDriverSerialImpl()
00082 {
00083     // force disconnection
00084     disconnect();
00085 
00086     rp::hal::serial_rxtx::ReleaseRxTx(_rxtx);
00087 }
00088 
00089 u_result RPlidarDriverSerialImpl::connect(const char * port_path, _u32 baudrate, _u32 flag)
00090 {
00091     if (isConnected()) return RESULT_ALREADY_DONE;
00092 
00093     if (!_rxtx) return RESULT_INSUFFICIENT_MEMORY;
00094 
00095     {
00096         rp::hal::AutoLocker l(_lock);
00097 
00098         // establish the serial connection...
00099         if (!_rxtx->bind(port_path, baudrate)  ||  !_rxtx->open()) {
00100             return RESULT_INVALID_DATA;
00101         }
00102 
00103         _rxtx->flush(0);
00104     }
00105 
00106     _isConnected = true;
00107 
00108     checkMotorCtrlSupport(_isSupportingMotorCtrl);
00109     stopMotor();
00110 
00111     return RESULT_OK;
00112 }
00113 
00114 void RPlidarDriverSerialImpl::disconnect()
00115 {
00116     if (!_isConnected) return ;
00117     stop();
00118     _rxtx->close();
00119 }
00120 
00121 bool RPlidarDriverSerialImpl::isConnected()
00122 {
00123     return _isConnected;
00124 }
00125 
00126 
00127 u_result RPlidarDriverSerialImpl::reset(_u32 timeout)
00128 {
00129     u_result ans;
00130 
00131     {
00132         rp::hal::AutoLocker l(_lock);
00133 
00134         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_RESET))) {
00135             return ans;
00136         }
00137     }
00138     return RESULT_OK;
00139 }
00140 
00141 u_result RPlidarDriverSerialImpl::getHealth(rplidar_response_device_health_t & healthinfo, _u32 timeout)
00142 {
00143     u_result  ans;
00144     
00145     if (!isConnected()) return RESULT_OPERATION_FAIL;
00146     
00147     _disableDataGrabbing();
00148 
00149     {
00150         rp::hal::AutoLocker l(_lock);
00151 
00152         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_DEVICE_HEALTH))) {
00153             return ans;
00154         }
00155 
00156         rplidar_ans_header_t response_header;
00157         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00158             return ans;
00159         }
00160 
00161         // verify whether we got a correct header
00162         if (response_header.type != RPLIDAR_ANS_TYPE_DEVHEALTH) {
00163             return RESULT_INVALID_DATA;
00164         }
00165 
00166         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00167         if ( header_size < sizeof(rplidar_response_device_health_t)) {
00168             return RESULT_INVALID_DATA;
00169         }
00170 
00171         if (_rxtx->waitfordata(header_size, timeout) != rp::hal::serial_rxtx::ANS_OK) {
00172             return RESULT_OPERATION_TIMEOUT;
00173         }
00174         _rxtx->recvdata(reinterpret_cast<_u8 *>(&healthinfo), sizeof(healthinfo));
00175     }
00176     return RESULT_OK;
00177 }
00178 
00179 u_result RPlidarDriverSerialImpl::getDeviceInfo(rplidar_response_device_info_t & info, _u32 timeout)
00180 {
00181     u_result  ans;
00182     
00183     if (!isConnected()) return RESULT_OPERATION_FAIL;
00184 
00185     _disableDataGrabbing();
00186 
00187     {
00188         rp::hal::AutoLocker l(_lock);
00189 
00190         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_DEVICE_INFO))) {
00191             return ans;
00192         }
00193 
00194         rplidar_ans_header_t response_header;
00195         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00196             return ans;
00197         }
00198 
00199         // verify whether we got a correct header
00200         if (response_header.type != RPLIDAR_ANS_TYPE_DEVINFO) {
00201             return RESULT_INVALID_DATA;
00202         }
00203 
00204         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00205         if (header_size < sizeof(rplidar_response_device_info_t)) {
00206             return RESULT_INVALID_DATA;
00207         }
00208 
00209         if (_rxtx->waitfordata(header_size, timeout) != rp::hal::serial_rxtx::ANS_OK) {
00210             return RESULT_OPERATION_TIMEOUT;
00211         }
00212 
00213         _rxtx->recvdata(reinterpret_cast<_u8 *>(&info), sizeof(info));
00214     }
00215     return RESULT_OK;
00216 }
00217 
00218 u_result RPlidarDriverSerialImpl::getFrequency(bool inExpressMode, size_t count, float & frequency, bool & is4kmode)
00219 {
00220     _u16 sample_duration = inExpressMode?_cached_sampleduration_express:_cached_sampleduration_std;
00221     frequency = 1000000.0f/(count * sample_duration);
00222 
00223     if (sample_duration <= 277) {
00224         is4kmode = true;
00225     } else {
00226         is4kmode = false;
00227     }
00228 
00229         return RESULT_OK;
00230 }
00231 
00232 u_result RPlidarDriverSerialImpl::startScanNormal(bool force, _u32 timeout)
00233 {
00234     u_result ans;
00235     if (!isConnected()) return RESULT_OPERATION_FAIL;
00236     if (_isScanning) return RESULT_ALREADY_DONE;
00237 
00238     stop(); //force the previous operation to stop
00239 
00240     {
00241         rp::hal::AutoLocker l(_lock);
00242 
00243         if (IS_FAIL(ans = _sendCommand(force?RPLIDAR_CMD_FORCE_SCAN:RPLIDAR_CMD_SCAN))) {
00244             return ans;
00245         }
00246 
00247         // waiting for confirmation
00248         rplidar_ans_header_t response_header;
00249         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00250             return ans;
00251         }
00252 
00253         // verify whether we got a correct header
00254         if (response_header.type != RPLIDAR_ANS_TYPE_MEASUREMENT) {
00255             return RESULT_INVALID_DATA;
00256         }
00257 
00258         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00259         if (header_size < sizeof(rplidar_response_measurement_node_t)) {
00260             return RESULT_INVALID_DATA;
00261         }
00262 
00263         _isScanning = true;
00264         _cachethread = CLASS_THREAD(RPlidarDriverSerialImpl, _cacheScanData);
00265         if (_cachethread.getHandle() == 0) {
00266             return RESULT_OPERATION_FAIL;
00267         }
00268     }
00269     return RESULT_OK;
00270 }
00271 
00272 u_result RPlidarDriverSerialImpl::checkExpressScanSupported(bool & support, _u32 timeout)
00273 {
00274     rplidar_response_device_info_t devinfo;
00275 
00276     support = false;
00277     u_result ans = getDeviceInfo(devinfo, timeout);
00278 
00279     if (IS_FAIL(ans)) return ans;
00280 
00281     if (devinfo.firmware_version >= ((0x1<<8) | 17)) {
00282         support = true;
00283         rplidar_response_sample_rate_t sample_rate;
00284         getSampleDuration_uS(sample_rate);
00285         _cached_sampleduration_express = sample_rate.express_sample_duration_us;
00286         _cached_sampleduration_std = sample_rate.std_sample_duration_us;
00287     }
00288 
00289     return RESULT_OK;
00290 }
00291 
00292 u_result RPlidarDriverSerialImpl::startScanExpress(bool fixedAngle, _u32 timeout)
00293 {
00294     u_result ans;
00295     if (!isConnected()) return RESULT_OPERATION_FAIL;
00296     if (_isScanning) return RESULT_ALREADY_DONE;
00297 
00298     stop(); //force the previous operation to stop
00299 
00300     {
00301         rp::hal::AutoLocker l(_lock);
00302 
00303         rplidar_payload_express_scan_t scanReq;
00304         scanReq.working_mode = (fixedAngle?RPLIDAR_EXPRESS_SCAN_MODE_FIXANGLE:RPLIDAR_EXPRESS_SCAN_MODE_NORMAL);
00305         scanReq.reserved = 0;
00306 
00307         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_EXPRESS_SCAN,&scanReq, sizeof(scanReq)))) {
00308             return ans;
00309         }
00310 
00311         // waiting for confirmation
00312         rplidar_ans_header_t response_header;
00313         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00314             return ans;
00315         }
00316 
00317         // verify whether we got a correct header
00318         if (response_header.type != RPLIDAR_ANS_TYPE_MEASUREMENT_CAPSULED) {
00319             return RESULT_INVALID_DATA;
00320         }
00321 
00322         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00323         if (header_size < sizeof(rplidar_response_capsule_measurement_nodes_t)) {
00324             return RESULT_INVALID_DATA;
00325         }
00326 
00327         _isScanning = true;
00328         _cachethread = CLASS_THREAD(RPlidarDriverSerialImpl, _cacheCapsuledScanData);
00329         if (_cachethread.getHandle() == 0) {
00330             return RESULT_OPERATION_FAIL;
00331         }
00332     }
00333     return RESULT_OK;
00334 }
00335 
00336 
00337 u_result RPlidarDriverSerialImpl::startScan(bool force, bool autoExpressMode)
00338 {
00339     bool isExpressModeSupported;
00340     u_result ans;
00341 
00342     if (autoExpressMode) {
00343         ans = checkExpressScanSupported(isExpressModeSupported);
00344 
00345         if (IS_FAIL(ans)) return ans;
00346     
00347         if (isExpressModeSupported) {
00348             return startScanExpress(false);
00349         }
00350     }
00351 
00352     return startScanNormal(force);
00353 }
00354 
00355 u_result RPlidarDriverSerialImpl::stop(_u32 timeout)
00356 {
00357     u_result ans;
00358     _disableDataGrabbing();
00359 
00360     {
00361         rp::hal::AutoLocker l(_lock);
00362 
00363         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_STOP))) {
00364             return ans;
00365         }
00366     }
00367 
00368     return RESULT_OK;
00369 }
00370 
00371 u_result RPlidarDriverSerialImpl::_cacheScanData()
00372 {
00373     rplidar_response_measurement_node_t      local_buf[128];
00374     size_t                                   count = 128;
00375     rplidar_response_measurement_node_t      local_scan[MAX_SCAN_NODES];
00376     size_t                                   scan_count = 0;
00377     u_result                                 ans;
00378     memset(local_scan, 0, sizeof(local_scan));
00379 
00380     _waitScanData(local_buf, count); // // always discard the first data since it may be incomplete
00381 
00382     while(_isScanning)
00383     {
00384         if (IS_FAIL(ans=_waitScanData(local_buf, count))) {
00385             if (ans != RESULT_OPERATION_TIMEOUT) {
00386                 _isScanning = false;
00387                 return RESULT_OPERATION_FAIL;
00388             }
00389         }
00390 
00391         for (size_t pos = 0; pos < count; ++pos)
00392         {
00393             if (local_buf[pos].sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT)
00394             {
00395                 // only publish the data when it contains a full 360 degree scan 
00396                 
00397                 if ((local_scan[0].sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT)) {
00398                     _lock.lock();
00399                     memcpy(_cached_scan_node_buf, local_scan, scan_count*sizeof(rplidar_response_measurement_node_t));
00400                     _cached_scan_node_count = scan_count;
00401                     _dataEvt.set();
00402                     _lock.unlock();
00403                 }
00404                 scan_count = 0;
00405             }
00406             local_scan[scan_count++] = local_buf[pos];
00407             if (scan_count == _countof(local_scan)) scan_count-=1; // prevent overflow
00408         }
00409     }
00410     _isScanning = false;
00411     return RESULT_OK;
00412 }
00413 
00414 void     RPlidarDriverSerialImpl::_capsuleToNormal(const rplidar_response_capsule_measurement_nodes_t & capsule, rplidar_response_measurement_node_t *nodebuffer, size_t &nodeCount)
00415 {
00416     nodeCount = 0;
00417     if (_is_previous_capsuledataRdy) {
00418         int diffAngle_q8;
00419         int currentStartAngle_q8 = ((capsule.start_angle_sync_q6 & 0x7FFF)<< 2);
00420         int prevStartAngle_q8 = ((_cached_previous_capsuledata.start_angle_sync_q6 & 0x7FFF) << 2);
00421 
00422         diffAngle_q8 = (currentStartAngle_q8) - (prevStartAngle_q8);
00423         if (prevStartAngle_q8 >  currentStartAngle_q8) {
00424             diffAngle_q8 += (360<<8);
00425         }
00426 
00427         int angleInc_q16 = (diffAngle_q8 << 3);
00428         int currentAngle_raw_q16 = (prevStartAngle_q8 << 8);
00429         for (size_t pos = 0; pos < _countof(_cached_previous_capsuledata.cabins); ++pos)
00430         {
00431             int dist_q2[2];
00432             int angle_q6[2];
00433             int syncBit[2];
00434 
00435             dist_q2[0] = (_cached_previous_capsuledata.cabins[pos].distance_angle_1 & 0xFFFC);
00436             dist_q2[1] = (_cached_previous_capsuledata.cabins[pos].distance_angle_2 & 0xFFFC);
00437 
00438             int angle_offset1_q3 = ( (_cached_previous_capsuledata.cabins[pos].offset_angles_q3 & 0xF) | ((_cached_previous_capsuledata.cabins[pos].distance_angle_1 & 0x3)<<4));
00439             int angle_offset2_q3 = ( (_cached_previous_capsuledata.cabins[pos].offset_angles_q3 >> 4) | ((_cached_previous_capsuledata.cabins[pos].distance_angle_2 & 0x3)<<4));
00440 
00441             angle_q6[0] = ((currentAngle_raw_q16 - (angle_offset1_q3<<13))>>10);
00442             syncBit[0] =  (( (currentAngle_raw_q16 + angleInc_q16) % (360<<16)) < angleInc_q16 )?1:0;
00443             currentAngle_raw_q16 += angleInc_q16;
00444 
00445 
00446             angle_q6[1] = ((currentAngle_raw_q16 - (angle_offset2_q3<<13))>>10);
00447             syncBit[1] =  (( (currentAngle_raw_q16 + angleInc_q16) % (360<<16)) < angleInc_q16 )?1:0;
00448             currentAngle_raw_q16 += angleInc_q16;
00449 
00450             for (int cpos = 0; cpos < 2; ++cpos) {
00451 
00452                 if (angle_q6[cpos] < 0) angle_q6[cpos] += (360<<6);
00453                 if (angle_q6[cpos] >= (360<<6)) angle_q6[cpos] -= (360<<6);
00454 
00455                 rplidar_response_measurement_node_t node;
00456 
00457                 node.sync_quality = (syncBit[cpos] | ((!syncBit[cpos]) << 1));
00458                 if (dist_q2[cpos]) node.sync_quality |= (0x2F << RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT);
00459 
00460                 node.angle_q6_checkbit = (1 | (angle_q6[cpos]<<1));
00461                 node.distance_q2 = dist_q2[cpos];
00462 
00463                 nodebuffer[nodeCount++] = node;
00464              }
00465 
00466         }
00467     }
00468 
00469     _cached_previous_capsuledata = capsule;
00470     _is_previous_capsuledataRdy = true;
00471 }
00472 
00473 
00474 u_result RPlidarDriverSerialImpl::_cacheCapsuledScanData()
00475 {
00476     rplidar_response_capsule_measurement_nodes_t    capsule_node;
00477     rplidar_response_measurement_node_t      local_buf[128];
00478     size_t                                   count = 128;
00479     rplidar_response_measurement_node_t      local_scan[MAX_SCAN_NODES];
00480     size_t                                   scan_count = 0;
00481     u_result                                 ans;
00482     memset(local_scan, 0, sizeof(local_scan));
00483 
00484     _waitCapsuledNode(capsule_node); // // always discard the first data since it may be incomplete
00485 
00486     while(_isScanning)
00487     {
00488         if (IS_FAIL(ans=_waitCapsuledNode(capsule_node))) {
00489             if (ans != RESULT_OPERATION_TIMEOUT && ans != RESULT_INVALID_DATA) {
00490                 _isScanning = false;
00491                 return RESULT_OPERATION_FAIL;
00492             } else {
00493                 // current data is invalid, do not use it.
00494                 continue;
00495             }
00496         }
00497 
00498         _capsuleToNormal(capsule_node, local_buf, count);
00499 
00500         for (size_t pos = 0; pos < count; ++pos)
00501         {
00502             if (local_buf[pos].sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT)
00503             {
00504                 // only publish the data when it contains a full 360 degree scan 
00505                 
00506                 if ((local_scan[0].sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT)) {
00507                     _lock.lock();
00508                     memcpy(_cached_scan_node_buf, local_scan, scan_count*sizeof(rplidar_response_measurement_node_t));
00509                     _cached_scan_node_count = scan_count;
00510                     _dataEvt.set();
00511                     _lock.unlock();
00512                 }
00513                 scan_count = 0;
00514             }
00515             local_scan[scan_count++] = local_buf[pos];
00516             if (scan_count == _countof(local_scan)) scan_count-=1; // prevent overflow
00517         }
00518     }
00519     _isScanning = false;
00520 
00521     return RESULT_OK;
00522 }
00523 
00524 u_result RPlidarDriverSerialImpl::grabScanData(rplidar_response_measurement_node_t * nodebuffer, size_t & count, _u32 timeout)
00525 {
00526     switch (_dataEvt.wait(timeout))
00527     {
00528     case rp::hal::Event::EVENT_TIMEOUT:
00529         count = 0;
00530         return RESULT_OPERATION_TIMEOUT;
00531     case rp::hal::Event::EVENT_OK:
00532         {
00533             if(_cached_scan_node_count == 0) return RESULT_OPERATION_TIMEOUT; //consider as timeout
00534 
00535             rp::hal::AutoLocker l(_lock);
00536 
00537             size_t size_to_copy = min(count, _cached_scan_node_count);
00538 
00539             memcpy(nodebuffer, _cached_scan_node_buf, size_to_copy*sizeof(rplidar_response_measurement_node_t));
00540             count = size_to_copy;
00541             _cached_scan_node_count = 0;
00542         }
00543         return RESULT_OK;
00544 
00545     default:
00546         count = 0;
00547         return RESULT_OPERATION_FAIL;
00548     }
00549 }
00550 
00551 u_result RPlidarDriverSerialImpl::ascendScanData(rplidar_response_measurement_node_t * nodebuffer, size_t count)
00552 {
00553     float inc_origin_angle = 360.0/count;
00554     size_t i = 0;
00555 
00556     //Tune head
00557     for (i = 0; i < count; i++) {
00558         if(nodebuffer[i].distance_q2 == 0) {
00559             continue;
00560         } else {
00561             while(i != 0) {
00562                 i--;
00563                 float expect_angle = (nodebuffer[i+1].angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f - inc_origin_angle;
00564                 if (expect_angle < 0.0f) expect_angle = 0.0f;
00565                 _u16 checkbit = nodebuffer[i].angle_q6_checkbit & RPLIDAR_RESP_MEASUREMENT_CHECKBIT;
00566                 nodebuffer[i].angle_q6_checkbit = (((_u16)(expect_angle * 64.0f)) << RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT) + checkbit;
00567             }
00568             break;
00569         }
00570     }
00571 
00572     // all the data is invalid
00573     if (i == count) return RESULT_OPERATION_FAIL;
00574 
00575     //Tune tail
00576     for (i = count - 1; i >= 0; i--) {
00577         if(nodebuffer[i].distance_q2 == 0) {
00578             continue;
00579         } else {
00580             while(i != (count - 1)) {
00581                 i++;
00582                 float expect_angle = (nodebuffer[i-1].angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f + inc_origin_angle;
00583                 if (expect_angle > 360.0f) expect_angle -= 360.0f;
00584                 _u16 checkbit = nodebuffer[i].angle_q6_checkbit & RPLIDAR_RESP_MEASUREMENT_CHECKBIT;
00585                 nodebuffer[i].angle_q6_checkbit = (((_u16)(expect_angle * 64.0f)) << RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT) + checkbit;
00586             }
00587             break;
00588         }
00589     }
00590 
00591     //Fill invalid angle in the scan
00592     float frontAngle = (nodebuffer[0].angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT)/64.0f;
00593     for (i = 1; i < count; i++) {
00594         if(nodebuffer[i].distance_q2 == 0) {
00595             float expect_angle =  frontAngle + i * inc_origin_angle;
00596             if (expect_angle > 360.0f) expect_angle -= 360.0f;
00597             _u16 checkbit = nodebuffer[i].angle_q6_checkbit & RPLIDAR_RESP_MEASUREMENT_CHECKBIT;
00598             nodebuffer[i].angle_q6_checkbit = (((_u16)(expect_angle * 64.0f)) << RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT) + checkbit;
00599         }
00600     }
00601 
00602     // Reorder the scan according to the angle value
00603     for (i = 0; i < (count-1); i++){
00604         for (size_t j = (i+1); j < count; j++){
00605             if(nodebuffer[i].angle_q6_checkbit > nodebuffer[j].angle_q6_checkbit){
00606                 rplidar_response_measurement_node_t temp = nodebuffer[i];
00607                 nodebuffer[i] = nodebuffer[j];
00608                 nodebuffer[j] = temp;
00609             }
00610         }
00611     }
00612 
00613     return RESULT_OK;
00614 }
00615 
00616 u_result RPlidarDriverSerialImpl::_waitNode(rplidar_response_measurement_node_t * node, _u32 timeout)
00617 {
00618     int  recvPos = 0;
00619     _u32 startTs = getms();
00620     _u8  recvBuffer[sizeof(rplidar_response_measurement_node_t)];
00621     _u8 *nodeBuffer = (_u8*)node;
00622     _u32 waitTime;
00623 
00624    while ((waitTime=getms() - startTs) <= timeout) {
00625         size_t remainSize = sizeof(rplidar_response_measurement_node_t) - recvPos;
00626         size_t recvSize;
00627 
00628         int ans = _rxtx->waitfordata(remainSize, timeout-waitTime, &recvSize);
00629         if (ans == rp::hal::serial_rxtx::ANS_DEV_ERR) 
00630             return RESULT_OPERATION_FAIL;
00631         else if (ans == rp::hal::serial_rxtx::ANS_TIMEOUT)
00632             return RESULT_OPERATION_TIMEOUT;
00633 
00634         if (recvSize > remainSize) recvSize = remainSize;
00635         
00636         _rxtx->recvdata(recvBuffer, recvSize);
00637 
00638         for (size_t pos = 0; pos < recvSize; ++pos) {
00639             _u8 currentByte = recvBuffer[pos];
00640             switch (recvPos) {
00641             case 0: // expect the sync bit and its reverse in this byte
00642                 {
00643                     _u8 tmp = (currentByte>>1);
00644                     if ( (tmp ^ currentByte) & 0x1 ) {
00645                         // pass
00646                     } else {
00647                         continue;
00648                     }
00649 
00650                 }
00651                 break;
00652             case 1: // expect the highest bit to be 1
00653                 {
00654                     if (currentByte & RPLIDAR_RESP_MEASUREMENT_CHECKBIT) {
00655                         // pass
00656                     } else {
00657                         recvPos = 0;
00658                         continue;
00659                     }
00660                 }
00661                 break;
00662             }
00663             nodeBuffer[recvPos++] = currentByte;
00664 
00665             if (recvPos == sizeof(rplidar_response_measurement_node_t)) {
00666                 return RESULT_OK;
00667             }
00668         }
00669     }
00670 
00671     return RESULT_OPERATION_TIMEOUT;
00672 }
00673 
00674 
00675 u_result RPlidarDriverSerialImpl::_waitScanData(rplidar_response_measurement_node_t * nodebuffer, size_t & count, _u32 timeout)
00676 {
00677     if (!_isConnected) {
00678         count = 0;
00679         return RESULT_OPERATION_FAIL;
00680     }
00681 
00682     size_t   recvNodeCount =  0;
00683     _u32     startTs = getms();
00684     _u32     waitTime;
00685     u_result ans;
00686 
00687     while ((waitTime = getms() - startTs) <= timeout && recvNodeCount < count) {
00688         rplidar_response_measurement_node_t node;
00689         if (IS_FAIL(ans = _waitNode(&node, timeout - waitTime))) {
00690             return ans;
00691         }
00692         
00693         nodebuffer[recvNodeCount++] = node;
00694 
00695         if (recvNodeCount == count) return RESULT_OK;
00696     }
00697     count = recvNodeCount;
00698     return RESULT_OPERATION_TIMEOUT;
00699 }
00700 
00701 
00702 u_result RPlidarDriverSerialImpl::_waitCapsuledNode(rplidar_response_capsule_measurement_nodes_t & node, _u32 timeout)
00703 {
00704     int  recvPos = 0;
00705     _u32 startTs = getms();
00706     _u8  recvBuffer[sizeof(rplidar_response_capsule_measurement_nodes_t)];
00707     _u8 *nodeBuffer = (_u8*)&node;
00708     _u32 waitTime;
00709 
00710    while ((waitTime=getms() - startTs) <= timeout) {
00711         size_t remainSize = sizeof(rplidar_response_capsule_measurement_nodes_t) - recvPos;
00712         size_t recvSize;
00713 
00714         int ans = _rxtx->waitfordata(remainSize, timeout-waitTime, &recvSize);
00715         if (ans == rp::hal::serial_rxtx::ANS_DEV_ERR) 
00716             return RESULT_OPERATION_FAIL;
00717         else if (ans == rp::hal::serial_rxtx::ANS_TIMEOUT)
00718             return RESULT_OPERATION_TIMEOUT;
00719 
00720         if (recvSize > remainSize) recvSize = remainSize;
00721         
00722         _rxtx->recvdata(recvBuffer, recvSize);
00723 
00724         for (size_t pos = 0; pos < recvSize; ++pos) {
00725             _u8 currentByte = recvBuffer[pos];
00726             switch (recvPos) {
00727             case 0: // expect the sync bit 1
00728                 {
00729                     _u8 tmp = (currentByte>>4);
00730                     if ( tmp == RPLIDAR_RESP_MEASUREMENT_EXP_SYNC_1 ) {
00731                         // pass
00732                     } else {
00733                         _is_previous_capsuledataRdy = false;
00734                         continue;
00735                     }
00736 
00737                 }
00738                 break;
00739             case 1: // expect the sync bit 2
00740                 {
00741                     _u8 tmp = (currentByte>>4);
00742                     if (tmp == RPLIDAR_RESP_MEASUREMENT_EXP_SYNC_2) {
00743                         // pass
00744                     } else {
00745                         recvPos = 0;
00746                         _is_previous_capsuledataRdy = false;
00747                         continue;
00748                     }
00749                 }
00750                 break;
00751             }
00752             nodeBuffer[recvPos++] = currentByte;
00753 
00754             if (recvPos == sizeof(rplidar_response_capsule_measurement_nodes_t)) {
00755                 // calc the checksum ...
00756                 _u8 checksum = 0;
00757                 _u8 recvChecksum = ((node.s_checksum_1 & 0xF) | (node.s_checksum_2<<4));
00758                 for (size_t cpos = offsetof(rplidar_response_capsule_measurement_nodes_t, start_angle_sync_q6);
00759                     cpos < sizeof(rplidar_response_capsule_measurement_nodes_t); ++cpos)
00760                 {
00761                     checksum ^= nodeBuffer[cpos];
00762                 }
00763                 if (recvChecksum == checksum)
00764                 {
00765                     // only consider vaild if the checksum matches...
00766                     if (node.start_angle_sync_q6 & RPLIDAR_RESP_MEASUREMENT_EXP_SYNCBIT) 
00767                     {
00768                         // this is the first capsule frame in logic, discard the previous cached data...
00769                         _is_previous_capsuledataRdy = false;
00770                         return RESULT_OK;
00771                     }
00772                     return RESULT_OK;
00773                 }
00774                 _is_previous_capsuledataRdy = false;
00775                 return RESULT_INVALID_DATA;
00776             }
00777         }
00778     }
00779     _is_previous_capsuledataRdy = false;
00780     return RESULT_OPERATION_TIMEOUT;
00781 }
00782 
00783 
00784 u_result RPlidarDriverSerialImpl::_sendCommand(_u8 cmd, const void * payload, size_t payloadsize)
00785 {
00786     _u8 pkt_header[10];
00787     rplidar_cmd_packet_t * header = reinterpret_cast<rplidar_cmd_packet_t * >(pkt_header);
00788     _u8 checksum = 0;
00789 
00790     if (!_isConnected) return RESULT_OPERATION_FAIL;
00791 
00792     if (payloadsize && payload) {
00793         cmd |= RPLIDAR_CMDFLAG_HAS_PAYLOAD;
00794     }
00795 
00796     header->syncByte = RPLIDAR_CMD_SYNC_BYTE;
00797     header->cmd_flag = cmd;
00798 
00799     // send header first
00800     _rxtx->senddata(pkt_header, 2) ;
00801 
00802     if (cmd & RPLIDAR_CMDFLAG_HAS_PAYLOAD) {
00803         checksum ^= RPLIDAR_CMD_SYNC_BYTE;
00804         checksum ^= cmd;
00805         checksum ^= (payloadsize & 0xFF);
00806 
00807         // calc checksum
00808         for (size_t pos = 0; pos < payloadsize; ++pos) {
00809             checksum ^= ((_u8 *)payload)[pos];
00810         }
00811 
00812         // send size
00813         _u8 sizebyte = payloadsize;
00814         _rxtx->senddata(&sizebyte, 1);
00815 
00816         // send payload
00817         _rxtx->senddata((const _u8 *)payload, sizebyte);
00818 
00819         // send checksum
00820         _rxtx->senddata(&checksum, 1);
00821     }
00822 
00823     return RESULT_OK;
00824 }
00825 
00826 
00827 u_result RPlidarDriverSerialImpl::_waitResponseHeader(rplidar_ans_header_t * header, _u32 timeout)
00828 {
00829     int  recvPos = 0;
00830     _u32 startTs = getms();
00831     _u8  recvBuffer[sizeof(rplidar_ans_header_t)];
00832     _u8  *headerBuffer = reinterpret_cast<_u8 *>(header);
00833     _u32 waitTime;
00834 
00835     while ((waitTime=getms() - startTs) <= timeout) {
00836         size_t remainSize = sizeof(rplidar_ans_header_t) - recvPos;
00837         size_t recvSize;
00838         
00839         int ans = _rxtx->waitfordata(remainSize, timeout - waitTime, &recvSize);
00840         if (ans == rp::hal::serial_rxtx::ANS_DEV_ERR) 
00841             return RESULT_OPERATION_FAIL;
00842         else if (ans == rp::hal::serial_rxtx::ANS_TIMEOUT)
00843             return RESULT_OPERATION_TIMEOUT;
00844         
00845         if(recvSize > remainSize) recvSize = remainSize;
00846         
00847         _rxtx->recvdata(recvBuffer, recvSize);
00848 
00849         for (size_t pos = 0; pos < recvSize; ++pos) {
00850             _u8 currentByte = recvBuffer[pos];
00851             switch (recvPos) {
00852             case 0:
00853                 if (currentByte != RPLIDAR_ANS_SYNC_BYTE1) {
00854                    continue;
00855                 }
00856                 
00857                 break;
00858             case 1:
00859                 if (currentByte != RPLIDAR_ANS_SYNC_BYTE2) {
00860                     recvPos = 0;
00861                     continue;
00862                 }
00863                 break;
00864             }
00865             headerBuffer[recvPos++] = currentByte;
00866 
00867             if (recvPos == sizeof(rplidar_ans_header_t)) {
00868                 return RESULT_OK;
00869             }
00870         }
00871     }
00872 
00873     return RESULT_OPERATION_TIMEOUT;
00874 }
00875 
00876 
00877 
00878 void RPlidarDriverSerialImpl::_disableDataGrabbing()
00879 {
00880     _isScanning = false;
00881     _cachethread.join();
00882 }
00883 
00884 u_result RPlidarDriverSerialImpl::getSampleDuration_uS(rplidar_response_sample_rate_t & rateInfo, _u32 timeout)
00885 {  
00886     if (!isConnected()) return RESULT_OPERATION_FAIL;
00887     
00888     _disableDataGrabbing();
00889     
00890     rplidar_response_device_info_t devinfo;
00891     // 1. fetch the device version first...
00892     u_result ans = getDeviceInfo(devinfo, timeout);
00893 
00894     rateInfo.express_sample_duration_us = _cached_sampleduration_express;
00895     rateInfo.std_sample_duration_us = _cached_sampleduration_std;
00896 
00897     if (devinfo.firmware_version < ((0x1<<8) | 17)) {
00898         // provide fake data...
00899 
00900         return RESULT_OK;
00901     }
00902 
00903 
00904     {
00905         rp::hal::AutoLocker l(_lock);
00906 
00907         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_SAMPLERATE))) {
00908             return ans;
00909         }
00910 
00911         rplidar_ans_header_t response_header;
00912         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00913             return ans;
00914         }
00915 
00916         // verify whether we got a correct header
00917         if (response_header.type != RPLIDAR_ANS_TYPE_SAMPLE_RATE) {
00918             return RESULT_INVALID_DATA;
00919         }
00920 
00921         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00922         if ( header_size < sizeof(rplidar_response_sample_rate_t)) {
00923             return RESULT_INVALID_DATA;
00924         }
00925 
00926         if (_rxtx->waitfordata(header_size, timeout) != rp::hal::serial_rxtx::ANS_OK) {
00927             return RESULT_OPERATION_TIMEOUT;
00928         }
00929         _rxtx->recvdata(reinterpret_cast<_u8 *>(&rateInfo), sizeof(rateInfo));
00930     }
00931     return RESULT_OK;
00932 }
00933 
00934 u_result RPlidarDriverSerialImpl::checkMotorCtrlSupport(bool & support, _u32 timeout)
00935 {
00936     u_result  ans;
00937     support = false;
00938     
00939     if (!isConnected()) return RESULT_OPERATION_FAIL;
00940     
00941     _disableDataGrabbing();
00942 
00943     {
00944         rp::hal::AutoLocker l(_lock);
00945 
00946         rplidar_payload_acc_board_flag_t flag;
00947         flag.reserved = 0;
00948 
00949         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_GET_ACC_BOARD_FLAG, &flag, sizeof(flag)))) {
00950             return ans;
00951         }
00952 
00953         rplidar_ans_header_t response_header;
00954         if (IS_FAIL(ans = _waitResponseHeader(&response_header, timeout))) {
00955             return ans;
00956         }
00957         
00958         // verify whether we got a correct header
00959         if (response_header.type != RPLIDAR_ANS_TYPE_ACC_BOARD_FLAG) {
00960             return RESULT_INVALID_DATA;
00961         }
00962 
00963         _u32 header_size = (response_header.size_q30_subtype & RPLIDAR_ANS_HEADER_SIZE_MASK);
00964         if ( header_size < sizeof(rplidar_response_acc_board_flag_t)) {
00965             return RESULT_INVALID_DATA;
00966         }
00967 
00968         if (_rxtx->waitfordata(header_size, timeout) != rp::hal::serial_rxtx::ANS_OK) {
00969             return RESULT_OPERATION_TIMEOUT;
00970         }
00971         rplidar_response_acc_board_flag_t acc_board_flag;
00972         _rxtx->recvdata(reinterpret_cast<_u8 *>(&acc_board_flag), sizeof(acc_board_flag));
00973 
00974         if (acc_board_flag.support_flag & RPLIDAR_RESP_ACC_BOARD_FLAG_MOTOR_CTRL_SUPPORT_MASK) {
00975             support = true;
00976         }
00977     }
00978     return RESULT_OK;
00979 }
00980 
00981 u_result RPlidarDriverSerialImpl::setMotorPWM(_u16 pwm)
00982 {
00983     u_result ans;
00984     rplidar_payload_motor_pwm_t motor_pwm;
00985     motor_pwm.pwm_value = pwm;
00986 
00987     {
00988         rp::hal::AutoLocker l(_lock);
00989 
00990         if (IS_FAIL(ans = _sendCommand(RPLIDAR_CMD_SET_MOTOR_PWM,(const _u8 *)&motor_pwm, sizeof(motor_pwm)))) {
00991             return ans;
00992         }
00993     }
00994 
00995     return RESULT_OK;
00996 }
00997 
00998 u_result RPlidarDriverSerialImpl::startMotor()
00999 {
01000     if (_isSupportingMotorCtrl) { // RPLIDAR A2
01001         setMotorPWM(DEFAULT_MOTOR_PWM);
01002         delay(500);
01003         return RESULT_OK;
01004     } else { // RPLIDAR A1
01005         rp::hal::AutoLocker l(_lock);
01006         _rxtx->clearDTR();
01007         delay(500);
01008         return RESULT_OK;
01009     }
01010 }
01011 
01012 u_result RPlidarDriverSerialImpl::stopMotor()
01013 {
01014     if (_isSupportingMotorCtrl) { // RPLIDAR A2
01015         setMotorPWM(0);
01016         delay(500);
01017         return RESULT_OK;
01018     } else { // RPLIDAR A1
01019         rp::hal::AutoLocker l(_lock);
01020         _rxtx->setDTR();
01021         delay(500);
01022         return RESULT_OK;
01023     }
01024 }
01025 
01026 }}}


rplidar_ros
Author(s):
autogenerated on Fri Dec 16 2016 03:59:16