Line data Source code
1 : /* 2 : This program is free software: you can redistribute it and/or modify 3 : it under the terms of the GNU General Public License as published by 4 : the Free Software Foundation, either version 3 of the License, or 5 : (at your option) any later version. 6 : 7 : This program is distributed in the hope that it will be useful, 8 : but WITHOUT ANY WARRANTY; without even the implied warranty of 9 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 : GNU General Public License for more details. 11 : 12 : You should have received a copy of the GNU General Public License 13 : along with this program. If not, see <http://www.gnu.org/licenses/>. 14 : */ 15 : 16 : #include "AP_RangeFinder_TeraRanger_Serial.h" 17 : 18 : #if AP_RANGEFINDER_TERARANGER_SERIAL_ENABLED 19 : 20 : 21 : #include <AP_HAL/utility/sparse-endian.h> 22 : #include <AP_Math/AP_Math.h> 23 : #include <ctype.h> 24 : 25 : #define FRAME_HEADER 0x54 26 : #define FRAME_LENGTH 5 27 : #define DIST_MAX 30.00 28 : #define OUT_OF_RANGE_ADD 10.00 29 : #define STATUS_MASK 0x1F 30 : #define DISTANCE_ERROR 0x0001 31 : 32 : // format of serial packets received from rangefinder 33 : // 34 : // Data Bit Definition Description 35 : // ------------------------------------------------ 36 : // byte 0 Frame header 0x54 37 : // byte 1 DIST_H Distance (in mm) high 8 bits 38 : // byte 2 DIST_L Distance (in mm) low 8 bits 39 : // byte 3 STATUS Status,Strengh,OverTemp 40 : // byte 4 CRC8 packet CRC 41 : 42 : // distance returned in reading_m, set to true if sensor reports a good reading 43 1343 : bool AP_RangeFinder_TeraRanger_Serial::get_reading(float &reading_m) 44 : { 45 1343 : if (uart == nullptr) { 46 0 : return false; 47 : } 48 : 49 1343 : float sum_mm = 0; 50 1343 : uint16_t count = 0; 51 1343 : uint16_t bad_read = 0; 52 : 53 : // read any available lines from the lidar 54 3068 : for (auto i=0; i<8192; i++) { 55 : uint8_t c; 56 3068 : if (!uart->read(c)) { 57 1343 : break; 58 : } 59 : // if buffer is empty and this byte is 0x57, add to buffer 60 1725 : if (linebuf_len == 0) { 61 345 : if (c == FRAME_HEADER) { 62 345 : linebuf[linebuf_len++] = c; 63 : } 64 : // buffer is not empty, add byte to buffer 65 : } else { 66 : // add character to buffer 67 1380 : linebuf[linebuf_len++] = c; 68 : // if buffer now has 5 items try to decode it 69 1380 : if (linebuf_len == FRAME_LENGTH) { 70 : // calculate CRC8 (tbd) 71 345 : uint8_t crc = 0; 72 345 : crc =crc_crc8(linebuf,FRAME_LENGTH-1); 73 : // if crc matches, extract contents 74 345 : if (crc == linebuf[FRAME_LENGTH-1]) { 75 : // calculate distance 76 345 : uint16_t dist = ((uint16_t)linebuf[1] << 8) | linebuf[2]; 77 345 : if (dist >= DIST_MAX *1000) { 78 : // this reading is out of range and a bad read 79 0 : bad_read++; 80 : } else { 81 : // check if reading is good, no errors, no overtemp, reading is not the special case of 1mm 82 345 : if ((STATUS_MASK & linebuf[3]) == 0 && (dist != DISTANCE_ERROR)) { 83 : // add distance to sum 84 345 : sum_mm += dist; 85 345 : count++; 86 : } else { 87 : // this reading is bad 88 0 : bad_read++; 89 : } 90 : } 91 : } 92 : // clear buffer 93 345 : linebuf_len = 0; 94 : } 95 : } 96 : } 97 : 98 1343 : if (count > 0) { 99 : // return average distance of readings since last update 100 338 : reading_m = (sum_mm * 0.001f) / count; 101 338 : return true; 102 : } 103 : 104 1005 : if (bad_read > 0) { 105 : // if a bad read has occurred this update overwrite return with larger of 106 : // driver defined maximum range for the model and user defined max range + 1m 107 0 : reading_m = MAX(DIST_MAX, max_distance() + OUT_OF_RANGE_ADD); 108 0 : return true; 109 : } 110 : 111 : // no readings so return false 112 1005 : return false; 113 : } 114 : 115 : #endif // AP_RANGEFINDER_TERARANGER_SERIAL_ENABLED