-
Notifications
You must be signed in to change notification settings - Fork 100
Add local grid publisher #629
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
base: main
Are you sure you want to change the base?
Conversation
|
Can you run |
|
Actually, after thinking about this a bit more, I think it would be better to have this live in the existing Could you make those changes and also modify your node to follow our conventions for homogeneity (i.e. going through |
|
Where exactly in the If I recall correctly, you can have executable Nodes written in both languages within the same package, so it shouldn't be an issue that the code is in Python. |
|
Bumping to re-open the PR. I've tried looking into a way to add the python node to the base I could try rewriting the node in C++, but I'm unfamiliar with the Spot C++ SDK so it'd take some time. The Python local grid publisher node is working as-is, so I would rather figure out how to integrate that into the driver and have rewriting it in C++ as a possible future improvement down the line. I'm sure there is a way to do this- I just need to look through more of this documentation. |
|
@ryan-roche no need to convert to C++ -- we already have some python code in |
|
I'll keep it in its own node- think that'll make it easier to not run it unless the user explicitly asks for it with the launch arguments. Just gotta figure out how you specify package dependencies for your python nodes in an |
|
I've fixed the linting and un-hardcoded the local grid that the publisher node queries from the robot, but I've run into an issue. ROS OccupancyGrid message data can only be in Regardless, I'm going to need some guidance on how to handle converting the data from the different grids into the As of now, I'm not sure how to proceed, as the format of the data in each grid is kind of its own thing, and I'm unable to figure out an appropriate conversion from the information available in the SDK documentation. |
tcappellari-bdai
left a comment
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.
Looks good to me! Thanks for making the requested edits! I just want to test this out on one of our robots before merging as a sanity check
|
I wouldn't merge the changes as-is- the node currently converts the grid data from the SDK response into 8-bit integers since that's the only supported format for the OccupancyGrid message data. In order for the data to still be usable, there's going to need to be some unique conversion logic for each grid- otherwise the data's just going to be clipped since most of it is in a 16-bit format |
khughes-bdai
left a comment
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.
Thanks for the PR! This seems like a really helpful feature. Just left a few high level comments
| from spot_driver.manual_conversions import se3_pose_to_ros_pose | ||
| from spot_driver.ros_helpers import get_from_env_and_fall_back_to_param | ||
|
|
||
| VALID_GRIDS = ["terrain", "terrain_valid", "intensity", "no_step", "obstacle_distance"] |
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.
nit: can you leave a comment here with where these options are coming from? (I'm assuming it's in some BD docs)
| def generate_launch_description() -> launch.LaunchDescription: | ||
| # Define launch arguments | ||
| local_grid_name = DeclareLaunchArgument( | ||
| "local_grid_name", default_value="obstacle_distance", description="Name of the local_grid you want published" |
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.
if the list of valid local_grids is the same as the list hardcoded in the node, I'd reccomend enforcing that too here in a choices field (makes it easier at runtime to see what the options are)
| "local_grid_name", | ||
| default_value="obstacle_distance", | ||
| description="Name of the local_grid you want published (i.e. obstacle_distance, no_step, etc.)", | ||
| ) |
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.
same comment here, you can have a choices option
| if not self.ip or not self.username or not self.password: | ||
| self.get_logger().error("Robot credentials not found") | ||
| raise ValueError("Robot credentials not found") |
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.
nit: i think this block can be deleted, as these are guaranteed to fall back to the default values specified above
| output="screen", | ||
| parameters=[{"local_grid_name": LaunchConfiguration("local_grid_name")}], | ||
| namespace=LaunchConfiguration("spot_name"), | ||
| remappings=[("grid_topic_REMAP_ME", local_grid_topic)], |
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 seems like it's not necessary to include this remapping -- you are already getting the local grid name as a parameter inside your node, so you can internally just use that as the topic name. This should also be able to pick up the namespace of the spot_name
| # "terrain_valid" and "intensity" grid protos are uint8 | ||
|
|
||
| if raw_cells.dtype == np.uint8: | ||
| converted_cells = (raw_cells.astype(np.int16) - 128).astype( | ||
| np.int8 | ||
| ) # Subtract a bias value so values remain correctly relative to each other | ||
|
|
||
| # "terrain", "no_step", and "obstacle_distance" grid protos are int16 | ||
| else: | ||
| converted_cells = raw_cells.astype(np.int8) |
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.
Just to be clear, what lines here are the ones that are clipping data (from your earlier comment)?
| # Set runtime variables | ||
| self.first_draw_done = False | ||
| self.im = None | ||
| self.fig = None | ||
| self.ax = None |
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.
another nit -- seems like these variables aren't used, and can be deleted

Change Overview
This PR adds a module
/spot_local_gridwith a ROS2 node providing a publisher for Spot's local grid.(Grid messages visualized in Foxglove Studio)
It is currently hard-coded to publish the
obstacle_distancegrid, but I can refactor it to take an argument for which grid to publish.Since this was something I developed internally as part of another project, I separated it to its own module. Should you choose to merge this into the driver repo, it might make more sense to integrate it into the driver itself and have it optionally activated when using the driver launchfile, similar to the
--publish-point-cloudsargument.Testing Done
Please create a checklist of tests you plan to do and check off the ones that have been completed successfully. Ensure that ROS 2 tests use
domain_coordinatorto prevent port conflicts. Further guidance for testing can be found on the ros utilities wiki.Being that this module is so dependent on data from the robot, I wasn't able to make any unit tests for it.