Open rotu opened 5 years ago
I think that the idea is to enforce node name uniqueness, but it has not been applied yet (see here). The only ticket I see tracking that is https://github.com/ros2/design/issues/187.
I think that the idea is to enforce node name uniqueness
I think that that's a great idea down the road, and it would obviate this issue. But it's also way too easy to have nodes not be unique right now and it's extremely confusing when the tools make this harder to introspect. My naive expectation is that the cli tools should throw up a warning and print info on all the nodes with that same name.
Is that duplicate node in ros2 node list
a caching issue in the daemon (and therefore not actually a live node at all)? Is it two instances of the same node accidentally being spun up in a launch file? Is it a TransformListener
node being launched deep in some library my code is using? Is it someone else on the same network using ROS?
My naive expectation is that the cli tools should throw up a warning and print info on all the nodes with that same name.
The problem is that that change would require changes in the cli, rclpy
, rcl
, rmw
, and in each rmw
implementation.
For example, for getting the subscribers info, the cli creates a node (with rclpy
). Through that node, it ends up calling rcl_get_subscriber_names_and_types_by_node
https://github.com/ros2/rcl/blob/ec8539b65c4c2b46d71c3bd6a5a9e25d8ab316b4/rcl/include/rcl/graph.h#L91-L136
That function wraps a similar rmw
function. For each rmw
implementation that function returns the subscribers info of the first node with that name found.
Ouch! So RCL doesn’t even have a globally unique identifier for nodes?
Ouch! So RCL doesn’t even have a globally unique identifier for nodes?
No. I think originally it was assumed that the node names were unique, but this isn't enforced (possibly an oversight?). IMO we should first decide if node names should be unique (ros2/design#187), if not, then we should implement GUIDs for nodes and use it throughout the stack.
// Function declarations int initialize_ros2(int argc, char argv[], rcl_context_t context, rcl_node_t node, rcl_publisher_t publisher); int capture_and_publish_audio(rcl_context_t context, rcl_publisher_t publisher); void cleanup_ros2(rcl_context_t context, rcl_node_t node, rcl_publisher_t *publisher);
int main(int argc, char *argv[]) { rcl_context_t context; rcl_node_t node; rcl_publisher_t publisher;
if (initialize_ros2(argc, argv, &context, &node, &publisher) != 0) {
return 1;
}
if (capture_and_publish_audio(&context, &publisher) != 0) {
cleanup_ros2(&context, &node, &publisher);
return 1;
}
cleanup_ros2(&context, &node, &publisher);
return 0;
}
int initialize_ros2(int argc, char argv[], rcl_context_t context, rcl_node_t node, rcl_publisher_t publisher) { rcl_ret_t ret;
// Initialize ROS 2 options
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_allocator_t allocator = rcl_get_default_allocator();
ret = rcl_init_options_init(&init_options, allocator);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error initializing ROS 2 options\n");
return 1;
}
// Initialize ROS 2 context
*context = rcl_get_zero_initialized_context();
ret = rcl_init(argc, (const char * const *)argv, &init_options, context);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error initializing ROS 2 context\n");
return 1;
}
// Create a ROS 2 node
*node = rcl_get_zero_initialized_node();
const char * node_name = "audio_publisher";
rcl_node_options_t node_options = rcl_node_get_default_options();
ret = rcl_node_init(node, node_name, "", context, &node_options);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error initializing ROS 2 node\n");
return 1;
}
// Create a ROS 2 publisher
*publisher = rcl_get_zero_initialized_publisher();
const rosidl_message_type_support_t * msg_type_support = ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, ByteMultiArray);
const char * topic_name = "audio_data";
rcl_publisher_options_t publisher_options = rcl_publisher_get_default_options();
ret = rcl_publisher_init(publisher, node, msg_type_support, topic_name, &publisher_options);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error initializing ROS 2 publisher\n");
return 1;
}
return 0;
}
int capture_and_publish_audio(rcl_context_t context, rcl_publisher_t publisher) { // Open the PCM device for recording snd_pcm_t *handle; if (snd_pcm_open(&handle, PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0) < 0) { fprintf(stderr, "Error opening PCM device %s\n", PCM_DEVICE); return 1; }
// Set parameters for recording
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(¶ms);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, 2);
unsigned int sample_rate = 44100;
snd_pcm_hw_params_set_rate_near(handle, params, &sample_rate, 0);
if (snd_pcm_hw_params(handle, params) < 0) {
fprintf(stderr, "Error setting PCM parameters\n");
snd_pcm_close(handle);
return 1;
}
// Buffer for captured audio
uint8_t buffer[AUDIO_BUFFER_SIZE];
// Create ROS 2 message
std_msgs__msg__ByteMultiArray msg;
std_msgs__msg__ByteMultiArray__init(&msg);
if (!rosidl_runtime_c__uint8__Sequence__init((rosidl_runtime_c__uint8__Sequence *)&msg.data, AUDIO_BUFFER_SIZE)) {
fprintf(stderr, "Error initializing ByteMultiArray sequence\n");
return 1;
}
// Publish captured audio
while (rcl_context_is_valid(context))
{
// Read audio data
int frames = snd_pcm_readi(handle, buffer, AUDIO_BUFFER_SIZE / 4); // 2 bytes per sample, 2 channels
if (frames < 0) {
frames = snd_pcm_recover(handle, frames, 0);
}
if (frames < 0) {
fprintf(stderr, "Error reading audio data: %s\n", snd_strerror(frames));
break;
}
// Assign buffer data to ROS 2 message
memcpy(msg.data.data, buffer, frames * 4); // 4 bytes per frame (2 bytes per sample, 2 channels)
msg.data.size = frames * 4;
// Publish audio data
rcl_ret_t ret = rcl_publish(publisher, &msg, NULL);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error publishing audio\n");
}
// Sleep for a short duration
usleep(10000); // 10 ms
}
// Clean up ROS 2 message
std_msgs__msg__ByteMultiArray__fini(&msg);
// Close PCM device
snd_pcm_close(handle);
return 0;
}
void cleanup_ros2(rcl_context_t context, rcl_node_t node, rcl_publisher_t *publisher) { rcl_ret_t ret;
// Shutdown ROS 2 resources
ret = rcl_publisher_fini(publisher, node);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error finalizing ROS 2 publisher\n");
}
ret = rcl_node_fini(node);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error finalizing ROS 2 node\n");
}
ret = rcl_shutdown(context);
if (ret != RCL_RET_OK)
{
fprintf(stderr, "Error shutting down ROS 2 context\n");
}
} this is my publisher code, i am trying to capture the audio and send it to the P.C means from SOM to PC, SOM(nvidia jetson agx developer kit 64 gb). The environment is ROS2 environment. Can you please help me out.
That question has nothing to do with this issue. Please open a question over on https://robotics.stackexchange.com/questions/tagged/ros, which is our central Question and Answer site. You'll get a better answer there, and it will be searchable for the future.
Make sure to include a lot of information on what platform you are using, which ROS distribution you are using, and the exact steps you took.
It is possible to launch multiple nodes of the same name. When this happens, those multiple nodes show up in
ros2 node list
but it is impossible to get info on these nodes withros2 node info
.In the below example, I have launched a single
amcl
process which spins up 3 nodes. But since the three nodes were assigned the same name, I can't introspect to see what topics those nodes are listening/publishing on.