Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
29ea12d
Mark version as `pre`
ted-miller Jul 15, 2025
1d457dc
Add service `start_rt_mode`
ted-miller Jul 15, 2025
6a0f6ef
ignore libmicroros folders
ted-miller Jul 15, 2025
7e07786
Add motion mode `MOTION_MODE_RT`
ted-miller Jul 15, 2025
4edb0c5
Change `StartRtMode` to use new message type
ted-miller Jul 15, 2025
87a3291
Manage interpolation task for each `MOTION_MODE`
ted-miller Jul 15, 2025
0f4a4ef
call library function
ted-miller Jul 16, 2025
f1ff1e0
Add RealTimeMotionControl.c to rpoject
ted-miller Jul 16, 2025
6d70c33
RealTimeMotionControl header
ted-miller Aug 12, 2025
932ced4
Make rt port number configurable
ted-miller Aug 14, 2025
e8ccaf2
Initial framework ready for testing
ted-miller Aug 14, 2025
404e879
subtraction was swapped
ted-miller Aug 14, 2025
67a48f3
Add timeout and clear motion mode
ted-miller Aug 14, 2025
c4d270a
Add RT fields to the yaml file
ted-miller Aug 14, 2025
be2d6a5
allow infinite timeout
ted-miller Aug 14, 2025
7f0feb9
Trying to make RT task able to be restarted
ted-miller Aug 14, 2025
ff34234
Remove gemini comments
ted-miller Aug 15, 2025
eb5ef13
Wrong socket id was preventing restart after timeout
ted-miller Aug 15, 2025
508dafc
I didn't get to use this product name for YMConnect. This will suffice.
ted-miller Aug 15, 2025
c1fb8e7
Add fb position to reply packet
ted-miller Aug 15, 2025
00a0f71
Add cartesian support
ted-miller Aug 22, 2025
4870a16
Apply feedback from Jimmy
ted-miller Sep 5, 2025
bf21d1b
Allow milliseconds for timeout
ted-miller Sep 19, 2025
7920aac
Make MAX_SEQUENCE_DIFFERENCE configurable
ted-miller Sep 19, 2025
3499120
User must call `stop_traj_mode` for consistency
ted-miller Sep 19, 2025
fb6e89f
Don't care about `Ros_setsockopt` return code
ted-miller Sep 19, 2025
9af33ba
Revert "ignore libmicroros folders"
ted-miller Sep 19, 2025
c241fdf
Remove `NOT_IMPLEMENTED` subcode
ted-miller Sep 19, 2025
4ab6157
excess whitespace
ted-miller Sep 19, 2025
14c147d
Add enums to elaborate ordering
ted-miller Sep 19, 2025
fa2add1
Add tool data
ted-miller Sep 19, 2025
62d9a8c
Unused variables
ted-miller Sep 19, 2025
3c2a5f9
Add cartesian and command positions to reply message
ted-miller Sep 19, 2025
a649731
Clarify `Ros_CtrlGroup_GetPulsePosCmd` comment
ted-miller Sep 26, 2025
db6b9b1
FSU detection
ted-miller Sep 26, 2025
afc8470
End session if API errors out (alarm or estop)
ted-miller Sep 26, 2025
b61eb17
Socket must persist for multiple sessions to work
ted-miller Sep 26, 2025
cd4d0e9
use absolute value
ted-miller Sep 26, 2025
2358575
Attempt (fail) to fix initialization problem.
ted-miller Sep 29, 2025
e95e412
`mpGetToolNo` was always getting R1
ted-miller Sep 29, 2025
7b6d54c
Purge stale packets at start of connection
ted-miller Sep 29, 2025
b35083b
Don't monitor speed limit for rotations
ted-miller Sep 29, 2025
c0895e9
Handle rollover of sequence id
ted-miller Sep 29, 2025
6f75377
Documentation
ted-miller Sep 30, 2025
4e3cbce
Satisfy REUSE and md_lint
ted-miller Sep 30, 2025
1c717f3
Whitespace
ted-miller Sep 30, 2025
3c8a1f5
Spelling
ted-miller Oct 2, 2025
be07e28
Report robot's configuration to the invoker
ted-miller Oct 2, 2025
a47be77
incoming increment can be negative
ted-miller Oct 2, 2025
4941a80
Ensure `prevRtCmdPosition` is set for all axes
ted-miller Oct 2, 2025
7c678f9
Tighten tolerance for `MAX_INCREMENT_DEVIATION_FOR_FSU_DETECTION`
ted-miller Oct 2, 2025
42ebb95
Fix warning on first cmd ID received
ted-miller Oct 2, 2025
28d7b11
Invalid boolean logic
ted-miller Oct 2, 2025
e96194f
Client should use the same timeout as the server
ted-miller Oct 2, 2025
cec6bf5
Purge UDP buffer before triggering next command
ted-miller Oct 2, 2025
66eb98e
header format
ted-miller Oct 10, 2025
7dad1ed
scale cartesian speed limit with interpolation clock
ted-miller Oct 10, 2025
8d6eae1
Consistent quotations for port numbers
ted-miller Oct 10, 2025
a213192
Repeat code. Remove it and explain what's happening
ted-miller Oct 10, 2025
fefa69d
Reply with error code if user requests invalid mode
ted-miller Oct 20, 2025
b57fc9e
rebase changed error codes
ted-miller Oct 20, 2025
c51090e
Correct subcode in link
ted-miller Oct 20, 2025
2f710a7
Use string; not enum
ted-miller Oct 29, 2025
c2593af
Documentation clarification based on review
ted-miller Nov 25, 2025
b410850
decrease `Timeout for real time motion commands`
ted-miller Dec 15, 2025
dcfe324
decrease `max_sequence_diff_for_rt_msg`
ted-miller Dec 15, 2025
184cdd8
Move `rt_udp_port_number` to range specified in manual
ted-miller Dec 15, 2025
92e3475
reflect port change in docs
ted-miller Dec 15, 2025
4339067
Implement `version` field
ted-miller Dec 15, 2025
b337a78
Verify incoming packet type
ted-miller Dec 15, 2025
47290e7
Implement feedback state
ted-miller Dec 15, 2025
efc8a88
Explicitly check packet size
ted-miller Mar 26, 2026
303cec8
Put robot state onto separate socket/thread
ted-miller Mar 26, 2026
1370af6
Set the dest address for SendRobotStatus routine
ted-miller Mar 26, 2026
3e8f8ba
Update documentation
ted-miller Mar 26, 2026
8421704
Remove control flag that terminates status info
ted-miller Mar 26, 2026
cb5eaa9
`mpConnect` is not needed since I'm using `sockaddr`
ted-miller Mar 27, 2026
2b18361
Formatting errors caught by linter
ted-miller Mar 27, 2026
9a493ee
Check return code when starting motion
ted-miller Jul 30, 2026
2c55b27
Ensure the default values match the default in the yaml
ted-miller Aug 12, 2026
f6d32ee
Add assertions when allocating RT socket
ted-miller Aug 12, 2026
450d688
Reword error message for clarity
ted-miller Aug 12, 2026
cb418be
Ensure that msgRobotStatus is allocated before usage
ted-miller Aug 12, 2026
cd45d09
`magnitude` instead of `vector`
ted-miller Aug 12, 2026
d27168b
`magnitude` should be mm instead of m
ted-miller Aug 12, 2026
9bdf8b8
Ensure `tidIncMoveThread` is valid before deleting it
ted-miller Aug 12, 2026
4619da4
Ensure `howMuchShouldIHaveMoved` is initialized from previous cycle
ted-miller Aug 19, 2026
e8eb2c7
Exclude external axes from cartesian feedback
ted-miller Aug 19, 2026
3c300f9
Set the cartesian frame based on the group type
ted-miller Aug 19, 2026
c4da270
Pack and version the `RobotState` packets
ted-miller Aug 19, 2026
6afbe03
Use `groupId` instead of `groupIndex`.
ted-miller Aug 19, 2026
900c214
`METERS_TO_MILLIMETERS` was inverted
ted-miller Aug 21, 2026
0191f08
Missing argument for debug msg
ted-miller Aug 21, 2026
0eb069b
Ensure `prevRtCmdPosition` gets processed for all groups
ted-miller Aug 21, 2026
fc799d4
Redundant `if` statement
ted-miller Aug 21, 2026
675f0f0
Utilize existing helper function
ted-miller Aug 21, 2026
4a78657
Verify only robots are being used for cartesian
ted-miller Aug 21, 2026
27c20ce
Check group id instead of index
ted-miller Aug 21, 2026
e8ed9af
Ensure `msgRobotStatus` gets NULL'ed out
ted-miller Aug 21, 2026
4020c6c
Exclude base tracks from cartesian mode.
ted-miller Aug 21, 2026
15513c5
Use quaternion for rotation instead of euler.
ted-miller Aug 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .reuse/dep5
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,7 @@ License: CC0-1.0
Files: doc/img/logo.png
Copyright: 2023 Yaskawa America, Inc.
License: CC-BY-NC-ND-4.0

Files: doc/img/RtFlow.png doc/img/RtFlow.vsdx
Copyright: 2023 Yaskawa America, Inc.
License: CC-BY-NC-ND-4.0
12 changes: 10 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
<!--
SPDX-FileCopyrightText: 2022-2023, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2022-2023, Delft University of Technology
SPDX-FileCopyrightText: 2022-2025, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2022-2025, Delft University of Technology

SPDX-License-Identifier: CC-BY-SA-4.0
-->

# Changelog

## Forthcoming

MotoROS2 is now built against `micro_ros_motoplus` version TODO

New functionality:

- Add new motion mode for real-time control of the robot. This pipes the user commands directly to the motion API with minimal overhead. ([#449](https://github.com/Yaskawa-Global/motoros2/pull/449))

## 0.2.1 (2025-06-26)

MotoROS2 is now built against `micro_ros_motoplus` version `20250328`.
Expand Down
30 changes: 24 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--
SPDX-FileCopyrightText: 2022-2023, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2022-2023, Delft University of Technology
SPDX-FileCopyrightText: 2022-2025, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2022-2025, Delft University of Technology

SPDX-License-Identifier: CC-BY-SA-4.0
-->
Expand Down Expand Up @@ -605,7 +605,12 @@ Instead, write a `FollowJointTrajectory` action *client* script or use a motion

### Commanding motion

The ROS API of MotoROS2 for commanding motion is similar to that of `motoman_driver` (with MotoROS1), and client applications are recommended to implement a similar flow of control to keep track of the state of the robot before, during and after trajectory and motion execution.
There are three methods of commanding motion using MotoROS2.
`FollowJointTrajectory` action server, point streaming, and real-time incremental control.

#### - [FollowJointTrajectory](doc/ros_api.md#follow_joint_trajectory) action server

The ROS API of MotoROS2 for commanding motion is similar to that of motoman_driver (with MotoROS1), and client applications are recommended to implement a similar flow of control to keep track of the state of the robot before, during and after trajectory and motion execution.

The following provides a high-level overview of the behaviour a client application should implement to successfully interact with the [FollowJointTrajectory](doc/ros_api.md#follow_joint_trajectory) action server offered by MotoROS2.
While not all steps are absolutely necessary, checking for errors and monitoring execution progress facilitates achieving robust execution and minimises unexpected behaviour in both client and server.
Expand All @@ -632,7 +637,22 @@ As a final check, inspect the `error_code` field of the result to ascertain exec
1. if there are more trajectories to execute, return to step 2.
Otherwise call the [stop_traj_mode](doc/ros_api.md#stop_traj_mode) service to exit MotoROS2's trajectory execution mode

Interaction with the *point streaming* interface (MotoROS2 `0.0.15` and newer) would be similar, although no `FollowJointTrajectory` action client would be created, no goals would be submitted and monitoring robot status would be done purely by subscribing to the [robot_status](doc/ros_api.md#robot_status) topic (instead of relying on an action client to report trajectory execution status).
#### - [QueueTrajectoryPoint](doc/ros_api.md#queue_traj_point) point streaming

Interaction with the *point streaming* interface (MotoROS2 `0.0.15` and newer) would be similar to the process above, although no `FollowJointTrajectory` action client would be created, no goals would be submitted and monitoring robot status would be done purely by subscribing to the [robot_status](doc/ros_api.md#robot_status) topic (instead of relying on an action client to report trajectory execution status).

Rather than submitting a complete trajectory in a single goal, an indefinite number of points are submitted to the robot one at a time.
The execution of the robot will be identical to the behavior of `FollowJointTrajectory`.

#### - [StartRtMode](doc/ros_api.md#start_rt_mode) real-time incremental motion

This activates a separate UDP server which listens for real-time position increments.
It is intended to be used in a closed loop system which requires low level control of the motion.
This UDP server is activated using a ROS2 service.
However, the protocol for commanding/monitoring motion is *not* based on ROS2 communication.

This control mode minimizes overhead as much as possible by routing the user commands directly to the motion API.
See [R/T Motion Control](doc/rt_control.md) for information on the protocol implementation.

### With MoveIt

Expand Down Expand Up @@ -844,9 +864,7 @@ The following items are on the MotoROS2 roadmap, and are listed here in no parti
- native (ie: Agent-less) communication
- support asynchronous motion / partial goals
- complete ROS parameter server support (there is currently no support for `string`s in RCL)
- real-time position streaming interface (skipping MotoROS2's internal motion queue)
- Cartesian motion interfaces
- velocity control (based on `mpExRcsIncrementMove(..)`)
- integration with ROS logging (`rosout`)
- publishing static transforms to `tf_static`
- integrate a UI into the teach pendant / Smart Pendant
Expand Down
47 changes: 47 additions & 0 deletions config/motoros2_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -318,3 +318,50 @@ publisher_qos:
# OPTIONS: USER_LAN1, USER_LAN2
# DEFAULT: (all available network ports)
#debug_broadcast_port: USER_LAN1

#-----------------------------------------------------------------------------
# For the real time motion interface, which port should the UDP messages
# be transmitted on?
#
# DEFAULT: 22000
#rt_listener_udp_port_number: 22000

#-----------------------------------------------------------------------------
# For the real time robot status interface, which port should the UDP messages
# be transmitted on?
#
# DEFAULT: 22001
#rt_status_udp_port_number: 22001

#-----------------------------------------------------------------------------
# For the real time robot status interface, how much delay should there be
# between messages?
#
# DEFAULT: 10
#rt_status_sleep_period: 10

#-----------------------------------------------------------------------------
# Timeout for real time motion commands. If a command packet is not received
# within this number of milliseconds, the motion mode will be cancelled. This
# applies to all packets within R/T session.
#
# Additionally, if the client does not receive a reply packet within this
# amount of time, then it should be assumed that the session is dead.
#
# Setting this to '-1' will never timeout. In that case, you must explicitly
# call '/stop_traj_mode' to stop the motion mode.
#
# DEFAULT: 5000 (5.000 seconds)
#timeout_for_rt_msg: 5000

#-----------------------------------------------------------------------------
# When using the real time motion interface, each command packet must increment
# the sequence ID. If too many packets are lost during communication, then it
# will be assumed that the PC is not in sync with the robot.
#
# If the sequence ID of an incoming packet is different from the previous
# command by a value greater than this, then the connection will be dropped.
# The motion mode must be reactivated to be used again.
#
# DEFAULT: 3
#max_sequence_diff_for_rt_msg: 3
Binary file added doc/img/RtFlow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/img/RtFlow.vsdx
Binary file not shown.
19 changes: 17 additions & 2 deletions doc/ros_api.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!--
SPDX-FileCopyrightText: 2023, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2023, Delft University of Technology
SPDX-FileCopyrightText: 2023 - 2025, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2023 - 2025, Delft University of Technology

SPDX-License-Identifier: CC-BY-SA-4.0
-->
Expand Down Expand Up @@ -133,6 +133,21 @@ Check the relevant fields of the `RobotStatus` messages to determine overall con

The `reset_error` service can be used to attempt to reset errors and alarms

### start_rt_mode

Type: [motoros2_interfaces/srv/StartRtMode](https://github.com/yaskawa-global/motoros2_interfaces/srv/StartRtMode.srv)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If/when we merge the related PR, this should be replaced by a permalink.


Attempts to enable servo drives, activate the [real-time UDP server](rt_control.md), and set the job-cycle mode to allow execution of `INIT_ROS`.
This allows the user to send incremental motion to the robot at the rate returned by the service (`period`).

See [R/T Motion Control](rt_control.md) for information on the protocol implementation.

Note: this service may fail if controller state prevents it from transitioning to R/T mode.
Inspect the `result_code` field to determine the cause.
Check the relevant fields of the `RobotStatus` messages to determine overall controller status.

The `reset_error` service can be used to attempt to reset errors and alarms

### stop_traj_mode

Type: [std_srvs/srv/Trigger](https://github.com/ros2/common_interfaces/blob/37ebe90cbfa91bcdaf69d6ed39c08859c4c3bcd4/std_srvs/srv/Trigger.srv)
Expand Down
219 changes: 219 additions & 0 deletions doc/rt_control.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
<!--
SPDX-FileCopyrightText: 2025, Yaskawa America, Inc.
SPDX-FileCopyrightText: 2025, Delft University of Technology

SPDX-License-Identifier: CC-BY-SA-4.0
-->

# R/T Motion Control

The real-time motion control server is intended to be used in a closed loop system.
It allows the user to command incremental offsets at the rate of the robot controller's interpolation clock.
Comment thread
ted-miller marked this conversation as resolved.
This control mode minimizes overhead as much as possible by routing the user commands directly to the MotoPlus motion API, mpExRcsIncrementMove.

## Activation

This control mode is activated using the [start_rt_mode](ros_api.md#start_rt_mode) service.
The user must specify the `control_mode` to indicate whether the increments will be joint offsets (radians) or cartesian TCP offsets (meters / quaternion).

If this service is successful, it will return a `result_code` of `Ready (1)`.
Otherwise, please examine the `result_code` and `message` files in the response for more information.

The service will also return a `period` in milliseconds.
This indicates the rate at which increment commands will be expected by the robot.
Comment thread
ted-miller marked this conversation as resolved.
The default period for a single manipulator is 4 milliseconds.
However, that value will increase as additional axes or manipulators are added to the system.

## Usage

### Command Flow

Once activated, a UDP server will listen on port `22000` (default).
The user then sends the first increment with a the `sequenceId` field set to `0`.
After that, the user must wait until the robot replies before sending the next increment.
Each subsequent command must increment the `sequenceId`. Additionally, each subsequent command must not be sent until the robot replies to the previous command.
Comment thread
ted-miller marked this conversation as resolved.
This will occur at the rate of the `period` from the [start_rt_mode](ros_api.md#start_rt_mode) service.

If a command is not received with 5 seconds (default), then the session times out and is dropped.
At that point, the server must be reactivated by calling `stop_traj_mode` and `start_rt_mode`.
A "keep-alive" can be used by sending a command with zero increments.

Additionally, if the client does not receive a reply packet within this amount of time, then it should be assumed that the session is dead.

<img src="img/RtFlow.png" alt="Command Flow" />

### Data format (command)

@gavanderhoorn gavanderhoorn Nov 24, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting here, as it's about both the command as well as the reply.

This is not an exhaustive list, but I would recommend to add:

  • a proper header structure, containing:
    • a version field: clients should implement version checks and refuse to work with servers of incompatible versions (and vice-versa). This should make it at least a little 'safer' to introduce breaking changes on the server side

    • a packet_type field: it's likely this interface will be extended in the future, which would then require some way of identifying which packets are being exchanged. Even if it absolutely won't be extended, this field could function as part of the 'magic' of the packet, making it harder to interpret 'random' data as valid motion commands / status data and to sync on incoming streams

    • a timestamp field: we could perhaps also rely on the determinism of the controller and assert that sequenceId * period == timestamp, but that would:

      • require more math on the client side, and
      • makes it harder to deal with overflow (which the server implementation already does, but still requires work on the client), and
      • makes the client responsible for matching the (calculated) stamp with its local clock (fi when correlating sensor data to robot motion). We already have a stamp on the MotoROS2 side, which when using NTP / micro-ROS synchronisation facilitates correlating MotoROS2 produced data with other sources. This would serve a similar goal

      we can still use the stamp as a sequence nr of course (in the end it's just a 'unique' numerical ID anyway), so clients should return the 'stamp' sent to them in the last state packet as part of their command packet.

Optional, but recommended:

  • add some reserved fields to allow for changes to packet definitions without breaking (de)serialisation of old traffic and/or breaking older implementations

For the state packet specifically:

  • a way to encode the full robot status (perhaps as a mirror of RobotStatus), perhaps as a bitmask. This would also include the FSU state (or perhaps FSU state deserves its own field, also a bitmask). The goal is for this protocol to be usable without ROS as well, so it can't delegate broadcasting robot/controller state to RobotStatus messages, as those might not be available in all usage scenarios (and even if they are available, they would not be (easily) synced with RT state traffic, nor would consuming them on the client be necessarily RT safe)
  • a field encoding the currently active command mode (see also below)

For the command packet:

  • a field indicating which control mode the client currently expects the server to have active: this serves both as a sanity check (client sending joint data while server expects Cartesian offsets), as well as an explicit indication as to in which way delta values are supposed to be interpreted (instead of implicitly relying on a piece of internal state being correctly maintained by MotoROS2).

For both (motion related packets) again:

  • it would be good to add a field stating whether absolute or relative mode is being used: right now this interface only supports offsets (ie: relative commands, or velocity), but it would not be too difficult to have the server also support an absolute command mode (ie: position). That would require changes to how offsets are interpreted & processed. By having clients specify which mode they are using (and at this point only relative mode would be supported, so anything else would result in errors), we prepare for when this changes and could do so without breaking anyone's client implementation.

My main motivation for these suggestions would be to make it possible to interpret data in command and state packets completely independently of the state of MotoROS2, another server and/or a client implementation. That makes both implementing MotoROS2, that other (hypothetical) server and clients easier to implement, as well as things like protocol dissectors and (de)serialisation libraries.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gavanderhoorn What do you think about this?

struct RtPacket
{
    UINT16 version;
    UINT16 packet_type;	//see enum xxxx

    UINT32 sequenceId;
	
    double delta[MAX_GROUPS][MAX_AXES]; //[8][8]
    int toolIndex[MAX_GROUPS]; //[8]
	
    char reserved[32];	//for future expansion
}
struct RtReply
{
    UINT32 sequenceEcho;
    
    double feedbackPositionJoints[MAX_GROUPS][MAX_JOINTS]; //[8][8]
    double feedbackPositionCartesian[MAX_GROUPS][MAX_JOINTS]; //[8][8]

    double previousCommandPositionJoints[MAX_GROUPS][MAX_AXES]; //[8][8]
    double previousCommandPositionCartesian[MAX_GROUPS][MAX_AXES]; //[8][8]

    RobotStatus status; //literal clone of the /robot_status structure

    bool fsuInterferenceDetected;
}

a timestamp field

Personally, I don't see why that's necessary. Since this is meant to be used in real time, why do I care about the stamp? All I really care about is the sequence identifier. I'm expecting that the user has done any time parameterization.

For the state packet specifically:
a way to encode the full robot status (perhaps as a mirror of RobotStatus), perhaps as a bitmask. This would also include the FSU state (or perhaps FSU state deserves its own field, also a bitmask)

I've already got the fsuInterferenceDetected field. I'm not sure what additional information we can include. I guess it's possible to indicate how much interference was detected...

For the command packet:
a field indicating which control mode the client currently expects the server to have active...
...
For both:
it would be good to add a field stating whether absolute or relative mode is being used

These could be part of the packet_type.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal is for this protocol to be usable without ROS as well, so it can't delegate broadcasting robot/controller state to RobotStatus messages, as those might not be available in all usage scenarios (and even if they are available, they would not be (easily) synced with RT state traffic,

Currently, anything that puts the robot into a non-ready state will immediately break the control loop and drop the connection. I think this is the safest approach.

So, I'm going to put the RobotStatus info on a separate socket and separate (lower priority) thread. If someone is interested in this data, they can listen on that port. If they're not, then the data will just go into the ether.


The command packet is a *packed* `RtPacket` structure.

```c
//##########################################################################
// !All data is little-endian!
//##########################################################################
struct RtPacket
Comment thread
ted-miller marked this conversation as resolved.
{
//The version of the command packet must match the value expected
//by MotoROS2.

int version;

//The packet type must match the control_mode which was specified
//in when invoking the start_rt_mode service.

PacketType packetType;

//Must increment sequentially with each new command packet.

UINT32 sequenceId;
Comment thread
ted-miller marked this conversation as resolved.

//The order of the joints must be in the order of [S L U R B T E 8].
//Please note that for seven axis robots, the 'E' joint is phyically
//mounted in the middle of the arm. But it must be sent at the end
//of the joint array. See JointIndices enum.
//
//For joint-space, this will be radians of each joint.
//
//For cartesian, this will be meters and quaternion of the TCP.
//The order of the joints must be in the order of [X Y Z Qx Qy Qz Qw Re].
//See CartesianIndices enum.

double delta[MAX_GROUPS][MP_GRP_AXES_NUM];

//Set tool that will be used by motion API (ie: passed by us to mpExRcsIncrementMove(..))
//NOTE: this will change the 'motion tool' ONLY for those increments which
// haven't yet been added to the increment queue. See also the ROS 2
// 'select_tool' service definition file in motoros2_interfaces.

int toolIndex[MAX_GROUPS]; //TOOL 0 - 63

//Reserved for future expansion

char reserved[64];
}
```

The `version` must match the version number expected by the server.
If it does not match the expected value, the packet will be rejected and the connection will be dropped.
The current version is `1`.

#### Joints

When the `control_mode` is `JOINT_ANGLES (1)`, the order of the joints in the `delta` array must be in the order of `S L U R B T E 8`.
Please note that for seven axis robots, the `E` joint is phyically mounted in the middle of the arm.
But it must be sent at the end of the joint array.

See `JointIndices` enum.

```c
enum JointIndices
{
Joint_S = 0, //radians
Joint_L,
Joint_U,
Joint_R,
Joint_B,
Joint_T,
Joint_E,
Joint_8,

MAX_JOINTS
}
```

#### Cartesian

When the `control_mode` is `CARTESIAN (2)`, the order of the joints in the `delta` array must be in order of `X Y Z Qx Qy Qz Qw Re`.

See `CartesianIndices` enum.

```c
enum CartesianIndices
{
TCP_X = 0, //meters
TCP_Y,
TCP_Z,

TCP_Qx, //quaternion
TCP_Qy,
TCP_Qz,
TCP_Qw,

TCP_Re, //radians

MAX_AXES
}
```

### Data format (reply)

The command packet is a *packed* `RtReply` structure.
This will echo the sequence ID, provide feedback position, and provide commanded position.

Additionally, there is a flag to indicate if the Functional Safety Unit (FSU) reduced the speed of the **previous** command cycle.
This indicates that the robot did not complete the full increment as commanded.

```c
//##########################################################################
// !All data is little-endian!
//##########################################################################
struct RtReply
{
UINT32 sequenceEcho;

//This is indicative of where the robot is physically located.
//Please note that this will trail behind the commanded position.
//The joint ordering will match that of the original command
//packet. See JointIndices and CartesianIndices enums.

double feedbackPositionJoints[MAX_GROUPS][MP_GRP_AXES_NUM];
double feedbackPositionCartesian[MAX_GROUPS][MP_GRP_AXES_NUM];

//The command position is the target destination you are instructing
//the robot to reach. It's the calculated endpoint based on the sum
//of all position increments received from the user.
//
//This is used to track if the robot's speed is being limited
//by the Functional Safety Unit (FSU). It can also be used to
//monitor the latency between command and feedback.

double previousCommandPositionJoints[MAX_GROUPS][MP_GRP_AXES_NUM];
double previousCommandPositionCartesian[MAX_GROUPS][MP_GRP_AXES_NUM];

//If the FSU speed limit is enabled, it can truncate the commanded
//delta increments. This flag is an indicator that the *previous*
//command cycle was truncated. It does NOT indicate that this most
//recent command packet was truncated.

bool fsuInterferenceDetected;
}
```

## Deactivation

Other motion modes may not be used at the same time as the real-time motion control server.
Comment thread
ted-miller marked this conversation as resolved.
The service to start those modes will fail when invoked.
By calling `stop_traj_mode`, the R/T server will be disposed.
At that time, another motion mode may be used.

## R/T Status Monitoring

When the R/T Motion Control is activated, MotoROS2 will begin to send the `RobotState` structure on port UDP `22001` (default).
This is essentially a clone of the `/robot_status topic`.
But decoupled from the `industrial_msgs/RobotStatus` type.

```c
struct RobotState
{
int version;

BOOL drives_powered;
BOOL e_stopped;
BOOL in_motion;
BOOL play_mode;
BOOL motion_possible;
BOOL error;
int error_code;
}
```

This will be sent every `rt_status_sleep_period` milliseconds.
Loading