Cartographer for mapping does not work

Hey,

we are coming from a ROS based system and are currently experimenting with isaac.
What we are doing is to test mapping, localization and navigation. We want to use the isaac cartographer wrapper for the mapping and localization.
Since we do have a robot that is based completely on ROS we wanted to test by just converting all sensor data to proto and use that in isaac.
What we’ve achieved so far is:

  • convert sensor_msgs::LaserScanto isaac::FlatscanProto
  • convert nav_msgs/Odometry to isaac::OdometryProto.
  • map ros::tf to isaac::PoseTree, we map base_link to robot and scan frame to lidar
  • setup ROS turtlebot sim to test in simulation.

We’ve based our apps on the //apps/carter/log_cartographer and //apps/carter/log_gmapping example.

We can get gmapping to work (at least a map is shown, the mapping params need to be tuned):

Cartographer does not work:
(I am not allowed to post more than one image) No map is shown and after closing the app , the map in /tmp is empty.

We are also confused by the documentation. According to this
cartographer does not need odometry as input as gmapping does.
However, according to this requirement cartographer needs some sort of odometry?

We have no idea what could be wrong with our cartographer app, since we use exactly the same app as for gmapping except including the cartographer subgraph and cartographer configs similar to the carter example.
We also cannot try the log_cartographerexample since the replay data is missing.

We use SDK version 2020.1.

Any help or pointers would be largely appreciated! Thanks in advance and kind regards,

Thomas

I think i get it now.
isaac::Cartographer reads odom directly from the PoseTree?
isaac::GMapping let’s the user decide if it should be read from the PoseTree or from the odom RX.
If i set use_pose_tree=true for GMapping, it also does not work and mapping gets stuck after the first scan.

Could it be that reading the PoseTree does not work correctly for isaac::Cartographer as well, resulting in our posted problem?
If so, what could cause this behaviour? We only use RosToPose to transfer our ros::TF to isaac. Websight does show the correct transformations. So reading works at least for other components.

Hi, @thomas.lindemeier

Thanks for trying out Isaac SDK!
In Isaac SDK PoseTree is used to manage pose information instead of message. Cartographer requires odometry data to function properly as mentioned in:
https://isaac.nvidia.com/master/packages/lidar_slam/doc/cartographer.html?highlight=pose

To have pose data into PoseTree: https://isaac.nvidia.com/master/doc/doc/component_api.html?highlight=posetree#isaac-alice-posetree

One way to do that is having a codelet that receives pose data from message channel and update the data into PoseTree periodically. Pose hook in engine/alice/hooks/pose_hook.hpp may come handy. You could define
ISAAC_POSE3(odom, sensor);
in the codelet and update data like
set_odom_T_sensor(pose_data, time_in_secs);

Hope this helps.

Hi,
the links where not working for me.
Here the fixed ones:
https://docs.nvidia.com/isaac/isaac/packages/lidar_slam/doc/cartographer.html?highlight=pose
and
https://docs.nvidia.com/isaac/isaac/doc/doc/component_api.html?highlight=posetree#isaac-alice-posetree
Best Markus

1 Like

Hi,

thank you very much for the reply.
We’ve setup a RosToPoses node thats maps all necessary tf poses to the PoseTree. The odom2robot transform gets correctly mapped from the tf::transform odom2base_link.
I can see that it works via websight. The poses are correctly synchronized to the PoseTree. However, GMapping is not working when GMapping::use_pose_tree settings is set to true. The laser scans are shown, but the map is not built, it seems that odom2robot is not read, or doesn’t change (although it does, as can be seen in websight::PoseTree).
My guess is, that this is the same prolem with cartographer since it directly reads from the PoseTree.

I tried to set the odom2robot manually as you suggested. I’ve put it into our ros::nav_msgs::Odometry to isaac::Odometry2Protoconverter, which is called at a rate of 50Hz. This does not work as intended though. After disabling our RosPoses mapper, the odom2robotshould now come only from our new converter node. If I std::cout the transform odom2robot it prints the correct values, but websight seems to be not synchronized. It seems to get not updated for longer periods. GMapping with use_pose_tree=true is also not working when using the manually published odom2robot transform. No warning or error is printed from isaac.

Is there a suggested rate for publishing PoseTree transformations? Could this be the reason of websight being not updated?

Best,

Thomas

Thx for fixing the links!

I have an idea,

we are playing rosbags with old time stamps.
Could it be that the RosToPose mapper uses the old time stamps? Resulting in old transformations when GMapping or cartographer query the PoseTree with a current time as argument?

I’ll investigate that and will post my results.

edit, this is what i get if read the odom2robot using a custom codelet that does nothing except periodically reading the odom2robot from the pose tree:

2020-07-14 11:04:14.395 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation   4.15523 -0.881271	rotation 0.797655
2020-07-14 11:04:14.495 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 0 0	rotation 0
2020-07-14 11:04:14.595 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation   4.24858 -0.772422	rotation 0.938966
2020-07-14 11:04:14.695 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 0 0	rotation 0
2020-07-14 11:04:14.795 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation   4.34188 -0.623418	rotation 1.08446

That seems strange. I use a pose initializer to set odom2robot to identity. I assume that this gets overwritten by RosToPoses?

Found out a a pose initializer does interfere. Removed the pose initializer and this happens:

2020-07-14 11:15:31.293 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 3.36078 9.62546	rotation 1.72432
2020-07-14 11:15:31.392 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 3.34834 9.70486	rotation 1.73326
2020-07-14 11:15:31.492 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 3.32959 9.81459	rotation 1.75306
2020-07-14 11:15:31.593 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation  3.3176 9.87832	rotation 1.77064
2020-07-14 11:15:31.692 INFO  packages/mojin_isaac/utils/PoseTreeTransformationReader.cpp@22: odom2robot: 	translation 3.30116 9.95658	rotation 1.79431

Edit:
I misunderstood the PoseInitializer. From the naming I concluded it is only an initializer, but it can be used to periodically publish a transform.
This can be controlled by params.

I’ve identified a major problem with how we use isaac and rely on played rosbags.
The PoseTree lives in another time as the messages.
Using sim_time=true and rosbag play --clock does not work since the RosToPoses still uses “current time”:

node()->pose().set(pose_mapping.isaac_pose.lhs_frame, pose_mapping.isaac_pose.rhs_frame, pose,
                         getTickTime());

My workaround is to use this instead:

 node()->pose().set(pose_mapping.isaac_pose.lhs_frame, pose_mapping.isaac_pose.rhs_frame, pose,
                         (get_enable_time_travel()) ? getTickTime() : transformStamped.header.stamp.toSec());

in packages/ros_bridge/components/RosToPoses.cpp.
I also parameterize whether to use forwarded time in all Ros to Proto converters.

This fixes using GMapping with use_pose_tree=true.
The original problem is not solved by that. Cartographer is still not running, nothing changed.

I also find it not helpful if tf2 lookup exceptions are caught and not handled:

 } catch (...) {
      // tf2::TransformException will be thrown if transformation could not be read
    }

packages/ros_bridge/components/RosToPoses.cpp:63

You will never know if your tf to PoseTree sync works or not.
It should be at least handled like this:

 } catch (tf2::TransformException& ex) {
      LOG_WARNING(ex.what());
    }