New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AP_RangeFinder: Benewake TF02 and TFmini lidar driver #8504
Conversation
79c3a57
to
47541dc
Compare
rebased to fix conflicts with the WASP200 lidar |
// no signal byte from TFmini | ||
sig_ok = true; | ||
} else { | ||
// TF02 provides signal strength (good = 7 or 8) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both provide signal strength, only TF02 provides reliability (which is what the code is checking).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, comments fixed in follow up commit.
// TFmini has short distance mode (mm) | ||
if ((model_type == BENEWAKE_TFmini)) { | ||
if (linebuf[6] == 0x02) { | ||
dist *= 10; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be divide by 10 right? In this case it's in mm and we want cm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops. thanks. distance is divided by 10 in follow-up commit.
// if checksum matches extract contents | ||
if (checksum == linebuf[BENEWAKE_FRAME_LENGTH-1]) { | ||
// calculate distance and add to sum | ||
uint16_t dist = be16toh(((uint16_t)linebuf[2] << 8) | linebuf[3]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Datasheet says it's in little endian, so I think this should be le16toh
.
Also, we should check for 0xFFFF because, according that datasheet, that's an invalid distance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, added check for 0xFFFF in follow up commit.
sig_ok = true; | ||
} else { | ||
// TF02 provides signal strength (good = 7 or 8) | ||
// we interpret a single good strength as confidence in the average distance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would propose something different:
- set
signal_ok
to true after checking that checksum is valid (so line 110) - set
sig_ok
as is (probably rename todist_reliable
or something like that), but:- only add to
sum_cm
and increasecount
ifsig_ok
is true - reset
sig_ok
to false whenlinebuf_len
is reset to 0
- only add to
This means two things:
- even if we don't receive a good distance, it won't be signaled as no data, but as out-of-range
- it won't add values that aren't good, even if just one was
// calculate checksum | ||
uint8_t checksum = 0; | ||
for (uint8_t i=0; i<BENEWAKE_FRAME_LENGTH-1; i++) { | ||
checksum += linebuf[i]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look correct. According to the datasheet, the checksum is the low 8-bit of the sum of the 8 first bytes. By making checksum
just uint8_t we might be overflowing. It should be a uint16_t and then the comparison below should be if (uint8_t(checksum & 0xFF) == ...)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's actually a difference is there? Either way the top bits are thrown away.. I've changed it in a follow-up commit but the checksum hasn't been failing..
if ((model_type == BENEWAKE_TFmini)) { | ||
if (linebuf[6] == 0x02) { | ||
dist *= 10; | ||
uint16_t dist = le16toh(((uint16_t)linebuf[3] << 8) | linebuf[2]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a terrible job explaining here, sorry. We have two options:
- we either do what's between parenthesis:
((uint16_t)linebuf[3] << 8) | linebuf[2]);
, OR - we call le16toh with a le16_t value:
le16toh(*((le16_t*)&linebuf[2]))
Doing both operations isn't needed. The second option is more useful where packets are defined by a packed structure and a buffer is just copied into it, here the first option seems the better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I don't know what to change. It works at the moment but if I flip around [3] and [2] it doesn't work...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be uint16_t dist = ((uint16_t)linebuf[3] << 8) | linebuf[2];
. There is no point in calling the method because we are already doing the operation to make it correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@OXINARF, cool thanks. I've pushed fixes now. We should squash all these together before merging probably. If you give the LGTM I can do that..
Txs for the reivew, all issues addressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it is an abnormal value when a value more than the performance is obtained. Because manufacturer does not guarantee.
// byte 5 STRENGTH_H Strength high 8 bits | ||
// byte 6 (TF02) SIG Reliability in 8 levels, 7 & 8 means reliable | ||
// byte 6 (TFmini) Distance Mode 0x02 for short distance (mm), 0x07 for long distance (cm) | ||
// byte 7 (TF02 only) TIME Exposure time in two levels 0x03 and 0x06 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it is better to know that it is 0 (without looking at the design sheet) for checksum check.
byte 7 (TFmini) 0x00
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm.. this makes me think that we could actually auto detect if it's a TF02 or TFmini by looking at one of these fields..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After a benchtest, it seems like byte 7 is always zero on both the tfmini and the tf02.. so not useful for automatically determining which lidar is being used.
// byte 6 (TF02) SIG Reliability in 8 levels, 7 & 8 means reliable | ||
// byte 6 (TFmini) Distance Mode 0x02 for short distance (mm), 0x07 for long distance (cm) | ||
// byte 7 (TF02 only) TIME Exposure time in two levels 0x03 and 0x06 | ||
// byte 8 Check Checksum parity bit, sum of byte 0 to byte 7 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that parity bit is not written.
Design sheet:
Checksum is the low 8 bits of the cumulative sum of the numbers of the first 8 bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the comments a bit to make it more clear I hope..
// if buffer now has 9 items try to decode it | ||
if (linebuf_len == BENEWAKE_FRAME_LENGTH) { | ||
// calculate checksum | ||
uint16_t checksum = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the design sheet the checksum is written as the lower 8 bits. I think that it is good to add 8 bits and 1 byte.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not quite sure what you mean. It seems to be working..
checksum += linebuf[i]; | ||
} | ||
// if checksum matches extract contents | ||
if ((uint8_t)(checksum & 0xFF) == linebuf[BENEWAKE_FRAME_LENGTH-1]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do a checksum with 1 byte, I think that this expression will be simplified as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was originally 1 byte, Francisco asked that we make it 2bytes to prevent overflow. It works either way so I think I will leave it as-is.
// TFmini has short distance mode (mm) | ||
if ((model_type == BENEWAKE_TFmini)) { | ||
if (linebuf[6] == 0x02) { | ||
dist *= 0.1f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case of short range, 0 - 5 m
For long range, 1-12 m
I think that it is better to judge other values as abnormal values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope that it will return a bad value if it's out-of-range but I'm not sure yet. let's see how testing goes.
Thanks for the reviews, merging! |
This PR add supports for the Benewake TF02 and TFmini lidars.
The same driver is used for both because the communication packets (sent over serial) are nearly identical. The only difference that we care about is that byte 6 provides a signal strength on the TF02 and a range-mode on the TFmini (either short or long).
I've tested the driver with both sensors and it seems to work.
Wiki pages for the two sensors are available below. Note that the TYPE parameter setting described needs to be updated on the wiki after this PR goes in: