I'm trying to localise my robot in an outdoor environment by integrating GPS data in ROS. I'm running two ekf_localisation
instances and one navsat_transform
instance. In addition, I'm running an instance of /move_base
so I can send ActionGoals to control the UGV. But in general, the localisation is inaccurate, and the origin of my /map
and /odom
frames move relative to each other, and relative to the real world. I'm not entirely sure why.
In addition, I'm trying to use navsat_transform
to create a /map
frame at a specified latitude/longitude whose 'Y' axis always faces true north. But I'm having difficulty achieving this as well, and I suspect that one problem is causing or at least contributing to the other.
Here is all the details and diagnostic info:
Robot: Clearpath Jackal UGV
OS: Ubuntu 14.04 on laptop, Ubuntu server on robot
ROS distro: Indigo Igloo
Launch files: ekf_plus_navsat.launch, odom_demo.launch
Frame tree: frames
rqt_graph_output: Nodes and topics
Example bag files: box_mapFrame.bag, box_mapFrame_odometry_and_sensors_only.bag, box_odomFrame.bag
Example sensor inputs: sample_imu_data.txt, sample_odometry_data.txt, sample_gps_data.txt
All of my sensor data conforms to REP-103 and REP-105. The IMU reports 0.0 facing True North but I use the yaw_offset
parameter in navsat_transform
to compensate accordingly
There is a variety of strange behaviour I'm seeing, so I'll try to break it down sequentially. In the bag files above (more coming soon) I mark out a 4x4 m grid starting the robot in one corner, manually drive it round the square and back to its origin. So the first time it moves around, it should definitely be moving in a (rough) 4x4 grid. I then remotely command the robot to move around the square by issuing it ActionGoals sequentially in either /map
frame or /odom
frame (I.e. 4,0 -> 4,4 -> 0,4 -> 0,0). Where the robot ends up is no-where near where it started, regardless of whether I'm giving issuing ActionGoals in the /map
or /odom
frame.
I've documented the various errors as best I can below. Any help or advice will be greatly appreciated.
UPDATE 1:
I can finally edit this again when I couldn't for a few days?! Anyway...
Here are my updated ekf_launch files: ekf_and_gps_localisation.launch
And separate launch files for each node: ekf_local.launch, ekf_global.launch, navsat_transform.launch
- IMU appears to be faulty
[EDIT]: Ignore any of my comments regarding the IMU - as it turns out the raw mag data from both /imu/mag
and /imu/magnetic_field
are un-calibrated which made me think the IMU wasn't working (it is). So lesson learned: use /imu/data
only to get an earth-referenced heading. In fairness the documentation could be a little clearer on this issue.
- Transforms missing when launching EKF/navsat nodes
The various EKF and navsat nodes are VERY picky about how they are launched. If you run the ekf_and_gps_localisation.launch by itself after bootup, the EKF nodes will launch properly, but when it tries to launch navsat_transform node it freezes and produces this error:
`[ERROR] [1466993920.331485830]: Could not obtain transform from odom->base_link`
At which point the only option is to hit Ctrl+C
, stopping the frozen launch file and killing the EKF nodes in the process. But I don't get this if I run each node individually, or if I run ekf_and_gps_localisation.launch when the robot boots. However, these methods still produce their own errors, as a different transform (imu_link->base_link
) appears to be missing. This error can be seen in rosconsole:
navsat_transform
node incorrectly calculates the datum origin and orientation
As I mentioned in the preamble, I want /map
to be centred at a specific latitude/longitude and facing True North. My understanding, based on the GPS Integration Tutorial is that I can use the datum
parameter to set the origin of /map
and that the heading
sub-parameter dictates the heading of /map
from True North (irrespective of the current or initial pose of the robot). So, according to the tutorial and REP-103, heading of 0.0 will result in the 'Y' axis of /map
facing True North and the 'X' axis of /map
facing True East.
Unfortunately something is going wrong with navsat_transform when I try to set the datum. If I set the datum in the launch file, it doesn't set /map
at the correct orientation or heading. If I use 'rosservice call /datum` after the node has launched then it at least calculates the origin correctly some of the time. Sometimes the origin is set to the correct latitude/longitude and other times it is out by a meter or so. You can actually see the incorrect calculation by watching the output in rosconsole:
Everything circled in red is output upon launching the navsat_transform
node. Everything in green is output when I use rosservice call /datum
to manually re-set the datum afterwards. I used the exact same latitude/longitude and heading in both cases, yet notice how the UTM coordinates given by the 'World frame->utm transform' message are different in each case. This obviously shouldn't happen, so navsat_transform is messing up the calculation somewhere. This issue is possibly related to the missing imu_link->base_link
transform described in point 2.
As for the orientation, this is incorrect regardless of whether I set the datum in the launch via or via rosservice
The 'Y' axis of /map
always points to Magnetic North, irrespective of the value of heading
in the datum
parameter. As I said, the GPS Integration Tutorial led me to believe that a heading of 0.0 would result in /map
facing True North, not Magnetic North. But even if I set heading
to the value of the magnetic declination, it still points to Magnetic North. In fact, it doesn't matter what the value of heading
is, the orientation of /map
is still the same. I've also noticed that the yaw_offset
parameter in navsat_transform
has no effect on this as well. I would have expected that changing yaw_offset
to 0.0 would result in the 'Y' axis of /map
pointing West, rather than North (since this is the default state of most IMUs including mine), but this is not the case.
[EDIT]: As it turns out, the setting the datum in the launch file ends up calling rosservice
anyway. So regardless of when it is set, the same method is used which means the only thing that's different between each call is the timing.
- Rviz doesn't display odometry properly
There is a BIG discrepancy between what Rviz displays and what is actually being measured, which I'm struggling to resolve. The below images shows what Rviz displays (right) and what you get if you plot each odometry set in Excel (left)
The data and the colours are exactly the same
- Blue for 'local' (which is
/odometry/filtered/local
measured in the/odom
frame) - Red for 'global' (which is
/odometry/filtered/global
measured in the/map
frame) - Green for 'gps' (which is
/odometry/gps
, also measured in the/map
frame).
Note that Rviz is not displaying 'gps' odometry even though it has been added to the list of displayed data, and the the fact that 'global' is being displayed proves that the /map->/odom
works properly.
The 'local' and 'global' data shouldn't overlap because they come from different frames. However 'global' and 'gps' should be identical because they are in the same frame and the gps data is being fused in the second EKF to produce the 'global' odometry data. Besides other things this clearly demonstrates that something is going very wrong with the second EKF.
[EDIT]: Tom has kindly pointed out that Rviz will transform each odometry data set into whatever reference frame you are currently viewing. Hence why /odometry/filtered/global
and /odometry/filtered/local
match in Rviz but not in Excel. This can be somewhat misleading but at least it proves that the /map->/odom
transform is working correctly.
UPDATE 2:
As requested, I've collected some new data. I used the launch files given at the top of "Update 1". I manually drove the robot approximately along a 85m long line that runs parallel to the meridian (i.e. lines up with True North/South). I collected two bag files, one running north along the line, and one running south back to the starting point. I made sure that the /odom
frame roughly pointed True North, so the topic /odometry/filtered/local
best represents the actual path of the robot (with some drift). Both /odom
and /map
had their origins at the same point.
Bag files: line_north.bag, line_south.bag
Originally posted by M@t on ROS Answers with karma: 2327 on 2016-06-17
Post score: 0
Original comments
Comment by Tom Moore on 2016-06-20:
Can you please post sample input messages for each sensor? It can be a bit quicker sometimes to rapidly troubleshoot issues if I don't have to pull down the bag first.
Comment by Tom Moore on 2016-06-20:
Also, the map and odom frame will move away from one another. Also also, please turn off debug mode! You're taxing your CPU a LOT by turning that on, and outputting a massive text file somewhere. :)
Comment by Tom Moore on 2016-06-20:
It looks like a pretty solid launch file. Post some raw input data and I'll try to take a look at the bag soon.
Comment by M@t on 2016-06-21:
I now suspect that I haven't set up navsat_transform quite right because the /odometry/gps data doesn't match the raw gps input. Regardless, I've uploaded sample sensor data and more bag files. Thanks for pointing out the debug file size - serves me right for not reading the documentation properly.
Comment by M@t on 2016-06-21:
As for the launch file, I largely copied it from one you had posted in a different answer. I was struggling to understand the GPS integration tutorial, but having a full working example to look at helped enormously, especially regarding how the /map, /odom and /utm frames are set up.
Comment by M@t on 2016-06-23:
I can't edit my own question now for some reason, but I'm convinced that my IMU and navsat_transform are the cause of the problem. the origin of /map is never where it's supposed to be - its always out by at least 2 meters, often more.
Comment by M@t on 2016-06-24:
The XYZ output of a vector magnetometer points in the direction of the magnetic field, isn't that correct? So as the robot rotates 360, the XY component on that vector should pass through every quadrant of a circle shouldn't it? I.e (X+,Y+) -> (X-,Y+) -> (X-,Y-) -> (X+,Y-) from /imu/magnetic_field
Comment by M@t on 2016-06-24:
Mine doesn't, it skips a whole quadrant. There is never any situation where X is +ve and Y is -ve. Unless I'm fundamentally misunderstanding something (and I may be), I'm pretty sure this is not the behaviour I should be seeing, and it must be contributing to the problem.
Comment by M@t on 2016-06-24:
So if I spin the robot in a circle several times, here is the plotted data: XYZ, heading (should be oscillating between 0-360)
Comment by M@t on 2016-06-26:
Investigation regarding the imu is ongoing but it appears to be working correctly (for now). I have noticed that running the launch files on boot-up results in the /map
frame origin not being set correctly, but it is set when I use the set_datum service.
Comment by M@t on 2016-06-26:
Running the whole ekf launch file after startup (as opposed to during) produces this error when launching navsat_transform:
[ERROR] [1466993920.331485830]: Could not obtain transform from odom->base_link
This is the problem - navsat_transform can't calculate /map
s origin without that tf
Comment by M@t on 2016-06-28:
...no it's not. If I run each node one at a time, I don't get that error (most of the time). But I'm still seeing the same behaviour. /odom
moves relative to /map
and /map
moves relative to the robot/move goals. Nothing about /map
is accurate or consistent.
Comment by Tom Moore on 2016-06-29:
Hi Matt. Thanks for the info and updated files. I will look into this soon.
Comment by M@t on 2016-06-29:
It's the heading. I've tried changing the magnetic declination, yaw offset, datum heading... nothing affects the orientation of /map
. /map
always points to magnetic north, never true north like I want it to. Doesn't matter if I set the datum in the launch file or via rosservice.
Comment by M@t on 2016-06-29:
The heading is critical for the UTM calculation, so this implies that navsat_transform isn't getting the heading correct, which could be why the origin of /map
moves all over the place.
Comment by asimay_y on 2016-06-30:
hi, it's very interesting. can you set use_odometry_yaw
to true? so that the navsat node angle data is related with your odom frame. and question 2, did you try to set delay
to longer time?
Comment by M@t on 2016-06-30:
@asimay_y: I could but then I wouldn't have any earth-referenced heading, the IMU is my only source. I've tried changing delay
but it doesn't seem to have an effect.
Comment by M@t on 2016-06-30:
@Tom Moore: I've been looking through the source code and I see that navsat_transform
uses a gps_frame_id
-> base_link_frame_id
conversion. I'm using an auxiliary GPS whose location on the robot does not match the tf frame of the original GPS, could this contribute to the behavior I'm seeing?
Comment by M@t on 2016-06-30:
Well, for all practical purposes it doesn't seem to make a difference. I've updated the navsat_link
origin so it matches my auxiliary GPS (hacky but easier than creating a whole new frame for it). But the behavior is still the same and /map
's orientation is still glued to magnetic north.