6.3.7. Middleware API¶
micro-ROS default rmw layer rmw_microxrcedds_c offers a set of utilities to directly configure and interact with the underlying middleware.
The exposed API detailed on this documentation can be used with the rmw_microxrcedds_c
public header: #include <rmw_microros/rmw_microros.h>
.
6.3.7.1. Transport configuration¶
Middleware provided transports can be configured at run-time, allowing the user to set the Agent address or the serial port identifier:
// Init RCL options and context
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_init_options_init(&init_options, rcl_get_default_allocator());
// Take RMW options from RCL options
rmw_init_options_t* rmw_options = rcl_init_options_get_rmw_init_options(&init_options);
// UDP transport configuration
char* agent_ip = "127.0.0.1";
char* agent_port = "8888";
rmw_uros_options_set_udp_address(agent_ip, agent_port, rmw_options);
// Serial transport configuration
char* serial_device = "/dev/ttyAMA0";
rmw_uros_options_set_serial_device(serial_device, rmw_options)
Note
Transport must be enabled on build time using RMW_UXRCE_TRANSPORT_UDP
or RMW_UXRCE_TRANSPORT_SERIAL
options.
6.3.7.2. Client Key configuration¶
The client key will identify a micro-ROS client on the Agent side, implying that all the connected clients must have a different key. This value is set randomly on micro-ROS initialization, but it is also possible to set it manually:
// Init RCL options and context
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_context_t context = rcl_get_zero_initialized_context();
rcl_init_options_init(&init_options, rcl_get_default_allocator());
// Take RMW options from RCL options
rmw_init_options_t* rmw_options = rcl_init_options_get_rmw_init_options(&init_options);
// Set RMW client key
uint32_t client_key = 0xBA5EBA11;
rmw_uros_options_set_client_key(0xBA5EBA11, rmw_options);
This feature can be useful for reusing DDS entities already created on the agent side, as explained on this Micro XRCE-DDS Deployment example.
6.3.7.3. Time configuration¶
6.3.7.3.1. Timeouts¶
Confirmation timeout: Reliable entities can increase blocking time on
rcl_publish
or executor spin calls as they will wait for the acknowledgement of each sent message.The default timeout value can be modified individually at run-time:
// Confirmation timeout in milliseconds int ack_timeout = 1000; // Get RWM publisher handle and set reliable timeout rmw_publisher_t* rmw_publisher_handle = rcl_publisher_get_rmw_handle(&publisher); rmw_uros_set_publisher_session_timeout(&rmw_publisher_handle, ack_timeout); // Get RWM service handle and set reliable timeout rmw_service_t* rmw_service_handle = rcl_service_get_rmw_handle(&service); rmw_uros_set_service_session_timeout(rmw_service_handle, ack_timeout); // Get RWM service handle and set reliable timeout rmw_client_t* rmw_client_handle = rcl_client_get_rmw_handle(&client); rmw_uros_set_client_session_timeout(rmw_client_handle, ack_timeout);
Entity timeouts: Creation and destruction of entities also include a timeout, as they will wait for the Agent confirmation on the operation. This timeout will affect all
init
andfini
methods such asrclc_node_init_default
,rcl_publisher_fini
, etc.The default value can be modified at run-time for all entities:
rclc_support_t support; support.context rmw_context_t * rmw_context = rcl_context_get_rmw_context(&support.context); if (NULL != rmw_context) { // Timeout in milliseconds int timeout = 1000; rmw_uros_set_context_entity_creation_session_timeout(rmw_context, timeout); rmw_uros_set_context_entity_destroy_session_timeout(rmw_context, timeout); }
Note
To avoid waiting for agent confirmation
timeout = 0
can be used, allowing the release of local resources if the agent is not present.
6.3.7.3.2. Time synchronization¶
micro-ROS clients can synchronize their epoch time with the connected Agent, this can be very useful when working in embedded environments that do not provide any time synchronization mechanism. This utility is based on the NTP protocol, taking into account delays caused by the transport layer.
An usage example can be found on epoch_synchronization micro-ROS demo:
// Sync timeout
const int timeout_ms = 1000;
// Synchronize time with the agent
rmw_uros_sync_session(timeout_ms);
After the session is synchronized, the adjusted timestamp can be retrieved with the following API:
// Check if session has been synchronized
if (rmw_uros_epoch_synchronized())
{
// Get time in milliseconds or nanoseconds
int64_t time_ms = rmw_uros_epoch_millis();
int64_t time_ns = rmw_uros_epoch_nanos();
}
Note
micro-ROS shall be already initialized and connected to the agent to use this functionality.
6.3.7.4. Ping agent¶
The client can test the connection with the Agent with the ping utility. This functionality can be used even when the micro-ROS context has not yet been initialized, which is useful to test the connection before trying to connect to the Agent. An example can be found on ping_uros_agent micro-ROS demo.
// Timeout for each attempt
const int timeout_ms = 1000;
// Number of attemps
const uint8_t attemps = 5;
// Ping the agent
rmw_ret_t ping_result = rmw_uros_ping_agent(timeout_ms, attempts);
if (RMW_RET_OK == ping_result)
{
// micro-ROS Agent is reachable
...
}
else
{
// micro-ROS Agent is not available
...
}
A secondary API is provided to ping the Agent with a specific rmw configuration. This API allows the user to ping with a specific custom transport without interfering with the actual micro-ROS configuration:
// Initialize rcl options and retrieve the internal rmw options
rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
rcl_init_options_init(&init_options, allocator);
rmw_init_options_t * rmw_options = rcl_init_options_get_rmw_init_options(&init_options);
// Set custom transport
rmw_uros_options_set_custom_transport(
false,
NULL,
custom_transport_open,
custom_transport_close,
custom_transport_write,
custom_transport_read,
rmw_options);
// Ping the agent with custom transport
const int timeout_ms = 1000;
const uint8_t attemps = 5;
rmw_ret_t ping_result = rmw_uros_ping_agent_options(timeout_ms, attempts, rmw_options);
if (RMW_RET_OK == ping_result)
{
// micro-ROS Agent is reachable
...
}
else
{
// micro-ROS Agent is not available
...
}
6.3.7.5. Error handling¶
micro-ROS RMW can be configured to report middleware errors to user space using custom callbacks.
This option is disabled by default and needs to be enabled at compile time via RMW_UROS_ERROR_HANDLING
CMake argument.
The behavior of this flag is:
RMW_UROS_ERROR_HANDLING=OFF
: Error handling is disabled. This is the default behavior. Errors are not reported to user space.
RMW_UROS_ERROR_HANDLING=ON
and callback not set: Error handling is enabled. Default ROS 2 RMW macros are used to report errors.
RMW_UROS_ERROR_HANDLING=ON
and callback set: Error handling is enabled. User callback and default ROS 2 RMW macros are used to report errors.
An example colcon.meta
is:
{
"names": {
"rmw_microxrcedds": {
"cmake-args": [
"-DRMW_UROS_ERROR_HANDLING=ON"
]
}
}
}
Once enabled, the user can register a callback to be called when an error is detected, using the following API:
void rmw_uros_set_error_handling_callback(
rmw_uros_error_handling error_cb);
An example callback of type rmw_uros_error_handling
is:
void error_handler(
const rmw_uros_error_entity_type_t entity,
const rmw_uros_error_source_t source,
const rmw_uros_error_context_t context,
const char * file,
const int line)
{
// Do something with the error
...
}
rmw_uros_error_entity_type_t
represent with entity is triggering the error.
It can be one of the following:
RMW_UROS_ERROR_ON_UNKNOWN
: Generic entity.
RMW_UROS_ERROR_ON_NODE
: Node entity.
RMW_UROS_ERROR_ON_SERVICE
: Service server entity.
RMW_UROS_ERROR_ON_CLIENT
: Service client entity.
RMW_UROS_ERROR_ON_SUBSCRIPTION
: Subscription entity.
RMW_UROS_ERROR_ON_PUBLISHER
: Publisher entity.
RMW_UROS_ERROR_ON_GRAPH
: Graph manager.
RMW_UROS_ERROR_ON_GUARD_CONDITION
: Guard condition entity.
RMW_UROS_ERROR_ON_TOPIC
: Topic memory.
rmw_uros_error_source_t
represent the source of the error.
It can be one of the following:
RMW_UROS_ERROR_ENTITY_CREATION
: Error on entity creation.
RMW_UROS_ERROR_ENTITY_DESTRUCTION
: Error on entity destruction.
RMW_UROS_ERROR_CHECK
: Error on a check.
RMW_UROS_ERROR_NOT_IMPLEMENTED
: Feature not implemented.
RMW_UROS_ERROR_MIDDLEWARE_ALLOCATION
: Memory error.
rmw_uros_error_context_t
represent the context of the error and contains, one or more of the following members:
node
: Name of the node of typeconst char *
.
node_namespace
: Namespace of the node of typeconst char *
.
topic_name
: Name of the topic of typeconst char *
.
ucdr
: Pointer to theucdrBuffer
of typeconst ucdrBuffer *
.
size
: Size of the buffer of typesize_t
.
type_support
: Pointer to the type support of typeconst message_type_support_callbacks_t *
orconst service_type_support_callbacks_t *
.
description
: Description of the error of typeconst char *
.
Also, this callback function gets the file name and line number where the error was detected. This information can be accessed using:
file
: File name of typeconst char *
.
line
: Line number of typeint
.