This repo is a module that implements the rdk:component:arm API resource to allow control over Yaskawa Robots arms. Currently the following models are supported:
- GP12, as
viam:yaskawa-robots:gp12 - GP180-120, as
viam:yaskawa-robots:gp180-120 - GP35L, as
viam:yaskawa-robots:gp35l
This model can be used to control a yaskawa robots arm from a machine running a viam-server. We recommend that the machine running the viam-server is using a wired ethernet connection for the best performance of this module. The following attribute template can be used to configure this model:
{
"host": <arm ip address string>,
"speed_rad_per_sec": <float or array>,
"acceleration_rad_per_sec2": <float or array>
}The following attributes are available for viam:yaskawa-robots arms:
| Name | Type | Inclusion | Description |
|---|---|---|---|
host |
string | Required | The IP address of the robot arm on your network. |
speed_rad_per_sec |
float or array | Required | Set the maximum desired speed of the arm joints in radians per second. Can be a single value (applied to all joints) or an array for per-joint limits. |
acceleration_rad_per_sec2 |
float or array | Required | Set the maximum desired acceleration of the arm joints in radians per second squared. Can be a single value (applied to all joints) or an array for per-joint limits. |
reject_move_request_threshold_rad |
float | Optional | Rejects move requests when the difference between the current position and first waypoint is above threshold. Range: 0 - 2π radians |
trajectory_sampling_freq_hz |
float | Optional | Sampling frequency for trajectory generation in Hz. Higher values produce smoother trajectories but require more computation. Default 3 Hz (range: 1 - 250) |
waypoint_deduplication_tolerance_deg |
float | Optional | Tolerance in degrees for deduplicating consecutive waypoints. Waypoints within this tolerance of each other are considered identical. Default ~0.057 degrees (1e-3 radians) (range: 0 - 10) |
path_tolerance_rad |
float | Optional | Path tolerance for trajectory planning in radians. Default 0.1 rad (range: 0.0 - 3.0) |
segmentation_threshold_rad |
float | Optional | Threshold for detecting direction reversals in waypoint paths. Lower values detect only sharp reversals; higher values are more sensitive. Default 0.005 rad (range: > 0, <= 0.1) |
collinearization_ratio |
float | Optional | Waypoint collinearization parameter for trajectory smoothing. (range: 0.0 - 2.0) |
enable_new_trajectory_planner |
bool | Optional | Enables the new trajectory planning algorithm. Default true |
enable_auto_error_recovery |
bool | Optional | When true, the driver automatically calls reset_errors to clear software errors so the arm can recover without operator intervention. Set to false if you want errors to remain visible on the pendant for inspection before they're cleared. (Move requests will still trigger error recovery as part of waking the arm — this only gates the passive background path.) Default true |
telemetry_output_path |
string | Optional | Path for writing telemetry data files. Default: VIAM_MODULE_DATA environment variable |
group_index |
int | Optional | Control group index on the Yaskawa controller that this arm represents (see below). Default 0 |
firmware_path |
string | Optional | Dev only. Absolute path (on the machine running the module) to a MotoPlus firmware .out to flash, overriding the version-pinned firmware bundled in the tarball. Default: the bundled firmware, if present. See Firmware Flashing. |
firmware_dest_name |
string | Optional | Dev only. Filename to store the application under on the controller. Default: the basename of the firmware being flashed (e.g. viammoto.out). |
flash_on_start |
bool | Optional | On every module start/reconfigure, flash the firmware only if the controller's running build differs from the bundled/configured one, then reboot. A flash failure is logged but does not stop the module from starting. Set false to disable (e.g. when testing a dev build on the controller manually). See Firmware Flashing. Default true |
A Yaskawa controller can manage multiple robot arms simultaneously. Each arm is assigned to a control group identified by a sequential index (0, 1, 2, ...). The group_index attribute tells the driver which control group this arm component controls.
When multiple arm components point to the same controller host, they share a single TCP connection and can move independently or concurrently. Each arm must specify a different group_index.
The available groups and their axis counts are discovered automatically via the capabilities handshake at connection time. You can find the group layout for your controller in the module logs at startup.
All configuration attributes (speed, acceleration, trajectory planner settings, telemetry path, etc.) are per-arm. Each arm component has its own config; only the underlying controller connection is shared.
{
"host": "10.1.10.84",
"speed_rad_per_sec": 2.09,
"acceleration_rad_per_sec2": 0.14
}Configure two arm components pointing to the same controller host with different group_index values:
Arm 1 (R1):
{
"host": "10.1.10.84",
"speed_rad_per_sec": 2.09,
"acceleration_rad_per_sec2": 0.14,
"group_index": 0
}Arm 2 (R2):
{
"host": "10.1.10.84",
"speed_rad_per_sec": 1.57,
"acceleration_rad_per_sec2": 0.10,
"group_index": 1
}{
"host": "10.1.10.84",
"speed_rad_per_sec": [2.09, 2.09, 2.09, 2.09, 2.09, 2.09],
"acceleration_rad_per_sec2": [0.14, 0.14, 0.14, 0.14, 0.14, 0.14]
}{
"host": "10.1.10.84",
"speed_rad_per_sec": 2.09,
"acceleration_rad_per_sec2": 0.14,
"trajectory_sampling_freq_hz": 10,
"path_tolerance_rad": 0.05,
"enable_new_trajectory_planner": true
}{
"host": "10.1.10.84",
"speed_rad_per_sec": 2.09,
"acceleration_rad_per_sec2": 0.14,
"telemetry_output_path": "/var/log/arm_telemetry"
}First ensure that your machine is displaying as Live on the Viam App. Then you can interact with your Yaskawa Robots arm in a couple ways:
- To simply view data from and manipulate your arm, use the CONTROL tab of the Viam App. For more information, see Control Machines.
- More advanced control of the arm can be achieved by using one of Viam's client SDK libraries
This module can flash the MotoPlus controller firmware (the .out application) over the network, replacing the Windows-only OnlineDownload.exe.
Production: the module bundles a firmware .out version-pinned in its tarball — a module release packages whatever version is tagged in the Makefile, coupling the controller firmware to the driver release. With flash_on_start (default true), the module flashes that bundled firmware on start only if the controller's running build differs, keeping the controller in sync with the driver automatically. No firmware config is needed.
Development only: to try a different .out (e.g. a local controller build) without a module release, point firmware_path at it on the machine running the module (not your laptop) — this overrides the bundled firmware — and/or trigger an on-demand flash with the flash_firmware DoCommand. These knobs are meant for dev work; deployments should rely on the bundled, version-pinned firmware. If firmware_path is unset and no bundled firmware is present (e.g. a local build that skipped make get-firmware), flashing is skipped with a warning.
- Servo power OFF and any HOLD released on the pendant. If servos are on, flashing fails with
rc=0x2010. - First time only: initialize the MotoPlus Temporary File in Maintenance mode, and set parameter
S4C1084 = 1. - Controller firmware YAS4.12.00-00 or newer (YRC1000).
{ "flash_firmware": {} }Dev only — deployments rely on the version-gated flash_on_start; this is for on-demand flashing during development. An explicit flash_firmware is a deliberate operator action, so it always flashes (no version gate) and always reboots — use it to force a (re)install regardless of the controller's current build.
The command deletes the existing app, uploads the firmware (firmware_path if set, otherwise the bundled firmware), and tells the controller to reboot. It returns once the upload completes (a few seconds); the controller then reboots and the module reconnects in the background (the arm is unavailable until it does). The response is a struct:
| Field | Meaning |
|---|---|
ok |
true if the download succeeded |
expected_id / running_id |
The firmware's build id vs the controller's reported build id |
download_detail / delete_detail |
Raw controller responses |
error |
Populated on failure (e.g. the servos-off instruction for rc=0x2010) |
note |
Rebooting/reconnecting status |
Read-only version check — no flashing:
{ "firmware_status": {} }Returns { "expected_id": "<firmware .version>", "running_id": "<controller build id>", "in_sync": true|false }.
flash_on_start is true by default. It runs in the background (it does not block module startup or reconfigure) and waits for the controller to connect before comparing versions, then compares the controller's reported build id (MSG_CAPABILITIES) against the bundled/configured firmware's .version sidecar and flashes only if they differ (then reboots). If the running build can't be determined — pre-v7 firmware, an unstamped ("unknown") build, or a missing .version — it flashes to be safe. A controller too old to speak the module's protocol can't complete the handshake, but that protocol mismatch is detected and treated as out-of-date, so it is flashed (this is the main way a stale controller self-heals). Only a controller that is genuinely unreachable is skipped. A failure is logged and does not prevent the module from starting. Set "flash_on_start": false to disable (e.g. when manually testing a dev build on the controller).
Only the arm on the primary group (group_index 0, the default) runs this check, so multiple arms sharing one controller don't flash concurrently.
Since the bundled firmware is the default, the default-on flash needs no extra config; an explicit firmware_path overrides which .out is used:
{
"host": "10.1.10.84",
"speed_rad_per_sec": 2.09,
"acceleration_rad_per_sec2": 0.14,
"flash_on_start": false
}Firmware is per-controller, but these attributes are per-arm. flash_on_start runs only on the arm at group_index 0 (see Control Groups), so it's safe to leave it at its default across several arms sharing a host — only the primary group's arm flashes. If you set a dev-only firmware_path, set it on that primary-group arm (the others are ignored for flashing). A flash reboots the whole controller, so every arm on that host disconnects and reconnects during it.
For development purposes, you can either build directly on your development machine, or within a docker container, or with conan. The advantage of the docker container is that it comes with the required runtime libraries preinstalled. However, the module.tar.gz that is produced will only run on an Ubuntu Noble (24.04) machine which already has the necessary runtime libraries installed, and it is unlikely that this matches your development machine. The advantage to building directly on your development machine is that the module.tar.gz that is built will work on that machine. However, you are required to install the necessary support libraries first. The advantage of conan is that it will build you a self-contained binary and will handle installing all of the dependencies. The resulting module.tar.gz should run on any system offering a system ABI compatible with the machine on which you built it (for instance, build on Debian 12 Bookworm, and it should run on Debian 13 Trixie).
Clone this repository to your machine and from the newly created folder start a new Docker container using the following commands:
git submodule update --init
docker pull ghcr.io/viam-modules/yaskawa-robots:amd64
docker run --net=host --volume .:/src -it ghcr.io/viam-modules/yaskawa-robots:amd64
If you are working on an ARM based machine, use the arm64 images:
docker pull ghcr.io/viam-modules/yaskawa-robots:arm64
docker run --net=host --volume .:/src -it ghcr.io/viam-modules/yaskawa-robots:arm64
Once inside the docker container build the binary using:
cd /src && make module.tar.gz
Install the prerequisite support libraries. These include, but are not limited to:
- Abseil
- Boost
- Eigen
- Protobuf
- Viam C++ SDK
- Xtensor
- gRPC
First, if you don't already have it, you will need to install conan. On macOS this is as easy as brew install conan. On systems where the system package manager does not provide it, you will most likely need to create a virtualenv and then run python -m pip install conan. Or use your python project/package management system of choice.
Next, you need to have conan build and install the prerequisite package by running the ./bin/setup.sh script. This will take a while since it needs to compile Boost, gRPC, Eigen, and the Viam C++ SDK from source.
Finally, you can run the bin/build.sh script, which will build the Yaskawa Robots driver. This should be relatively quick, and you can run this repeatedly to re-run the build of the driver and produce module.tar.gz.
Use one of the above techniques to produce module.tar.gz. Then, follow the instructions to add a local module to add the local instance of the yaskawa-robots module to your machine.
Note
Simply running make install inside the docker image is a faster way to build but creates an executable that must be run from within the Docker container, per the above notes. If you are interested in making and testing many quick changes to this module it will likely be faster to only build this way and then run viam-server from within the Docker container, pointing to a config file that has a local instance of this module with an executable path of build/install/bin/yaskawa-robots. To download and run viam-server this way run:
wget https://storage.googleapis.com/packages.viam.com/apps/viam-server/viam-server-stable-x86_64
chmod +x ./viam-server-stable-x86_64
./viam-server-stable-x86_64 -config {PATH_TO_VIAM_CONFIG}
Our kinematics representation of the arm can be found at src/kinematics. Right now we only support the gp12 model.
We would like to call out that link_4_r is modeled as a smaller geometry than necessary and might lead to collisions when there should be none. If a user runs into this please raise immediately and we will issue an appropriate fix.
The motivation for shrinking the geometry is described next. Suppose a user has attached an end effector attachment. If it is long or wide enough and joint_4_r has a rotation of -90 degrees this will result in a collision between the attachment and link_4_r.
Below is an image to show exactly how undermodeled the geometry is at this point in time.

The gp180-120 model has a related, two-part adjustment for the same kind of false-collision problem. The y dimension of link_2_l was expanded by ~240mm beyond the raw mesh AABB so it covers the motor housing protruding from link_3_u, and link_3_u's z dimension was then shrunk by ~300mm (centered higher) since the motor that geometry would have covered now lives in link_2_l's box. The combined coverage still envelops the physical robot for external collision checks while letting the two links no longer collide with each other at extreme joint angles.
Note
The gp35l kinematics generated from the URDF use raw mesh AABBs and have not yet been reviewed for false self-collisions. Similar adjustments may be needed before the model is ready for users.