Skip to content
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

AC_PrecLand: Use sensor timestamp to match inertial frame corrections #18548

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

amilcarlucas
Copy link
Contributor

@amilcarlucas amilcarlucas commented Sep 2, 2021

This is a rebase and cleanup of @fnoop #9020

If the sensor sets the timestamp with the sensor frame then it attempts to match it against inertial frame timestamps.
Sensor frames can have widely varying latencies so this is essential to safely correlate the attitude compensation against any given sensor reading.
This effectively auto-detects the sensor latency and makes the PLND_LAG manual setting unnecessary.
The only caveat is that PLND_LAG must be set large enough to hold the biggest sensor latency.
So if used with a sensor that supports timestamping PLND_LAG should be set to something large like 0.250 (s).

  • Move inertial_data_delayed to _inertial_data_delayed
  • Separate out sync_frames logic, make _inertial_data_delayed class struct
  • Run forward prediction from synced frame
  • Remove _ prefixes in non-member (local) variable's names
Binary Name      Text [B]        Data [B]     BSS (B)        Total Flash Change [B] (%)      Flash Free After PR (B)
---------------  --------------  -----------  -------------  ----------------------------  -------------------------
ardurover        116 (+0.0071%)  0 (0.0000%)  4 (+0.0015%)   116 (+0.0071%)                                   335640
blimp            0 (0.0000%)     0 (0.0000%)  0 (0.0000%)    0 (0.0000%)                                      620052
arducopter       116 (+0.0065%)  0 (0.0000%)  -4 (-0.0015%)  116 (+0.0065%)                                   190732
arduplane        116 (+0.0066%)  0 (0.0000%)  -4 (-0.0015%)  116 (+0.0065%)                                   191404
ardusub          0 (0.0000%)     0 (0.0000%)  0 (0.0000%)    0 (0.0000%)                                      397076
antennatracker   0 (0.0000%)     0 (0.0000%)  0 (0.0000%)    0 (0.0000%)                                      642736
arducopter-heli  116 (+0.0065%)  0 (0.0000%)  -4 (-0.0015%)  116 (+0.0065%)                                   184300

@rishabsingh3003
Copy link
Contributor

I like the idea of this PR!
Has this had any testing where this PR improved the performance? Like a before vs after comparison

@amilcarlucas
Copy link
Contributor Author

No testing has been done yet. I would like to get feedback though.

@fnoop
Copy link
Contributor

fnoop commented Sep 4, 2021

Thanks @amilcarlucas for rebasing this and pushing it forward, I had given up hope :)
I tested it at least in SITL, if not real life - so long ago I can't remember. I tested all of my PRs extensively but this was the last bit of work and can't remember how well it was tested unfortunately. Certainly the frames were matching correctly on unstable frequency inputs which was a huge instability factor in PrecLand. The fixed lag parameter was a good step forward but this PR is really needed for proper stability, particularly on slower/non-realtime platforms or those with lots of other stuff running.

@amilcarlucas
Copy link
Contributor Author

amilcarlucas commented Feb 13, 2024

Rebased and solved conflicts again. Any feedback?

@tridge
Copy link
Contributor

tridge commented Feb 14, 2024

@rishabsingh3003 need your input on this one

if (los_meas_time_us != 0) {
// Search through inertial history for the nearest frame to the measurement timestamp
for (uint8_t i=0; i<_inertial_history->available(); i++) {
uint64_t delta_usec = labs((*_inertial_history)[i]->time_usec - los_meas_time_us);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a time wrap issue here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

los_meas_time_ms will wrap after 71 days, and time_usec does not wrap, so there is a wrap issue

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I solved that now and unit tested it with the script below.

if (los_meas_time_us != 0) {
// Search through inertial history for the nearest frame to the measurement timestamp
for (uint8_t i=0; i<_inertial_history->available(); i++) {
uint64_t delta_usec = labs((*_inertial_history)[i]->time_usec - los_meas_time_us);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

los_meas_time_ms will wrap after 71 days, and time_usec does not wrap, so there is a wrap issue

@amilcarlucas amilcarlucas force-pushed the precland_adaptive branch 4 times, most recently from bd23044 to 7f1c877 Compare February 15, 2024 15:58
Copy link
Contributor

@rishabsingh3003 rishabsingh3003 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you will remove all the commits that will go with #26238. That will make this PR much simpler.
Specifically the "sync_frame" changes look correct and will help the companion computer backend most likely. However, some amount of testing, atleast in SITL, is warranted before we add more complexity. Also the time-wrap bit looks mostly okay, but I would want to double check if that is being handled correctly.
We can potentially modify the SITL prec land backend to trivially test this PR.

for (uint8_t i=0; i<_inertial_history->available(); i++) {
uint64_t delta_us;
uint64_t ih_point_us = (*_inertial_history)[i]->time_usec; // overflows after approximately 584 554.531 years
while (ih_point_us >= (UINT32_MAX + 1UL) * 1000UL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment explaining that this is needed because of the comparison with "ms" time stamp given by the backend would be helpful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the timestamp of the companion Computer Precision landing Vision messages has a half a second delay when compared with the IMU timestamps? It causes problems when comparing the timestamps in the precision landing companion autotest.
I would like to fix that, but I need help. Does this have to do with TIME_SYNC messages? Is the delay in there purposeful?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a followup of #26238. I moved the NFCish things into that one.

I added the comment that you asked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The wrap code has been tested with this:

#!/bin/env python

UINT32_MAX = 2**32 - 1

def compare_timestamps(los_meas_time_ms, ih_point_us):
    """
    Compare two timestamps and calculate the difference in microseconds,
    accounting for 32-bit wrap-around.

    Args:
        los_meas_time_ms (int): The first timestamp in milliseconds.
        ih_point_us (int): The second timestamp in microseconds.

    Returns:
        int: The difference between the two timestamps in microseconds.

    Note:
        This function assumes that the timestamps are close to each other and
        handles the case where the difference exceeds the maximum value of a
        32-bit unsigned integer.
    """
    # simulate 32bit wrap in python
    while los_meas_time_ms >= (UINT32_MAX + 1):
        los_meas_time_ms -= (UINT32_MAX + 1)
    los_meas_time_us = los_meas_time_ms * 1000

    while ih_point_us >= (UINT32_MAX + 1) * 1000:
        ih_point_us -= (UINT32_MAX + 1) * 1000

    if ih_point_us > los_meas_time_us:
        delta_us = ih_point_us - los_meas_time_us
    else:
        delta_us = los_meas_time_us - ih_point_us
    if delta_us > UINT32_MAX * 1000 / 2:
        delta_us = (UINT32_MAX + 1) * 1000 - delta_us
    print(delta_us)
    return delta_us

assert compare_timestamps(0, 0) == 0
assert compare_timestamps(1, 0) == 1000
assert compare_timestamps(0, 1) == 1
assert compare_timestamps(2, 0) == 2000
assert compare_timestamps(0, 2) == 2
assert compare_timestamps(2, 0) == 2000
assert compare_timestamps(UINT32_MAX, UINT32_MAX*1000) == 0
assert compare_timestamps(UINT32_MAX, UINT32_MAX*1000+1) == 1
assert compare_timestamps((UINT32_MAX+1)+0, (UINT32_MAX+1)*1000+0) == 0
assert compare_timestamps((UINT32_MAX+1)+0, (UINT32_MAX+1)*1000-1) == 1
assert compare_timestamps((UINT32_MAX+1)+0, (UINT32_MAX+1)*1000-2) == 2
assert compare_timestamps((UINT32_MAX+1)+0, (UINT32_MAX+1)*1000+1) == 1
assert compare_timestamps((UINT32_MAX+1)+0, (UINT32_MAX+1)*1000+2) == 2
assert compare_timestamps((UINT32_MAX+1)+0, 2*(UINT32_MAX+1)*1000+2) == 2
assert compare_timestamps((UINT32_MAX+1)+0, 3*(UINT32_MAX+1)*1000+4) == 4
assert compare_timestamps((UINT32_MAX+0)+0, 3*(UINT32_MAX+1)*1000+4) == 1004
assert compare_timestamps((UINT32_MAX+1)+7, 3*(UINT32_MAX+1)*1000+4) == 6996

@amilcarlucas
Copy link
Contributor Author

I have updated the size comparison on top of this PR

@amilcarlucas amilcarlucas force-pushed the precland_adaptive branch 2 times, most recently from 53fc196 to 8eace96 Compare February 19, 2024 13:33
@amilcarlucas amilcarlucas marked this pull request as draft February 22, 2024 14:49
@amilcarlucas amilcarlucas force-pushed the precland_adaptive branch 2 times, most recently from 6a5a5f9 to 8f0f4e3 Compare March 6, 2024 08:58
@amilcarlucas
Copy link
Contributor Author

This PR was started by @khancyr , later picked up by @fnoop and later on by me. It has been around by many years, but it is now a lot shorter and easier to review.

Unfortunately right now I do not have a vehicle that I can test this with, so it would be nice if someone with a companion computer and visual fiducial markers would test this.

Co-authored-by: Dr.-Ing. Amilcar do Carmo Lucas <amilcar.lucas@iav.de>

If the sensor sets the timestamp with the sensor frame then it attempts to match it against inertial frame timestamps.
Sensor frames can have widely varying latencies so this is essential to safely correlate the attitude compensation against any given sensor reading.
This effectively auto-detects the sensor latency and makes the PLND_LAG manual setting unnecessary.
The only caveat is that PLND_LAG must be set large enough to hold the biggest sensor latency.
So if used with a sensor that supports time-stamping PLND_LAG should be set to something large like 0.250 (s).

- Separate out sync_frames logic, make _inertial_data_delayed class struct
- Run forward prediction from synced frame
@amilcarlucas amilcarlucas marked this pull request as ready for review March 13, 2024 23:21
@amilcarlucas
Copy link
Contributor Author

@rishabsingh3003 the other 2 precland PRs from me got merged, only this one remains and it got a lot smaller now. Can you review this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants