2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
26 #ifdef USE_RANGEFINDER_TF
28 #include "build/debug.h"
29 #include "build/build_config.h"
31 #include "io/serial.h"
33 #include "drivers/time.h"
34 #include "drivers/rangefinder/rangefinder.h"
35 #include "drivers/rangefinder/rangefinder_lidartf.h"
37 #define TF_DEVTYPE_NONE 0
38 #define TF_DEVTYPE_MINI 1
39 #define TF_DEVTYPE_02 2
41 static uint8_t tfDevtype
= TF_DEVTYPE_NONE
;
43 #define TF_FRAME_LENGTH 6 // Excluding sync bytes (0x59) x 2 and checksum
44 #define TF_FRAME_SYNC_BYTE 0x59
45 #define TF_TIMEOUT_MS (100 * 2)
48 // Benewake TFmini frame format
49 // Byte Off Description
52 // 3 0 Measured distance (LSB)
53 // 4 1 Measured distance (MSB)
54 // 5 2 Signal strength (LSB)
55 // 6 3 Signal strength (MSB)
58 // 9 - Checksum (Unsigned 8-bit sum of bytes 0~7)
61 // 1. If distance is 12m (1200cm), then OoR.
63 #define TF_MINI_FRAME_INTEGRAL_TIME 4
66 // Benewake TF02 frame format (From SJ-GU-TF02-01 Version: A01)
67 // Byte Off Description
70 // 3 0 Measured distance (LSB)
71 // 4 1 Measured distance (MSB)
72 // 5 2 Signal strength (LSB)
73 // 6 3 Signal strength (MSB)
74 // 7 4 SIG (Reliability in 1~8, less than 7 is unreliable)
75 // 8 5 TIME (Exposure time, 3 or 6)
76 // 9 - Checksum (Unsigned 8-bit sum of bytes 0~7)
79 // 1. If SIG is less than 7, unreliable
80 // 2. If distance is 22m (2200cm), then OoR.
82 #define TF_02_FRAME_SIG 4
86 #define TF_MINI_RANGE_MIN 40
87 #define TF_MINI_RANGE_MAX 1200
89 #define TF_02_RANGE_MIN 40
90 #define TF_02_RANGE_MAX 2200
92 #define TF_DETECTION_CONE_DECIDEGREES 900
94 static serialPort_t
*tfSerialPort
= NULL
;
97 TF_FRAME_STATE_WAIT_START1
,
98 TF_FRAME_STATE_WAIT_START2
,
99 TF_FRAME_STATE_READING_PAYLOAD
,
100 TF_FRAME_STATE_WAIT_CKSUM
,
103 static tfFrameState_e tfFrameState
;
104 static uint8_t tfFrame
[TF_FRAME_LENGTH
];
105 static uint8_t tfReceivePosition
;
108 // Command for 100Hz sampling (10msec interval)
109 // At 100Hz scheduling, skew will cause 10msec delay at the most.
110 static uint8_t tfCmdTFmini
[] = { 0x42, 0x57, 0x02, 0x00, 0x00, 0x00, 0x01, 0x06 };
113 // Same as TFmini for now..
114 static uint8_t tfCmdTF02
[] = { 0x42, 0x57, 0x02, 0x00, 0x00, 0x00, 0x01, 0x06 };
116 static int32_t lidarTFValue
;
117 static uint16_t lidarTFerrors
= 0;
119 static void lidarTFSendCommand(void)
122 case TF_DEVTYPE_MINI
:
123 serialWriteBuf(tfSerialPort
, tfCmdTFmini
, sizeof(tfCmdTFmini
));
126 serialWriteBuf(tfSerialPort
, tfCmdTF02
, sizeof(tfCmdTF02
));
131 void lidarTFInit(rangefinderDev_t
*dev
)
135 tfFrameState
= TF_FRAME_STATE_WAIT_START1
;
136 tfReceivePosition
= 0;
139 void lidarTFUpdate(rangefinderDev_t
*dev
)
142 static timeMs_t lastFrameReceivedMs
= 0;
143 const timeMs_t timeNowMs
= millis();
145 if (tfSerialPort
== NULL
) {
149 while (serialRxBytesWaiting(tfSerialPort
)) {
150 uint8_t c
= serialRead(tfSerialPort
);
151 switch (tfFrameState
) {
152 case TF_FRAME_STATE_WAIT_START1
:
153 if (c
== TF_FRAME_SYNC_BYTE
) {
154 tfFrameState
= TF_FRAME_STATE_WAIT_START2
;
158 case TF_FRAME_STATE_WAIT_START2
:
159 if (c
== TF_FRAME_SYNC_BYTE
) {
160 tfFrameState
= TF_FRAME_STATE_READING_PAYLOAD
;
162 tfFrameState
= TF_FRAME_STATE_WAIT_START1
;
166 case TF_FRAME_STATE_READING_PAYLOAD
:
167 tfFrame
[tfReceivePosition
++] = c
;
168 if (tfReceivePosition
== TF_FRAME_LENGTH
) {
169 tfFrameState
= TF_FRAME_STATE_WAIT_CKSUM
;
173 case TF_FRAME_STATE_WAIT_CKSUM
:
175 uint8_t cksum
= TF_FRAME_SYNC_BYTE
+ TF_FRAME_SYNC_BYTE
;
176 for (int i
= 0 ; i
< TF_FRAME_LENGTH
; i
++) {
182 uint16_t distance
= tfFrame
[0] | (tfFrame
[1] << 8);
183 uint16_t strength
= tfFrame
[2] | (tfFrame
[3] << 8);
185 DEBUG_SET(DEBUG_LIDAR_TF
, 0, distance
);
186 DEBUG_SET(DEBUG_LIDAR_TF
, 1, strength
);
187 DEBUG_SET(DEBUG_LIDAR_TF
, 2, tfFrame
[4]);
188 DEBUG_SET(DEBUG_LIDAR_TF
, 3, tfFrame
[5]);
191 case TF_DEVTYPE_MINI
:
192 if (distance
>= TF_MINI_RANGE_MIN
&& distance
< TF_MINI_RANGE_MAX
) {
193 lidarTFValue
= distance
;
194 if (tfFrame
[TF_MINI_FRAME_INTEGRAL_TIME
] == 7) {
195 // When integral time is long (7), measured distance tends to be longer by 12~13.
204 if (distance
>= TF_02_RANGE_MIN
&& distance
< TF_02_RANGE_MAX
&& tfFrame
[TF_02_FRAME_SIG
] >= 7) {
205 lidarTFValue
= distance
;
211 lastFrameReceivedMs
= timeNowMs
;
213 // Checksum error. Simply discard the current frame.
215 //DEBUG_SET(DEBUG_LIDAR_TF, 3, lidarTFerrors);
219 tfFrameState
= TF_FRAME_STATE_WAIT_START1
;
220 tfReceivePosition
= 0;
226 // If valid frame hasn't been received for more than a timeout, resend command.
228 if (timeNowMs
- lastFrameReceivedMs
> TF_TIMEOUT_MS
) {
229 lidarTFSendCommand();
233 // Return most recent device output in cm
235 int32_t lidarTFGetDistance(rangefinderDev_t
*dev
)
242 static bool lidarTFDetect(rangefinderDev_t
*dev
, uint8_t devtype
)
244 const serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_LIDAR_TF
);
250 tfSerialPort
= openSerialPort(portConfig
->identifier
, FUNCTION_LIDAR_TF
, NULL
, NULL
, 115200, MODE_RXTX
, 0);
252 if (tfSerialPort
== NULL
) {
259 dev
->maxRangeCm
= (devtype
== TF_DEVTYPE_MINI
) ? TF_MINI_RANGE_MAX
: TF_02_RANGE_MAX
;
260 dev
->detectionConeDeciDegrees
= TF_DETECTION_CONE_DECIDEGREES
;
261 dev
->detectionConeExtendedDeciDegrees
= TF_DETECTION_CONE_DECIDEGREES
;
263 dev
->init
= &lidarTFInit
;
264 dev
->update
= &lidarTFUpdate
;
265 dev
->read
= &lidarTFGetDistance
;
270 bool lidarTFminiDetect(rangefinderDev_t
*dev
)
272 return lidarTFDetect(dev
, TF_DEVTYPE_MINI
);
275 bool lidarTF02Detect(rangefinderDev_t
*dev
)
277 return lidarTFDetect(dev
, TF_DEVTYPE_02
);