I’m trying to create a custom Nitro message for my CUDA ROS 2 node, but I can’t find any documentation on how to approach this.
Could someone provide the steps or point me to a guide on creating and integrating custom Nitro messages in ROS 2? Any examples would be greatly appreciated.
I was using these as a tutorial for how to use Nitro pub/sub in my ROS 2 node. However, the existing Nitro message types do not include the fields I need.
I need a custom message—for example, something similar to nvidia::isaac_ros::nitros::NitrosCustomListMap (namespace TBD custom::custom::NitroCustomListMap) where I can define the message fields myself.
Hi,
I’m still trying to create a custom message for Nitros. I need a modified version of the occupancyGrid and then a message with a List of occupancyGrid.
I created the ros msgs interfaces. But now I’m stuck on how to pass the list to the gfx entity. I know I can’t use the same approach as the TensorList since I do not have a gfx entity, but I saw I could use a createOccupancySetMessage and getOccupancySetMessage, but I’m not sure how or if it’s the correct approach.
auto griddata_msg = msg_entity->get<mycustom::OccupancySet>()
OR
griddata_msg = createOccupancySetMessage( msg_entity.value())
for (map : griddata_msg){
grid_data = mycustom::OccupancyGrid();
grid_data.name = map→get<int>(“name”);
}
auto griddata_msg = msg_entity->get<mycustom::OccupancySet>();
// OR
griddata_msg = createOccupancySetMessage(msg_entity.value());
these are not interchangeable:
msg_entity->get<mycustom::OccupancySet>() Used when some upstream GXF codelet has already created the message and you’re just reading it (typical for convert_to_ros()).
createOccupancySetMessage(...) Used when you’re in ROS → GXF direction, and you need to allocate and populate the GXF message from a ROS msg (typical for convert_to_gxf()).
If you’ve already created your own ROS msg type something like below,
# CustomOccupancyGrid.msg
string name
float32 resolution
# … other fields …
# CustomOccupancyGridList.msg
CustomOccupancyGrid grids
then in your Nitros type’s ROS → GXF conversion you can do something like:
void convert_to_gxf(const my_pkg::msg::CustomOccupancyGridList & msg)
{
// here `msg` is CustomOccupancyGridList
// and `msg.grids` is the array field defined above
}
and inside that function follow this pattern to pass the list into the GXF entity.
// PSEUDOCODE – use the real OccupancySet API from its header
// Allocate an entity that owns an OccupancySet.
auto maybe_entity = createOccupancySetMessage(context /* or nitros ctx */);
if (!maybe_entity) {
// handle error
}
auto entity = std::move(maybe_entity.value());
// Get your OccupancySet component off the entity
auto occ_set = entity.getmycustom::OccupancySet().value();
// Resize / add entries to match msg.grids.size()
occ_set->resize(msg.grids.size()); // or addGrid(i), depending on API
for (size_t i = 0; i < msg.grids.size(); ++i) {
auto & map = occ_set->at(i); // or operator[] / getGrid(i) / iterator
// Fill fields from your ROS message (keys depend on your OccupancySet schema)
map.set<std::string>("name", src.name);
map.set<float>("res", src.resolution);
// … etc: copy width, height, origin, data, etc., according to your design ...
}
// Return ‘entity’ as the GXF message for NITROS
Note: this is not a fully validated implementation. You’ll need to adapt it to your actual OccupancySet API and your specific use case.
In your design, GridData is declared as a gxf::Component but you never create it with entity.add<GridData>(), you just do GridData grid; and push it into a std::vector<GridData>.
That’s inconsistent with how GXF Components are supposed to be used.
You can fix this in the simpler way by dropping : public gxf::Component from GridData, so it’s just a plain struct that holds handles to real Components. With GridData no longer a Component, storing it by value in std::vector<GridData> is fine.
Also, you need to fix the member name mismatch in CreateGridDataListMessag.
It should be grid.data= tensor;not grid.tensor.
Another issue is kDevice means GPU memory; std::memcpy will not copy host→device correctly. If you only need CPU storage: use MemoryStorageType::kHost (or whichever host storage the allocator provides), then std::memcpy is OK.
If you really want to use kDevice, then replace std::memcpy with a CUDA copy or NITROS utility that copies from host to device.
The existing NITROS occupancy grid type is a good reference for how to wire the allocator + copy properly: