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_Benewake.h" 17 : 18 : #if AP_RANGEFINDER_BENEWAKE_ENABLED 19 : 20 : #include <AP_HAL/AP_HAL.h> 21 : #include <AP_HAL/utility/sparse-endian.h> 22 : 23 : #include <ctype.h> 24 : 25 : extern const AP_HAL::HAL& hal; 26 : 27 : #define BENEWAKE_FRAME_HEADER 0x59 28 : #define BENEWAKE_FRAME_LENGTH 9 29 : #define BENEWAKE_DIST_MAX_CM 32768 30 : #define BENEWAKE_OUT_OF_RANGE_ADD 1.00 // metres 31 : 32 : // format of serial packets received from benewake lidar 33 : // Model | Byte 0-1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | Byte 8 34 : // ------------+-----------+--------+--------+------------+------------+------------+----------------+--------- 35 : // TFmini | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | dist mode* | reserved | Checksum 36 : // TF02 | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | SIG* | Exposure Time* | Checksum 37 : // TF-Nova | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp | Confidence* | Checksum 38 : // ------------+-----------+--------+--------+------------+------------+------------+----------------+--------- 39 : // TFmini-S | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp_L | Temp_H | Checksum 40 : // TFmini-plus | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp_L | Temp_H | Checksum 41 : // TF02-Pro | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp_L | Temp_H | Checksum 42 : // TFS20-L | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp_L | Temp_H | Checksum 43 : // TF-Luna | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | Temp_L | Temp_H | Checksum 44 : // TF03 | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | reserved | reserved | Checksum 45 : // TF350 | 0x59 0x59 | Dist_L | Dist_H | Strength_L | Strength_H | reserved | reserved | Checksum 46 : // 47 : // Notes: 48 : // TFmini (discontinued) : Byte 6 : Distance mode is 0x02 for short distance (mm), 0x07 for long distance (cm) 49 : // TF02 (discontinued) : Byte 6 : SIG byte is reliability in 8 levels, 7 & 8 means reliable 50 : // TF02 (discontinued) : Byte 7 : Exposure Time in two levels 0x03 and 0x06 51 : // TF-Nova : Byte 7 : Confidence from 0 ~ 100 (100 being highest confidence) 52 : // 53 : // Strength values per model: 54 : // TFmini: No documentation 55 : // TF02: 0 ~ 3000, reliable if value >=20 and <= 2000 56 : // TF-Nova: No documentation 57 : // TFmini-S: 0 ~ 65535. reliable if value >=100 and <65535, 65535 (-1) means signal strength saturation (bad) 58 : // TFmini-plus: 0 ~ 65535. reliable if value >=100 and <65535, 65535 (-1) means signal strength saturation (bad) 59 : // TF02-Pro: 0 ~ 65535, no documentation 60 : // TFS20-L: 0 ~ 65535, no documentation 61 : // TF-Luna: 0 ~ 65535. reliable if value >=100 and <65535, 65535 (-1) means signal strength saturation (bad) 62 : // TF03: 0 ~ 3500, reliable if >=40 ~ 1200. if high reflectivity object will be 1500 63 : // TF350: 0 ~ 3500, reliable if >=40 ~ 1200. if high reflectivity object will be 1500 64 : 65 : // distance returned in reading_m, signal_ok is set to true if sensor reports a strong signal 66 5809 : bool AP_RangeFinder_Benewake::get_reading(float &reading_m) 67 : { 68 5809 : if (uart == nullptr) { 69 0 : return false; 70 : } 71 : 72 5809 : float sum_cm = 0; 73 5809 : uint16_t count = 0; 74 5809 : uint16_t count_out_of_range = 0; 75 : 76 : // read any available lines from the lidar 77 19093 : for (auto j=0; j<8192; j++) { 78 : uint8_t c; 79 19093 : if (!uart->read(c)) { 80 5809 : break; 81 : } 82 : // if buffer is empty and this byte is 0x59, add to buffer 83 13284 : if (linebuf_len == 0) { 84 1476 : if (c == BENEWAKE_FRAME_HEADER) { 85 1476 : linebuf[linebuf_len++] = c; 86 : } 87 11808 : } else if (linebuf_len == 1) { 88 : // if buffer has 1 element and this byte is 0x59, add it to buffer 89 : // if not clear the buffer 90 1476 : if (c == BENEWAKE_FRAME_HEADER) { 91 1476 : linebuf[linebuf_len++] = c; 92 : } else { 93 0 : linebuf_len = 0; 94 : } 95 : } else { 96 : // add character to buffer 97 10332 : linebuf[linebuf_len++] = c; 98 : // if buffer now has 9 items try to decode it 99 10332 : if (linebuf_len == BENEWAKE_FRAME_LENGTH) { 100 : // calculate checksum 101 1476 : uint8_t checksum = 0; 102 13284 : for (uint8_t i=0; i<BENEWAKE_FRAME_LENGTH-1; i++) { 103 11808 : checksum += linebuf[i]; 104 : } 105 : // if checksum matches extract contents 106 1476 : if (checksum == linebuf[BENEWAKE_FRAME_LENGTH-1]) { 107 : // calculate distance 108 1476 : uint16_t dist = ((uint16_t)linebuf[3] << 8) | linebuf[2]; 109 1476 : if (dist >= BENEWAKE_DIST_MAX_CM || dist == uint16_t(model_dist_max_cm())) { 110 : // this reading is out of range. Note that we 111 : // consider getting exactly the model dist max 112 : // is out of range. This fixes an issue with 113 : // the TF03 which can give exactly 18000 cm 114 : // when out of range 115 0 : count_out_of_range++; 116 1476 : } else if (!has_signal_byte()) { 117 : // no signal byte so can immediately add distance to sum 118 689 : sum_cm += dist; 119 689 : count++; 120 : } else { 121 : // TF02 provides signal reliability (good = 7 or 8) 122 787 : if (linebuf[6] >= 7) { 123 : // add distance to sum 124 787 : sum_cm += dist; 125 787 : count++; 126 : } else { 127 : // this reading is out of range 128 0 : count_out_of_range++; 129 : } 130 : } 131 : } 132 : // clear buffer 133 1476 : linebuf_len = 0; 134 : } 135 : } 136 : } 137 : 138 5809 : if (count > 0) { 139 : // return average distance of readings 140 1459 : reading_m = (sum_cm * 0.01f) / count; 141 1459 : return true; 142 : } 143 : 144 4350 : if (count_out_of_range > 0) { 145 : // if only out of range readings return larger of 146 : // driver defined maximum range for the model and user defined max range + 1m 147 0 : reading_m = MAX(model_dist_max_cm() * 0.01, max_distance() + BENEWAKE_OUT_OF_RANGE_ADD); 148 0 : return true; 149 : } 150 : 151 : // no readings so return false 152 4350 : return false; 153 : } 154 : 155 : #endif // AP_RANGEFINDER_BENEWAKE_ENABLED