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

Add ability to navigate using MAVLink vision messages #7980

Closed
wants to merge 17 commits into from

Conversation

peterbarker
Copy link
Contributor

@peterbarker peterbarker commented Mar 21, 2018

We accept messages of various sorts, and feed the data into EKF2, which can fuse this data and allow us to navigate.

Preliminary instructions on testing this are here:
https://github.com/peterbarker/ardupilot_wiki/blob/vicon/dev/source/docs/using-sitl-for-ardupilot-testing.rst#testing-visual-positioning

Notes:

  • arming in loiter is not possible unless GPS checks are disabled

Edit: the earlier issue, in which the vehicle could not climb in Loiter mode while using external position estimates, has been resolved.

@rmackay9
Copy link
Contributor

This is a really important feature. This will enable the ROS users to feed in the SLAM position estimates to ArduPilot.

@@ -191,6 +191,19 @@ void SITL_State::wait_clock(uint64_t wait_time_usec)
}
}

#define streq(a, b) (!strcmp(a, b))
Copy link
Contributor

Choose a reason for hiding this comment

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

can we remove this define ?

Copy link
Contributor

Choose a reason for hiding this comment

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

it is used only once !


// push a reading into the socket...

bool should_send_heartbeat = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

this look weird

Copy link
Member

Choose a reason for hiding this comment

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

Yep, this means it never sends an heartbeat... (and it should be false in any case).


private:

const uint8_t system_id = 17;
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe add a todo for a param table to handle that

@peterbarker
Copy link
Contributor Author

peterbarker commented Mar 21, 2018 via email

@peterbarker
Copy link
Contributor Author

peterbarker commented Mar 21, 2018 via email

@rmackay9
Copy link
Contributor

@OXINARF, if you get a chance to review this that would be really really appreciated!

@vincekurtz
Copy link
Contributor

As requested in #7997 by @peterbarker, I'm trying to test this functionality but running into some trouble.

I'm able to send VISION_POSITION_ESTIMATE and ATT_POS_MOCAP messages generated by an Optitrack mocap system via mavros, and can view them in QGroundControl's MavLink inspector. I'm also able to run the preliminary tests without any problem.

But on the actual system (pixhawk 2.1, custom quad frame, mavlink connection on Telem2), I never get the APM: EKF2 IMU0 is using external nav data ... messages. I'm guessing my setup is not quite right: any guidance would be much appreciated!

Parameters: mocap_message_tests.txt
Logs: logs.zip

Copy link
Member

@OXINARF OXINARF left a comment

Choose a reason for hiding this comment

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

Besides inline comments:

  • why isn't this in EKF3? Looks like that could lead to a regression when we change to using it
  • I have no issue with how SITL Vicon simulation is done, but it's different from other simulated devices
  • SITL Vicon seems to have an old idea of keeping an observation history that is unused

/*
* Write position and quaternion data from an external navigation system
*
* pos : position in the RH navigation frame. Frame is assumed to be NED if frameIsNED is true. (m)
Copy link
Member

Choose a reason for hiding this comment

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

There is no frameIsNED argument.

Copy link
Contributor

Choose a reason for hiding this comment

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

will fix

* Write position and quaternion data from an external navigation system
*
* pos : position in the RH navigation frame. Frame is assumed to be NED if frameIsNED is true. (m)
* quat : quaternion desribing the the rotation from navigation frame to body frame
Copy link
Member

Choose a reason for hiding this comment

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

desribing -> describing

Copy link
Contributor

Choose a reason for hiding this comment

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

will fix

// handle yaw reset as special case
extNavYawResetRequest = true;
controlMagYawReset();
// handle height reset as sepcial case
Copy link
Member

Choose a reason for hiding this comment

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

sepcial -> special

Copy link
Contributor

Choose a reason for hiding this comment

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

will fix

@@ -169,7 +169,8 @@ void NavEKF2_core::setAidingMode()
// GPS aiding is the preferred option unless excluded by the user
bool canUseGPS = ((frontend->_fusionModeGPS) != 3 && readyToUseGPS() && filterIsStable && !gpsInhibit);
bool canUseRangeBeacon = readyToUseRangeBeacon() && filterIsStable;
if(canUseGPS || canUseRangeBeacon) {
bool canUseExtNav = readyToUseExtNav() && tiltAlignComplete;
Copy link
Member

Choose a reason for hiding this comment

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

tiltAlignComplete is already checked in readyToUseExtNav.

Copy link
Contributor

Choose a reason for hiding this comment

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

will fix

@@ -500,7 +520,7 @@ void NavEKF2_core::updateFilterStatus(void)
filterStatus.flags.takeoff = expectGndEffectTakeoff; // The EKF has been told to expect takeoff and is in a ground effect mitigation mode
filterStatus.flags.touchdown = expectGndEffectTouchdown; // The EKF has been told to detect touchdown and is in a ground effect mitigation mode
filterStatus.flags.using_gps = ((imuSampleTime_ms - lastPosPassTime_ms) < 4000) && (PV_AidingMode == AID_ABSOLUTE);
filterStatus.flags.gps_glitching = !gpsAccuracyGood && (PV_AidingMode == AID_ABSOLUTE); // The GPS is glitching
filterStatus.flags.gps_glitching = !gpsAccuracyGood && (PV_AidingMode == AID_ABSOLUTE) && !extNavUsedForPos; // The GPS is glitching
Copy link
Member

Choose a reason for hiding this comment

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

This doesn't make much sense to me, just because we are using external navigation, the GPS might be glitching anyway. If anything, it seems to make more sense in the line above, using_gps.

Copy link
Contributor

Choose a reason for hiding this comment

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

The problem is how that flag is used. With copter it causes a failsafe reversion into alt hold mode and will prevent takeoff. The EKF2 will never use external nav and GPS at the same time, so when external nav is being used, GPS status is irrelevant.

Copy link
Contributor

Choose a reason for hiding this comment

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

The better way to describe the gps_glitching flag is being 'true when GPS glitching is affecting navigation accuracy'. I will update comments to make this clearer.

struct {
const uint16_t observation_interval_ms = 20;
// delay results by some multiplier of the observation_interval:
const uint8_t observation_history_length = 0;
Copy link
Member

Choose a reason for hiding this comment

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

If this is const, how does it change? It looks unused...

const uint16_t observation_interval_ms = 20;
// delay results by some multiplier of the observation_interval:
const uint8_t observation_history_length = 0;
ObjectArray<obs_elements> observation_history{observation_history_length};
Copy link
Member

Choose a reason for hiding this comment

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

An array of 0?

Quaternion attitude;
};

bool observation_history_initialised;
Copy link
Member

Choose a reason for hiding this comment

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

Unused

observation = new_obs;
} else {
vicon.observation_history.push(new_obs);
vicon.last_observation_ms = now;
Copy link
Member

Choose a reason for hiding this comment

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

This should always be updated, not just when history would be used.

// we share channels with the ArduPilot binary!
const uint8_t mavlink_ch = 17;

uint32_t last_update_ms;
Copy link
Member

Choose a reason for hiding this comment

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

Unused

@peterbarker
Copy link
Contributor Author

peterbarker commented Mar 26, 2018 via email

@priseborough
Copy link
Contributor

There was a bigger change under development for EKF3 that adds an additional state for scale factor estimation of monocular SLAM and VO. Adding changes from this PR to EKF3 would cause pain in rebasing.

@rmackay9
Copy link
Contributor

Merged after removing squashing the last commit and removing the, "DataFlash: Add debug loggin for EKF external nav fusion". Thanks @priseborough and @peterbarker!

@rmackay9 rmackay9 closed this Mar 27, 2018
@peterbarker
Copy link
Contributor Author

peterbarker commented Mar 30, 2018 via email

@vincekurtz
Copy link
Contributor

@peterbarker - I'm fairly certain the mavlink connection is solid, but I'm still unable to use ATT_POS_MOCAP or VISION_POSITION_ESTIMATE messages. I've set up a minimal working example using mavros, mavros_extras, python, and SITL as follows:

Test Example

Set up SITL:

sim_vehicle.py -v ArduCopter -w
STABILIZE> param set GPS_TYPE 0
STABILIZE> param set EK2_GPS_TYPE 3
sim_vehicle.py -v ArduCopter

Connect via mavros (using the px4 launch file because it enables the mocap_pose_estimate plugin by default - using a modified apm launch file gives the same results)

roslaunch mavros px4.launch fcu_url:=udp://127.0.0.1:14551@14555

Run a python script that publishes to the /mavros/mocap/pose topic: mavros will use this to generate and send a ATT_POS_MOCAP message.

test_pose_publisher.py:

import rospy
from geometry_msgs.msg import PoseStamped
import time

topic = "/mavros/mocap/pose"
pose_data = PoseStamped()

try:
    rospy.init_node("test_pose_publisher")
    pose_pub = rospy.Publisher(topic, PoseStamped, queue_size=10)

    rate = rospy.Rate(30)  # in Hz
    pose_data.header.frame_id = "map"
    pose_data.pose.position.x = 2

    start_time = rospy.get_rostime()
    while not rospy.is_shutdown():
        now = rospy.get_rostime() - start_time
        pose_data.header.stamp.secs = now.secs
        pose_data.header.stamp.nsecs = now.nsecs
        
        pose_pub.publish(pose_data)
        
        rate.sleep()

except rospy.ROSInterruptException:
    pass

Results

By putting gcs().send_text(MAV_SEVERITY_INFO, "..."); statements at various points in the code, I can tell that the handle_att_pos_mocap() function of GCS_MAVLink/GCS_Common.cpp is being called and that the data matches what is being published on the ROS topic.

I'm able to trace the progress of the (fake) mocap information as far as the SelectVelPosFusion() function of AP_NavEKF2/AP_NavEKF2_PosVelFusion.cpp. At this point, it appears that extNavDataToFuse is never set to 1.

@rmackay9
Copy link
Contributor

rmackay9 commented Apr 5, 2018

@vincekurtz, it's really great that you're testing this, thanks!

We think the issue may be the timestamps in the messages. They need to be synced up with the system time of the flight controller/ArduPilot. If the times are very far off the EKF will simply not consume the data.

If you're using a Rover or Copter on a Pixhawk (or compatible) could you try this firmware?

It's just master with two patches on top to ignore the time in the message and instead uses the system time. This won't work really well but it should basically work. https://github.com/rmackay9/rmackay9-ardupilot/commits/visp-log

@vincekurtz
Copy link
Contributor

Logs from two flights using the patched firmware are attached. I was able hold altitude and position, but performance was relatively poor considering the accuracy of the mocap system. Altitude tended to drift up and down about a meter, and position hold was plagued by circular oscillations (especially evident in the second test flight).

I'm not sure how much the poor performance is due to my setup (I didn't disable baro or mess with any of the EKF noise parameters) and how much is due to delays between measurement and use in the EKF that aren't taken into account.

extNavTest-ignore_time.zip

@rmackay9
Copy link
Contributor

rmackay9 commented Apr 6, 2018

@vincekurtz, I guess you used a different firmware from the one I linked above? sorry, just having trouble finding the VISP message. I've merged the VISP message to master so you could just use master if you like. The system time isn't used in master though so using master requires ensuring that somehow the timestamps match the flight controller's time.

@vincekurtz
Copy link
Contributor

@rmackay9, it looks like the VISP message doesn't get logged for the ATT_POS_MOCAP message type, which is what I was using. Specifically, the handle_att_pos_mocap() function doesn't call _handle_common_vision_position_estimate_data(), presumably because ATT_POS_MOCAP gives quaternion attitude information from the start.

That should be an easy fix, but for now I'll try another test using the VICON_POSITION_ESTIMATE message, which does use _handle_common_vision_position_estimate_data().

@vincekurtz
Copy link
Contributor

Flight log using VICON_POSITION_ESTIMATE is attached. Performance was similar to using ATT_POS_MOCAP: there were large (but generally bounded) oscillations in position hold mode.

extNav-vision_position_estimate.zip

@rmackay9
Copy link
Contributor

@vincekurtz, we've got this PR which we hope will allow syncing the clocks between the two computers. It's being reviewed now and I hope it will go into master later this week. Txs for your patience and testing!

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

6 participants