-
Notifications
You must be signed in to change notification settings - Fork 17.6k
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_Proximity: add RPLidar S2, remove memory copy for each measurement #26835
base: master
Are you sure you want to change the base?
Conversation
I am so happy to see this!! |
return; | ||
} | ||
|
||
// descriptor packet has 7 byte in total | ||
if (_byte_count < sizeof(_descriptor)) { | ||
_uart->read(&_payload[0], sizeof(_descriptor)); |
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 maybe we should change this to read (or peek) just a single byte until we find the RPLIDAR_PREAMBLE byte. As it is, it always reads 7 bytes at a time so if a stray byte gets in there it will only recover if it gets lucky and the preamble byte of some later packet happens to be at a 7-byte interval in the buffer.
I think one easy way for a stray byte to be in the buffer is immediately after a RESET (see above). Just from inspection I would have thought that after, "_ujart->discard_input()" is called another message could arrive or we could catch half a message as it is on its way into the buffer.
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.
@rmackay9 What I saw, after a reset the response will send by RPLidar, we will skip that after a second, until then no new message is send by RPLidar so we can use the read of 7 bytes, otherwise there is a protocol error. But I check to add the byte looking think for RPILIDAR_PREAMBLE.
Good to see that @peterbarker is on the review list 'cuz he's the expert on our serial parsers. BTW, I think this parser does need to be different from most because it has to process so much data that we don't want to use an intermediate buffer. Txs again! |
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.
What hardware has this been tested on?
Has this been tested on Rover running at 50Hz?
Has this been tested with injection of a (small!) amount of serial corruption? Under Valgrind?
What benchmarking has this had on real hardware? I would suspect it is faster than the existing code, but I think we need to know. microseconds-spent-doing-this-stuff-per-10-seconds-of-runtime is the sort of number I'm thinking here.
I certainly don't hate this.
// looking for 0x52 at start of buffer; the 62 following | ||
// bytes are "information" | ||
if (!make_first_byte_in_payload('R')) { // that's 'R' as in RPiLidar | ||
if (AP_HAL::millis() - _last_reset_ms < 1000) { |
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.
Why is this limit here?
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 is a wait for 1000 ms after a Lidar reset. We can make sure the Lidar has rebooted and skip the startup message.
@@ -75,15 +74,6 @@ void AP_Proximity_RPLidarA2::update(void) | |||
return; | |||
} | |||
|
|||
// request device info 3sec after reset | |||
// required for S1 support that sends only 9 bytes after a reset (A1,A2 send 63) |
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.
Has this PR been tested on S1?
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.
@peterbarker Yes, tested with S1. Also with A1 and S2, S1 and S2 send the same data after reset. What is tested is also in the header of this PR.
if (_uart->available() < sizeof(_payload.device_info)) { | ||
return; | ||
} | ||
if ((_read_result = _uart->read(&_payload[0], sizeof(_payload.device_info))) > 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.
Any result here (and in similar places) which is not equal to (here) sizeof(_payload.device_info)
is invalid. In the case that read is short for some reason we'd end up parsing essentially random data.
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 only reads if we have enough data to read, otherwise we have to wait. Or I may not understand your concern.
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.
Don't trust what available()
says. There are paths through ArduPilot which can lead to available() returning a number of bytes then read() returning fewer bytes! These are exceptional cases, like the user asking for serial pass-through.
} | ||
if ((_read_result = _uart->read(&_payload[0], sizeof(_payload.device_info))) > 0) { | ||
_bytes_read += _read_result; | ||
} else { | ||
return; |
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 return means that in the case you don't get the number you're after you'll continue to loop endlessly. Again, you've asked how many bytes are available, if you don't get the number you expect then something drastic is probably in order.
I should say that's not an impossibility, BTW. serial-port-passthrough and other hijinks can do strange things.
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.
No, we will no endlessly loop here, because there is a timeout in the driver that triggers a reset. How should I go in an endless loop here?
It is tested with the hardware in the description of the PR, A1, S1 and S2
No. It was tested by unplug and re plug it again while running and it recovers safely.
Yes it is much faster then the code before, because we are not copy data in the buffer after each measurement. @peterbarker How can I get the microseconds-spent for this?
|
OK, I can test this on A2.
We do need to test it under the conditions I mention.
Usually you would |
Hi @mirkix @peterbarker, I wonder what the next steps on this PR are? More changes from @mirkix? more feedback required from @peterbarker? |
We discussed this on the dev call this morning and PeterB pointed out two things that we need to do before merging:
|
Hello, we have succesfully tested this PR with RPLidar C1 |
This PR adds RPLidar S2 support. RPLidar S2 sends out data with 1MBit/s via serial, at the moment the driver copy / move data in the driver internal buffer with each measurement, which result in high MCU load (S2 send up to 32.000 measurements per second). With this PR the driver consume the data direct from serial driver which result in a less MCU load.
For RPLidar S2 set
SERIALx_BAUD 1000
Tested with: