Actions

ROS2 actions are designed for long-running tasks that provide feedback during execution and can be cancelled. Unlike services (which are synchronous request-response), actions allow you to monitor progress and interrupt execution. Common examples include navigation goals, arm trajectories, and robot behaviors.

When to Use Actions vs Services

Use Actions when:

  • Task takes significant time to complete (seconds to minutes)
  • You need progress feedback during execution
  • Task should be cancellable mid-execution
  • Examples: navigation goals, arm movements, robot behaviors

Use Services when:

  • Task completes quickly (milliseconds)
  • No progress feedback needed
  • Examples: getting parameters, triggering snapshots, simple calculations

listActions()

List all available ROS2 action servers.

Returns: Promise<Array<{name: string, type: string}>> - Array of action servers with names and types

JS
// JavaScript const actions = await oloClient.core.listActions(); console.log('Available actions:', actions); // Output: [{ name: '/my_action', type: 'my_pkg/action/MyAction' }, ...] // Filter by package name const robotActions = actions.filter(a => a.type && a.type.includes('my_pkg')); console.log('Robot actions:', robotActions);

getActionsForNode(nodeName)

Get actions for a specific ROS2 node with reliable type information. This method uses ros2 node info which always returns action types correctly.

Parameters:

  • nodeName (string) - The ROS2 node name (e.g., '/bt_navigator')

Returns: Promise<Array<{name: string, type: string}>> - Array of actions with names and types

JS
// JavaScript const actions = await oloClient.core.getActionsForNode('/bt_navigator'); console.log('Actions for bt_navigator:', actions); // Output: [{ name: '/navigate_to_pose', type: 'nav2_msgs/action/NavigateToPose' }, ...]

getActionGoalStructure(actionType)

Get the goal message structure for a ROS2 action type. This is useful for understanding what parameters an action accepts before invoking it.

Parameters:

  • actionType (string) - The action type from discovery (e.g., 'nav2_msgs/action/NavigateToPose')

Returns: Promise<Object> - Structure information with goal, result, and feedback fields

JS
// JavaScript - First discover actions, then use the 'type' field const actions = await oloClient.core.listActions(); const action = actions.find(a => a.name === '/navigate_to_pose'); // Use action.type (NOT action.name) const structure = await oloClient.core.getActionGoalStructure(action.type); console.log('Goal fields:', structure.goal); console.log('Result fields:', structure.result); console.log('Feedback fields:', structure.feedback);

sendActionGoal(actionName, actionType, goal, options)

Send a goal to a ROS2 action server. This method returns immediately with a goal handle that can be used to cancel the action. Use callbacks to receive feedback and results.

Parameters:

  • actionName (string) - The action server name (e.g., '/my_action')
  • actionType (string) - The action type (e.g., 'my_pkg/action/MyAction')
  • goal (object) - The goal message values
  • options (object, optional) - Additional options:
    • onFeedback (function) - Callback for feedback messages: (feedback) => void
    • onResult (function) - Callback for result: (result, status) => void
    • timeout (number) - Timeout in milliseconds (JavaScript) or seconds (Python)

Returns: Promise<{goalId: string, cancel: function}> - Goal handle with cancel function

Status values: 'succeeded', 'cancelled', 'aborted', 'timeout', 'unknown'

JS
// JavaScript - Send goal with feedback const handle = await oloClient.core.sendActionGoal( '/my_action', 'my_pkg/action/MyAction', { /* goal fields based on action structure */ }, { onFeedback: (feedback) => { console.log('Progress:', feedback); }, onResult: (result, status) => { console.log('Completed with status:', status); console.log('Result:', result); }, timeout: 60000 // 60 seconds } ); console.log('Goal started with ID:', handle.goalId); // Cancel the action if needed // handle.cancel();

cancelActionGoal(actionName, goalId)

Cancel an active action goal.

Parameters:

  • actionName (string) - The action server name
  • goalId (string) - The goal ID to cancel

Returns: Promise<boolean> - True if cancel message was sent

JS
// JavaScript const handle = await oloClient.core.sendActionGoal('/my_action', 'my_pkg/action/MyAction', goal); // Later, cancel the action await oloClient.core.cancelActionGoal('/my_action', handle.goalId);

callAction(actionName, actionType, goal, options)

Call a ROS2 action and wait for the result. This is a convenience method that sends a goal and blocks until completion. Use this for simpler fire-and-wait scenarios.

Parameters:

  • actionName (string) - The action server name
  • actionType (string) - The action type
  • goal (object) - The goal message values
  • options (object, optional) - Additional options:
    • onFeedback (function) - Optional callback for feedback messages
    • timeout (number) - Timeout in milliseconds (JS) or seconds (Python). Default: 60000ms / 60s

Returns: Promise<{result: object, status: string}> - Action result and final status

Throws: Error if action is cancelled, aborted, or times out

JS
// JavaScript - Simple action call try { const { result, status } = await oloClient.core.callAction( '/my_action', 'my_pkg/action/MyAction', { /* goal fields */ }, { onFeedback: (fb) => console.log('Progress:', fb), timeout: 30000 } ); console.log('Action complete! Status:', status); } catch (err) { console.error('Action failed:', err.message); }

Action Discovery Workflow

A typical workflow for working with actions on your robot:

JS
// 1. Discover available actions const actions = await oloClient.core.listActions(); console.log('Found', actions.length, 'action servers'); // List them for (const action of actions) { console.log(' ', action.name, '->', action.type || 'unknown'); } // 2. Find an action with a known type const targetAction = actions.find(a => a.type && a.type !== 'unknown'); if (!targetAction) { console.log('No actions with known types found'); return; } // 3. Get the goal structure to understand required fields const structure = await oloClient.core.getActionGoalStructure(targetAction.type); console.log('Action requires:', structure.goal); // 4. Invoke the action with proper parameters const { result, status } = await oloClient.core.callAction( targetAction.name, targetAction.type, { /* fill in goal fields based on structure */ } ); console.log('Action completed:', status);