Add documentation for KUKA Sunrise features and programs

- Created a new document for the Station interface, detailing its menu structure, process data, safety functions, frames, and smartPAD function buttons.
- Added a document for RobotPowerControl, explaining its purpose for safely shutting down or restarting the KUKA Sunrise Cabinet controller.
- Introduced ServerFriRos2 documentation, outlining its role in establishing an FRI connection between the KUKA LBR iiwa and a ROS 2 computer.
- Documented the TeachKuka application, which allows manual teaching of the KUKA LBR iiwa, including position capturing and trajectory recording.
- Added an overview of Sunrise Workbench, including installation instructions for Windows and Linux.
- Created a section on installing a Windows compatibility tool (PortProton) on Linux.
- Documented the installation process for SunriseWorkbench on Linux using PortProton.
- Added installation instructions for SunriseWorkbench on Windows.
- Created troubleshooting documentation for configuration errors and SSL errors during installation.
- Implemented a hook to generate the shared PDF only during the default-language build.
This commit is contained in:
Даниил Грабарь
2026-08-13 18:01:59 +03:00
parent 08ebd40671
commit 79d88db930
42 changed files with 2973 additions and 17 deletions
@@ -0,0 +1,169 @@
# cobot CLI commands
`cobot` is the single entry point for managing the entire project. Use it for operations involving the robot, simulator, Docker containers, and documentation.
## Help
```bash
cobot -h
```
The help output is divided into four command groups:
- **Setup commands** — system configuration;
- **Run commands** — starting the project;
- **Build commands** — building ROS 2;
- **Management commands** — package management.
Some commands have their own subcommands. For example:
```bash
cobot doc-setup rebuild # rebuild subcommand of doc-setup
cobot doc-setup --help # help for a command's subcommands
```
---
## Setup commands
Commands for initial and repeated system setup.
### `cobot setup`
First-run setup wizard. It guides you through three steps:
1. Configure the documentation server.
2. Configure robot parameters in `cobot-setting.yaml`: IP address, FRI port, and tool.
3. Select a build environment: native ROS 2 Jazzy or a Docker image.
```bash
cobot setup
```
Use this command for the first installation instead of running each setup command manually.
---
### `cobot local-setup`
Installs ROS 2 Jazzy locally without Docker: downloads dependencies with `rosdep` and builds the workspace with `colcon`.
```bash
cobot local-setup
```
!!! note
After the command finishes, run `source ~/.bashrc` or open a new terminal.
---
### `cobot docker-setup`
Builds or downloads the Docker images used to run the project in isolation. Two options are available:
- **Build from the Dockerfile** — slower, but produces an up-to-date image;
- **Download a prebuilt image** — faster, using a published image.
```bash
cobot docker-setup
```
---
### `cobot doc-setup`
Deploys a local MkDocs documentation server containing a full copy of the [online documentation](https://daniel-robotics.gitverse.site/lightweight-cobot/).
```bash
cobot doc-setup # start/build the documentation
cobot doc-setup rebuild # rebuild the documentation image
```
After startup, the documentation is available at `http://localhost:8000`.
---
### `cobot robot-setup`
Interactive wizard for configuring `cobot-setting.yaml`. It asks for the robot IP address, FRI port, active tool, and other parameters.
```bash
cobot robot-setup
```
!!! tip
Use this command to change the configuration. It validates the entered values and prevents YAML syntax errors. See [System configuration](configuration.md) for parameter details.
---
## Run commands
### `cobot run`
Starts the full stack: hardware interface, MoveIt 2, RViz, and optional components such as Foxglove and the REST API. At startup, it asks you to select:
- **Docker or local execution**;
- **Webots simulation or the physical robot**.
```bash
cobot run # select the mode interactively
cobot run --simulate # force simulation mode
```
---
## Build commands
### `cobot rebuild`
Rebuilds the ROS 2 workspace with `colcon`. Use it after changing package source code.
```bash
cobot rebuild
```
!!! note
This command is available only for a local installation, not Docker. It is equivalent to `colcon build --mixin release`.
---
### `cobot clean`
Removes generated build directories. It prompts you to select which directories to remove:
- `build/` — compilation artifacts;
- `install/` — installed package files;
- `log/` — build logs.
```bash
cobot clean
```
---
## Management commands
### `cobot update`
Downloads the latest project version from GitVerse and reinstalls the `cobot` CLI.
```bash
cobot update
```
---
### `cobot delete`
Removes project components from the system. It lets you remove only the project, the Docker images and containers, or ROS 2 as well.
```bash
cobot delete
```
!!! danger
This operation is irreversible. Removed files and Docker images must be installed again.
---
**Robot control:** [Control via the REST API](control/rest-api.md)
@@ -0,0 +1,15 @@
# System architecture
!!! info "Work in progress"
A detailed description of the system architecture is being prepared.
LWC is built as a set of interconnected ROS 2 packages. Key components:
- **iiwa_bringup** — launch files and the entry point for starting the system
- **iiwa_controller** — hardware interface connecting to the KUKA controller over FRI
- **iiwa_planning** — MoveIt 2-based motion planning
- **iiwa_web** — REST API and MCP server for external control
- **iiwa_description** — URDF robot description and Webots worlds
- **iiwa_config** — configuration files for MoveIt, controllers, and cameras
- **iiwa_utils** — helper Python utilities and configuration loading
- **iiwa_msgs** — custom ROS 2 message types (action and srv)
@@ -0,0 +1,23 @@
# FRI protocol
!!! info "Work in progress"
A detailed description of the FRI protocol is being prepared.
**FRI (Fast Robot Interface)** is a UDP protocol for low-level real-time control of a KUKA robot. It runs over Ethernet and provides a deterministic data exchange cycle between an external PC and the KUKA controller.
## Main characteristics
- **Transport:** UDP (no delivery guarantee, which is important for real-time operation)
- **Cycle period:** 5 ms (200 Hz) or 10 ms (100 Hz), configured in `cobot-setting.yaml``robot.fri_cycle_ms`
- **Control modes:** position, torque, and impedance
## Network requirements
!!! warning "Important: a 5 ms cycle requires KONI"
A **5 ms (200 Hz)** cycle requires the **KONI** port (KUKA Optional Network Interface).
The KLI port supports only a 10 ms cycle. Set `fri_cycle_ms: 10` when using KLI.
| Port | Minimum cycle | Purpose |
|---|---|---|
| **KONI** | 5 ms | High-frequency control, recommended for FRI |
| **KLI** | 10 ms | Standard control and programming |
@@ -0,0 +1,23 @@
# Motion planning
!!! info "Work in progress"
A detailed description of motion planning is being prepared.
LWC uses **MoveIt 2**, the standard motion-planning framework for ROS 2.
## Key concepts
- **Planning group** (`iiwa_arm`) — the set of joints for which a plan is generated. Defined in SRDF.
- **Planner** — the trajectory-generation algorithm. Available planners:
- `ompl` — general-purpose probabilistic planner (default)
- `pilz_industrial_motion_planner` — deterministic PTP, LIN, and CIRC trajectories
- **TCP (Tool Center Point)** — the tool point for which the target pose is specified. Set in `cobot-setting.yaml``planning.pose_link`.
- **Reference frame** — the coordinate system for targets. Default: `base_link`.
## `cobot-setting.yaml` settings
| Parameter | Description |
|---|---|
| `planning.default_planner` | Default planner: `ompl` or `pilz_industrial_motion_planner` |
| `planning.planning_attempts` | Number of attempts after a planning failure |
| `planning.pose_link` | TCP link for Cartesian targets |
@@ -0,0 +1,18 @@
# Simulation (Webots)
!!! info "Work in progress"
A detailed simulator guide is being prepared.
**Webots** is an open-source robot simulator. LWC uses it as a digital twin of the KUKA LBR IIWA 7, allowing control algorithms to be developed and debugged without a physical robot.
## Key features
- The simulator uses the same ROS 2 topics and interfaces as the real robot.
- The simulation world is set in `cobot-setting.yaml``digital_twin.webots.world`.
- Start it with `cobot run --simulate`.
## Differences from the real robot
- There are no real safety constraints, so motion can be faster.
- Physics is approximate, including inertia, friction, and elasticity.
- FRI is not used; communication goes through the Webots ROS 2 driver.
@@ -0,0 +1,176 @@
# System configuration
## Main configuration file
All system parameters are stored in a single file: **`cobot-setting.yaml`** in the project root. It is the single source of truth for the robot IP address, ports, configuration paths, planner settings, and web server settings.
!!! info "No manual configuration is needed before installation"
When you run `cobot setup`, the wizard offers to configure this file automatically in **step 2**. Return to this section when you want to change parameters after the initial installation.
!!! danger "Do not edit the file manually"
Use only `cobot robot-setup`. The interactive wizard validates values and prevents syntax errors. Editing the YAML manually may cause parsing errors and prevent the system from starting.
```bash
cobot robot-setup
```
---
## `robot` section — robot parameters
Controls the connection to the physical KUKA controller through FRI.
```yaml
robot:
name: "iiwa7"
ip: "192.170.10.2"
port: 30200
fri_cycle_ms: 10
joint_position_tau: 0.04
joint_velocity_tau: 0.01
active_controller: "jtc"
description: pkg://iiwa_description/urdf/iiwa7.urdf.xacro
```
| Parameter | Description | Recommendation |
|---|---|---|
| `name` | Robot model | Do not change: `iiwa7` |
| `ip` | KUKA controller IP address | **Change** to the actual controller address |
| `port` | FRI UDP port | Default: `30200`; change only if the port conflicts |
| `fri_cycle_ms` | FRI cycle: `5` ms = 200 Hz, `10` ms = 100 Hz | Use `10` for stable operation or `5` for high-precision tasks |
| `joint_position_tau` | Position EMA filter [s], smoothing commands before transmission | Decrease for a faster response; increase if vibration occurs |
| `joint_velocity_tau` | Velocity EMA filter [s], removing finite-difference spikes | Tune in the same way as `joint_position_tau` |
| `active_controller` | Control mode: `jtc` (MoveIt / JointTrajectory) or `forward` (direct control) | Use `jtc` for most tasks |
| `description` | Path to the robot URDF | Do not change |
---
## `digital_twin` section — simulator
Configures the Webots environment and RViz visualization.
```yaml
digital_twin:
webots:
world: pkg://iiwa_description/worlds/iiwa.wbt
transform: "-0.25 0 0.79"
rotation: "0 0 1 0"
controller_timer: "50"
cameras:
- pkg://iiwa_config/config/cameras/d455_top.yaml
rviz:
config: pkg://iiwa_config/config/rviz/rviz_moveit.rviz
```
| Parameter | Description |
|---|---|
| `webots.world` | Path to the simulator `.wbt` world |
| `webots.transform` | Robot base offset in the world `[x y z]`, in meters |
| `webots.rotation` | Base orientation `[x y z angle]`, in radians |
| `webots.cameras` | List of YAML configurations for connected cameras |
| `rviz.config` | Path to the RViz configuration |
---
## `tool` section — active tool
Specifies which gripper or tool is attached to the robot.
```yaml
tool:
active: "patron"
```
| Value | Description |
|---|---|
| `none` | No tool |
| `patron` | Patron chuck/gripper |
Available tools are defined in `src/iiwa_config/config/tools.yaml`. To add a tool, describe it there and then set its name in `tool.active`.
---
## `planning` section — motion planning
Configures MoveIt 2 and the trajectory planner.
```yaml
planning:
pose_link: "tcp"
planning_group: "iiwa_arm"
default_frame: "base_link"
default_planner: "ompl"
planning_attempts: 3
```
| Parameter | Description | Recommendation |
|---|---|---|
| `pose_link` | TCP link used for Cartesian targets | Must match the URDF frame; do not change without updating the URDF |
| `planning_group` | Planning group from the SRDF | Do not change: `iiwa_arm` |
| `default_frame` | Default reference frame | Do not change: `base_link` |
| `default_planner` | Planner: `ompl` or `pilz_industrial_motion_planner` | `ompl` is general purpose; `pilz` produces predictable trajectories |
| `planning_attempts` | Number of planning attempts after failure | Increase for difficult trajectories |
---
## `web` section — REST API and MCP server
Configures the FastAPI server used to control the robot over HTTP and MCP for AI-agent integration.
```yaml
web:
enabled: true
host: "0.0.0.0"
port: 8007
endpoints: pkg://iiwa_config/config/api_endpoints.yaml
joint_limits: pkg://iiwa_config/config/moveit/joint_limits.yaml
```
| Parameter | Description |
|---|---|
| `enabled` | Enable (`true`) or disable (`false`) the web server |
| `host` | Listening address: `0.0.0.0` for all interfaces or `127.0.0.1` for local access only |
| `port` | HTTP API port; default: `8007` |
| `endpoints` | Path to the REST endpoint description |
| `joint_limits` | Path to joint limits used for command validation |
After startup, the REST API is available at `http://<host>:8007`, and MCP is available at `/mcp`.
---
## `foxglove` section — Foxglove Studio monitoring
[Foxglove Studio](https://foxglove.dev/) visualizes and monitors ROS 2 topics in real time.
```yaml
foxglove:
enabled: true
port: 8765
debug: false
address: 0.0.0.0
```
| Parameter | Description |
|---|---|
| `enabled` | Enable or disable Foxglove Bridge |
| `port` | WebSocket port used by Foxglove Studio; default: `8765` |
| `debug` | Detailed logging for the bridge process |
| `address` | WebSocket listening address |
The remaining parameters (`tls`, `topic_whitelist`, `min_qos_depth`, and others) are intended for advanced configuration and normally do not need to be changed.
---
## What to change and what to keep
| | Parameter | Action |
|---|---|---|
| ✅ | `robot.ip` | **Must be changed** to the controller IP address |
| ✅ | `robot.fri_cycle_ms` | Select `10` (standard) or `5` (high frequency) |
| ✅ | `tool.active` | Set the active tool |
| ✅ | `web.enabled` | Set to `false` if the web interface is not needed |
| ⚠️ | `robot.active_controller` | Change only when intentionally switching the control mode |
| ⚠️ | `planning.*` | Change only when another planner or other parameters are required |
| ❌ | `robot.description` | Do not change; this is the URDF path |
| ❌ | `controller.moveit.*` | Do not change; these are package-internal MoveIt configuration paths |
| ❌ | `digital_twin.webots.world` | Do not change unless you understand the Webots world structure |
@@ -0,0 +1,10 @@
# Control via Foxglove Studio
!!! info "Work in progress"
Detailed control and monitoring instructions for Foxglove Studio are being prepared.
[Foxglove Studio](https://foxglove.dev/home) is a tool for visualizing and monitoring ROS 2 data in real time. It connects to the running stack through a WebSocket bridge (port `8765` by default, configured in the `foxglove` section of `cobot-setting.yaml`).
## Download Foxglove Studio
Visit the [official Foxglove website](https://foxglove.dev/home) and download the application for your operating system.
@@ -0,0 +1,651 @@
# Control via the REST API
The REST API reads robot state and sends commands over HTTP. It is intended for application scripts, integrations with other systems, and quick checks through Swagger UI.
Motion requests are synchronous: the response is returned after planning and execution finish or an internal timeout occurs. The API has no command queue. Wait for the current request to finish before sending another one.
!!! warning "Safety"
The REST API does not replace the standard KUKA safety system or emergency stop. Before the first run on a physical robot, check the Sunrise program, safety zones, tool, and workspace. Begin using the API in simulation.
## Starting and accessing the server
The web server starts with the robot stack when the **web** section is enabled in the root **cobot-setting.yaml** file:
~~~ yaml
web:
enabled: true
host: 0.0.0.0
port: 8007
endpoints: pkg://iiwa_config/config/api_endpoints.yaml
joint_limits: pkg://iiwa_config/config/moveit/joint_limits.yaml
~~~
After starting the stack with **cobot run**, the server is available at **http://server-address:8007**. Swagger UI shows the actual request schema and lets you run individual tests:
- locally: [http://localhost:8007/docs](http://localhost:8007/docs);
- from another computer: `http://server-address:8007/docs`;
- OpenAPI JSON schema: `http://server-address:8007/openapi.json`.
There is no separate health-check endpoint. If Swagger UI opens, the HTTP server is running. Readiness of ROS components is checked when a specific endpoint is called.
By default, the server listens on all network interfaces and does not use authentication. Do not expose port 8007 to an untrusted network. For local access, set **host: 127.0.0.1**. For remote access, restrict the network with firewall rules or a VPN.
## Preparing the examples
The tabs on this page are synchronized. Select a language once and the same tab will be selected in subsequent examples.
=== "curl"
~~~ bash
HOST=http://localhost:8007
~~~
=== "Python"
~~~ python
import httpx
HOST = "http://localhost:8007"
T_READ = 10
T_MOVE = 60
~~~
=== "MATLAB"
~~~ matlab
HOST = 'http://localhost:8007';
T_READ = 10;
T_MOVE = 60;
readOpts = weboptions('Timeout', T_READ);
moveOpts = weboptions('MediaType', 'application/json', 'Timeout', T_MOVE);
~~~
MATLAB uses the built-in `webwrite` function for JSON requests. Uploading CSV and JSON files requires `matlab.net.http`, available in modern desktop versions of MATLAB.
## API overview
| Method | Endpoint | Purpose |
|---|---|---|
| GET | /robot/joint_states | Current joint state |
| GET | /robot/pose | TCP pose relative to base_link |
| GET | /robot/positions | Named positions from the SRDF |
| POST | /robot/move/named | Move to a named position |
| POST | /robot/move/pose | Cartesian TCP motion |
| POST | /robot/move/joints | Move the seven joints to specified angles |
| POST | /trajectory/send | Publish a trajectory from JSON |
| POST | /trajectory/send_csv | Upload and publish a trajectory from CSV |
| GET | /trajectory/logs | Latest trajectory module log entries |
| POST | /sequences/start | Start a sequence from a JSON file |
| GET | /sequences/status | Running sequence status |
| GET | /sequences/logs | Sequence process output |
| POST | /stop | Stop API commands and the planner |
## Reading robot state
### Joint state
GET **/robot/joint_states** returns the latest message from the ROS **/joint_states** topic. The **position**, **velocity**, and **effort** fields use the same order as the **name** array. Angles in **position** are in radians.
=== "curl"
~~~ bash
curl -sS --max-time 10 $HOST/robot/joint_states | python3 -m json.tool
~~~
=== "Python"
~~~ python
response = httpx.get(f"{HOST}/robot/joint_states", timeout=T_READ)
response.raise_for_status()
state = response.json()
print(dict(zip(state["name"], state["position"])))
~~~
=== "MATLAB"
~~~ matlab
jointState = webread([HOST '/robot/joint_states'], readOpts);
disp(jointState.position)
~~~
Typical response:
~~~ json
{
"name": ["joint1", "joint2", "joint3", "joint4", "joint5", "joint6", "joint7"],
"position": [0.0, 0.0, 0.0, -1.57, 0.0, 1.57, 0.0],
"velocity": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
"effort": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
}
~~~
If no controller messages arrive within two seconds, the API returns 503. This usually means that the controller or robot has not started yet.
### TCP pose
GET **/robot/pose** computes forward kinematics with the MoveIt **/compute_fk** service. Position is specified in meters. Orientation is returned as both a quaternion and Euler angles:
- **euler_rad** — radians;
- **euler_deg** — degrees;
- **A, B, C** follow the KUKA ABC convention: rotation around Z, then Y, then X.
=== "curl"
~~~ bash
curl -sS --max-time 10 $HOST/robot/pose | python3 -m json.tool
~~~
=== "Python"
~~~ python
response = httpx.get(f"{HOST}/robot/pose", timeout=T_READ)
response.raise_for_status()
pose = response.json()
print(pose["position"])
~~~
=== "MATLAB"
~~~ matlab
pose = webread([HOST '/robot/pose'], readOpts);
fprintf('TCP: x=%.3f, y=%.3f, z=%.3f m\n', ...
pose.position.x, pose.position.y, pose.position.z);
fprintf('ABC: A=%.1f, B=%.1f, C=%.1f deg\n', ...
pose.orientation.euler_deg.a, ...
pose.orientation.euler_deg.b, ...
pose.orientation.euler_deg.c);
~~~
This endpoint depends on both **/joint_states** and MoveIt. If either is unavailable, it returns 503.
### Named positions
GET **/robot/positions** reads `group_state` positions from the SRDF. The list is not hardcoded in the API; it reflects the current robot configuration. The standard configuration includes **home**, **work**, and **transport**.
=== "curl"
~~~ bash
curl -sS $HOST/robot/positions | python3 -m json.tool
~~~
=== "Python"
~~~ python
response = httpx.get(f"{HOST}/robot/positions", timeout=T_READ)
response.raise_for_status()
for position in response.json():
print(position["name"], "—", position["description"])
~~~
=== "MATLAB"
~~~ matlab
namedPositions = webread([HOST '/robot/positions'], readOpts);
for i = 1:numel(namedPositions)
fprintf('%s — %s\n', namedPositions(i).name, ...
namedPositions(i).description);
end
~~~
Call this endpoint before **/robot/move/named** to obtain the exact name, planning group, and target joint angles.
## Motion commands
All three commands below use MoveIt. A response has this form:
~~~ json
{"success": true, "message": "Motion completed successfully"}
~~~
**success: false** means that the planner could not plan or execute the trajectory. The HTTP status may still be 200, so application code must check both the HTTP status and the **success** field.
### Moving to a named position
POST **/robot/move/named** moves the manipulator to a position from the SRDF.
| Field | Required | Value |
|---|---:|---|
| name | yes | Position name from /robot/positions |
| speed | no | Speed scale from 0.01 to 1.0; default: 0.1 |
| accel_scale | no | Acceleration scale from 0 to 1.0; 0 uses speed |
=== "curl"
~~~ bash
curl -sS --max-time 60 -X POST $HOST/robot/move/named \
-H "Content-Type: application/json" \
-d '{"name": "home", "speed": 0.1, "accel_scale": 0.0}'
~~~
=== "Python"
~~~ python
response = httpx.post(
f"{HOST}/robot/move/named",
json={"name": "home", "speed": 0.1, "accel_scale": 0.0},
timeout=T_MOVE,
)
response.raise_for_status()
result = response.json()
if not result["success"]:
raise RuntimeError(result["message"])
~~~
=== "MATLAB"
~~~ matlab
body = struct('name', 'home', 'speed', 0.1, 'accel_scale', 0.0);
reply = webwrite([HOST '/robot/move/named'], body, moveOpts);
assert(reply.success, reply.message)
~~~
### Cartesian TCP motion
POST **/robot/move/pose** accepts a TCP position in meters and an ABC orientation in radians. If **frame_id** is empty, the frame from the planning settings is used; in the standard configuration this is **base_link**.
| Field | Required | Value |
|---|---:|---|
| x, y, z | yes | TCP coordinates, m |
| a, b, c | no | KUKA ABC angles, rad; default: 0 |
| speed | no | Speed scale from 0.01 to 1.0; default: 0.1 |
| planner | no | ompl, ptp, lin, circ, or chomp; default: ptp |
| frame_id | no | Target pose frame; an empty string uses the default frame |
The **planner** value is converted to lowercase. PTP is suitable for transitions between points; LIN produces straight-line tool motion. CIRC is appropriate only when it is supported by the planner and target pose.
=== "curl"
~~~ bash
curl -sS --max-time 60 -X POST $HOST/robot/move/pose \
-H "Content-Type: application/json" \
-d '{
"x": 0.40, "y": 0.00, "z": 0.50,
"a": 0.0, "b": 3.14159, "c": 0.0,
"speed": 0.1, "planner": "ptp", "frame_id": ""
}'
~~~
=== "Python"
~~~ python
target = {
"x": 0.40, "y": 0.00, "z": 0.50,
"a": 0.0, "b": 3.14159, "c": 0.0,
"speed": 0.1, "planner": "ptp", "frame_id": "",
}
response = httpx.post(f"{HOST}/robot/move/pose", json=target, timeout=T_MOVE)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
body = struct( ...
'x', 0.40, 'y', 0.00, 'z', 0.50, ...
'a', 0.0, 'b', pi, 'c', 0.0, ...
'speed', 0.1, 'planner', 'ptp', 'frame_id', '');
reply = webwrite([HOST '/robot/move/pose'], body, moveOpts);
assert(reply.success, reply.message)
~~~
### Moving by joint angles
POST **/robot/move/joints** accepts exactly seven angles in J1J7 order. The API validates the number of values and the current limits from **joint_limits.yaml**.
| Joint | Allowed angle, rad |
|---|---:|
| J1 | -2.97 to 2.97 |
| J2 | -2.10 to 2.10 |
| J3 | -2.97 to 2.97 |
| J4 | -2.10 to 2.10 |
| J5 | -2.97 to 2.97 |
| J6 | -2.10 to 2.10 |
| J7 | -3.05 to 3.05 |
If the limits file changes, use Swagger UI as the reference. The table above describes the supplied configuration.
=== "curl"
~~~ bash
curl -sS --max-time 60 -X POST $HOST/robot/move/joints \
-H "Content-Type: application/json" \
-d '{"joints": [0.0, 0.5, 0.0, -1.57, 0.0, 1.57, 0.0], "speed": 0.1}'
~~~
=== "Python"
~~~ python
response = httpx.post(
f"{HOST}/robot/move/joints",
json={
"joints": [0.0, 0.5, 0.0, -1.57, 0.0, 1.57, 0.0],
"speed": 0.1,
},
timeout=T_MOVE,
)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
body = struct( ...
'joints', [0.0, 0.5, 0.0, -1.57, 0.0, 1.57, 0.0], ...
'speed', 0.1);
reply = webwrite([HOST '/robot/move/joints'], body, moveOpts);
assert(reply.success, reply.message)
~~~
## Joint trajectories
Endpoints under **/trajectory** publish a `JointTrajectory` message directly to **/iiwa_arm_controller/joint_trajectory**. A **status: sent** response confirms publication, not completion of motion or absence of controller errors. Monitor **/robot/joint_states** and inspect **/trajectory/logs** when necessary.
### JSON trajectory
POST **/trajectory/send** accepts one or more points.
| Field | Value |
|---|---|
| points | Non-empty point list |
| points[].positions | Exactly 7 J1J7 angles in radians |
| points[].time_from_start | Time from trajectory start in seconds, at least 0 |
| validate_limits | Validate joint limits; default: true |
The server does not check that time increases between points. Set increasing values yourself to make controller behavior predictable.
=== "curl"
~~~ bash
curl -sS --max-time 20 -X POST $HOST/trajectory/send \
-H "Content-Type: application/json" \
-d '{
"points": [
{"positions": [0, 0, 0, 0, 0, 0, 0], "time_from_start": 0.0},
{"positions": [0, 0.5, 0, -1.0, 0, 1.0, 0], "time_from_start": 3.0},
{"positions": [0, 0, 0, 0, 0, 0, 0], "time_from_start": 6.0}
],
"validate_limits": true
}'
~~~
=== "Python"
~~~ python
trajectory = {
"points": [
{"positions": [0.0] * 7, "time_from_start": 0.0},
{"positions": [0.0, 0.5, 0.0, -1.0, 0.0, 1.0, 0.0], "time_from_start": 3.0},
{"positions": [0.0] * 7, "time_from_start": 6.0},
],
"validate_limits": True,
}
response = httpx.post(f"{HOST}/trajectory/send", json=trajectory, timeout=T_READ)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
p1 = struct('positions', [0, 0, 0, 0, 0, 0, 0], ...
'time_from_start', 0.0);
p2 = struct('positions', [0, 0.5, 0, -1.0, 0, 1.0, 0], ...
'time_from_start', 3.0);
trajectory.points = [p1, p2];
trajectory.validate_limits = true;
opts = weboptions('MediaType', 'application/json', 'Timeout', T_READ);
reply = webwrite([HOST '/trajectory/send'], trajectory, opts);
disp(reply)
~~~
### Uploading CSV
POST **/trajectory/send_csv** accepts a CSV file in the multipart **file** field. The first row must be a header. Joint columns may be named **joint1** or **joint_1**, case-insensitively. The time column may be named **t**, **time**, or **time_from_start**. Columns may appear in any order.
Example file:
~~~ csv
joint1,joint2,joint3,joint4,joint5,joint6,joint7,t
0,0,0,0,0,0,0,0.0
0,0.5,0,-1.0,0,1.0,0,3.0
~~~
Pass **separator** and **validate_limits** in the query string, not as form fields. The default separator is a comma and limit validation is enabled.
=== "curl"
~~~ bash
curl -sS --max-time 20 -X POST \
"$HOST/trajectory/send_csv?separator=%2C&validate_limits=true" \
-F "file=@trajectory.csv;type=text/csv"
~~~
=== "Python"
~~~ python
with open("trajectory.csv", "rb") as csv_file:
response = httpx.post(
f"{HOST}/trajectory/send_csv",
params={"separator": ",", "validate_limits": True},
files={"file": ("trajectory.csv", csv_file, "text/csv")},
timeout=T_READ,
)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
import matlab.net.http.*
import matlab.net.http.io.*
uri = URI([HOST '/trajectory/send_csv?separator=%2C&validate_limits=true']);
form = MultipartFormProvider('file', FileProvider('trajectory.csv'));
request = RequestMessage('post', [], form);
httpOpts = HTTPOptions('ConnectTimeout', T_READ, 'ResponseTimeout', T_READ);
response = request.send(uri, httpOpts);
disp(response.Body.Data)
~~~
For a semicolon-delimited file, replace `%2C` with `%3B`.
### Trajectory module log
GET **/trajectory/logs?n=50** returns up to 300 latest entries. The **n** parameter must be between 1 and 300.
=== "curl"
~~~ bash
curl -sS "$HOST/trajectory/logs?n=20" | python3 -m json.tool
~~~
=== "Python"
~~~ python
response = httpx.get(f"{HOST}/trajectory/logs", params={"n": 20}, timeout=T_READ)
response.raise_for_status()
for line in response.json()["lines"]:
print(line)
~~~
=== "MATLAB"
~~~ matlab
logs = webread([HOST '/trajectory/logs?n=20'], readOpts);
disp(logs.lines)
~~~
Use the common **POST /stop** endpoint to interrupt a trajectory. The API has no **/trajectory/stop** endpoint.
## Motion sequences
POST **/sequences/start** launches a separate `motion_sequence_runner` process. It reads the uploaded JSON file and sends `MoveToJoints` or `MoveToPose` targets in sequence.
| Form field | Default | Purpose |
|---|---:|---|
| config | — | Sequence JSON file; required |
| n_iterations | 3 | Number of repetitions; at least 1 |
| delay_between_iterations | 5.0 | Delay between iterations, s |
| bag_path | empty | rosbag output path; an empty string disables recording |
| topics | empty | Comma-separated rosbag topics; empty means all discovered topics |
| joints_action | cobot/move_to_joints | Action name for joint targets |
| pose_action | cobot/move_to_pose | Action name for Cartesian targets |
Minimal configuration:
~~~ json
{
"home": {
"joints": [0, 0, 0, -1.57, 0, 1.57, 0],
"speed": 0.1
},
"waypoints": [
{
"x": 0.6, "y": 0.1, "z": 0.55,
"a": 3.14, "b": 0.31, "c": 2.79,
"speed": 0.2, "planner": "lin"
},
{
"joints": [0.5, 0.3, 0, -1.2, 0, 1.4, 0],
"speed": 0.2
}
]
}
~~~
A point containing **joints** is treated as a joint target. Otherwise, the runner expects Cartesian fields **x**, **y**, **z**, **a**, **b**, and **c**.
### Starting a sequence
=== "curl"
~~~ bash
curl -sS --max-time 10 -X POST $HOST/sequences/start \
-F "config=@motion_sequence_config.json;type=application/json" \
-F "n_iterations=3" \
-F "delay_between_iterations=5.0"
~~~
=== "Python"
~~~ python
with open("motion_sequence_config.json", "rb") as config:
response = httpx.post(
f"{HOST}/sequences/start",
files={"config": ("motion_sequence_config.json", config, "application/json")},
data={"n_iterations": "3", "delay_between_iterations": "5.0"},
timeout=T_READ,
)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
import matlab.net.http.*
import matlab.net.http.io.*
form = MultipartFormProvider( ...
'config', FileProvider('motion_sequence_config.json'), ...
'n_iterations', '3', ...
'delay_between_iterations', '5.0');
request = RequestMessage('post', [], form);
httpOpts = HTTPOptions('ConnectTimeout', T_READ, 'ResponseTimeout', T_READ);
response = request.send(URI([HOST '/sequences/start']), httpOpts);
disp(response.Body.Data)
~~~
A **status: started** response confirms that the process started, not that the JSON is valid or that every motion succeeds. If the runner exits with an error, inspect its status and log.
### Sequence status and log
=== "curl"
~~~ bash
curl -sS $HOST/sequences/status | python3 -m json.tool
curl -sS "$HOST/sequences/logs?n=50" | python3 -m json.tool
~~~
=== "Python"
~~~ python
status = httpx.get(f"{HOST}/sequences/status", timeout=T_READ)
status.raise_for_status()
print(status.json())
logs = httpx.get(f"{HOST}/sequences/logs", params={"n": 50}, timeout=T_READ)
logs.raise_for_status()
for line in logs.json()["lines"]:
print(line)
~~~
=== "MATLAB"
~~~ matlab
status = webread([HOST '/sequences/status'], readOpts);
logs = webread([HOST '/sequences/logs?n=50'], readOpts);
disp(status)
disp(logs.lines)
~~~
Statuses:
- **idle** — no sequence has been started;
- **running** — the process is running;
- **finished** — the process has exited; the response includes **returncode**.
Only one sequence can run at a time. A second POST to **/sequences/start** while one is running returns 409. Use **POST /stop** to stop it; there is no separate **/sequences/stop** endpoint.
## Common stop command
POST **/stop** stops the running sequence runner, publishes a hold point at the current position to the trajectory controller, and calls the MoveIt **cobot/stop** service. If current joint states are unavailable, it publishes an empty trajectory instead.
=== "curl"
~~~ bash
curl -sS --max-time 10 -X POST $HOST/stop | python3 -m json.tool
~~~
=== "Python"
~~~ python
response = httpx.post(f"{HOST}/stop", timeout=T_READ)
response.raise_for_status()
print(response.json())
~~~
=== "MATLAB"
~~~ matlab
reply = webwrite([HOST '/stop'], struct(), ...
weboptions('MediaType', 'application/json', 'Timeout', T_READ));
disp(reply)
~~~
This command cancels software operations, but does not remove robot power or replace the standard emergency stop. After calling it, verify both the response message and the physical robot state.
## Errors and diagnostics
| Code | When it occurs |
|---:|---|
| 200 | The request was processed; for motion commands, also check the success field |
| 409 | A motion sequence is already running |
| 422 | Invalid request structure, joint count, speed, planner, or joint limits |
| 503 | A ROS topic, service, action server, or MoveIt is unavailable; a wait timeout may also have occurred |
When troubleshooting, proceed from simple checks to more complex ones:
1. Open **/docs** and verify that the server is running and the endpoint appears in the schema.
2. Check **/robot/joint_states**. Without it, pose retrieval does not work and trajectory stopping cannot generate a hold point.
3. Make sure that the complete stack is running: `controller_manager`, MoveIt, and `iiwa_motion_server`.
4. After starting a sequence, inspect **/sequences/logs**. After publishing a trajectory, inspect **/trajectory/logs**.
The MCP server runs in the same process but provides a separate interface at **http://server-address:8007/mcp/mcp**. For ordinary HTTP integrations, use the endpoints documented on this page.
@@ -0,0 +1,11 @@
# Control via ROS 2
!!! info "Work in progress"
Detailed instructions for control through ROS 2 topics and action servers are being prepared.
This method sends commands directly to ROS 2 using CLI tools (`ros2 topic pub`, `ros2 action send_goal`) or custom ROS 2 nodes written in Python or C++.
## Additional resources
- [ROS 2 Jazzy documentation](https://docs.ros.org/en/jazzy/index.html) — official documentation for topics, services, action servers, and node development
- [MATLAB Robotics System Toolbox](https://www.mathworks.com/help/ros/index.html?s_tid=CRUX_lftnav) — control the robot through ROS 2 from MATLAB
@@ -0,0 +1,24 @@
# Getting started
This section explains how to prepare the environment, connect to the controller, install the project, and start controlling the robot.
## Quick start
1. [**Sunrise Workbench setup**](sunrise-setup.md) — prepare the KUKA controller, upload `ServerFriRos2`, and configure the network. *(Physical robot only.)*
2. [**Connect to the server**](remote-access.md) — choose local or remote deployment and connect to the control server over SSH.
3. [**Install the project**](installation.md) — install LWC using `curl`, `git`, or manually.
4. [**Configure the system**](configuration.md) — configure `cobot-setting.yaml` with the robot IP, ports, and tools.
5. [**cobot CLI**](cli-reference.md) — learn the commands for running, building, and updating the project.
!!! tip "Simulation only?"
Skip the physical-controller setup and run `cobot run --simulate` after installation.
## Concepts and control
- [System architecture](concepts/architecture.md)
- [FRI protocol](concepts/fri-protocol.md)
- [Webots simulation](concepts/simulation.md)
- [Motion planning](concepts/motion-planning.md)
- [ROS 2 Control](control/ros2-control.md)
- [Foxglove](control/foxglove.md)
- [REST API](control/rest-api.md)
@@ -0,0 +1,114 @@
# Project installation
## Quick installation
The easiest option is to install the project with a single `curl` command. Make sure that `curl` is installed:
```bash
sudo apt update && sudo apt upgrade -y && sudo apt install curl
```
Go to your home directory and run the installation script:
=== "Stable version (master)"
```bash
cd ~
curl -fsSL https://gitverse.ru/api/repos/daniel-robotics/lightweight-cobot/raw/branch/master/install.sh | bash
```
=== "Development version (dev)"
```bash
cd ~
curl -fsSL https://gitverse.ru/api/repos/daniel-robotics/lightweight-cobot/raw/branch/dev/install.sh | bash -s dev
```
---
## Installation with Git
The project is available on both [GitVerse](https://gitverse.ru/daniel-robotics/lightweight-cobot) (preferred) and [GitHub](https://github.com/Daniel-Robotic/lightweight-cobot).
!!! tip "New to Git?"
If this is your first time using Git and GitHub, see the [GitHub getting-started guide](https://docs.github.com/en/get-started/start-your-journey/hello-world).
Clone the repository and run the installation script:
=== "GitVerse"
```bash
cd ~
git clone https://gitverse.ru/daniel-robotics/lightweight-cobot.git
cd ~/lightweight-cobot
sudo chmod +x ./install.sh
./install.sh
```
=== "GitHub"
```bash
cd ~
git clone https://github.com/Daniel-Robotic/lightweight-cobot.git
cd ~/lightweight-cobot
sudo chmod +x ./install.sh
./install.sh
```
---
## Manual installation
If neither `curl` nor `git` is available, download the project archive manually from the repository page using the **Download ZIP** button, extract it, and run:
```bash
cd ~/lightweight-cobot
sudo chmod +x ./install.sh
./install.sh
```
---
## Installation process
The [`install.sh`](https://gitverse.ru/daniel-robotics/lightweight-cobot/raw/branch/master/install.sh) script automatically installs:
- **Git** — version control system;
- **Docker** — containerization for isolated execution;
- **`cobot` CLI** — the main project management tool;
- Ubuntu system dependencies.
### Restarting after installation
After the script finishes, a restart may be required for Docker to work:
```bash
sudo reboot now
```
Watch the terminal output: the script will indicate whether a restart is required.
### If the log is empty
If the script produces no output, reload the Bash environment and continue setup manually:
```bash
source ~/.bashrc # refresh environment variables
cobot setup # continue system setup
```
---
## Verifying the installation
After installation, make sure that `cobot` is available:
```bash
cobot -h
```
If the command displays the list of available subcommands, installation was successful.
---
**Next step:** [System configuration](configuration.md)
@@ -0,0 +1,76 @@
# Connecting to the server
## Deployment options
The project can be deployed in two ways:
| Option | Description | When to use it |
|---|---|---|
| **Local** | Install on your PC | Development, simulation, and debugging |
| **Remote (server)** | Install on a dedicated server connected to the KUKA controller | Working with the physical robot |
With remote deployment, you control the server from your PC over an **SSH connection**.
---
## SSH clients
Choose any of the following applications:
- [**Termius**](https://termius.com/) — cross-platform SSH client with a convenient GUI;
- [**MobaXterm**](https://mobaxterm.mobatek.net/) — multifunctional terminal for Windows;
- [**PuTTY**](https://putty.software/) — classic SSH client for Windows;
- the **built-in terminal or command prompt**, as described below.
For instructions on configuring Termius, MobaXterm, or PuTTY, refer to their official documentation.
---
## Connection details
```
IP address: 192.168.21.1
Username: cobot
Password: 12345678
```
!!! warning "Network requirement"
Your PC must be on the **same network/subnet as the robot** (for example, the KnASU network). Otherwise, the connection cannot be established.
---
## Connecting from the built-in terminal
=== "Linux"
Any distribution can be used. Open a terminal and run:
```bash
ssh cobot@192.168.21.1
```
=== "Windows"
**Windows 10** or later is required for the built-in SSH client. Open **Command Prompt** or **PowerShell** and run:
```powershell
ssh cobot@192.168.21.1
```
The command will prompt for a password:
```
cobot@192.168.21.1's password:
```
Enter `12345678`. Characters are not displayed while you type; this is normal security behavior. Press ++enter++.
After a successful connection, the server command prompt appears:
```
cobot@server:~$
```
---
**Next step:** [Project installation](installation.md)
@@ -0,0 +1,85 @@
# SunriseWorkbench setup
!!! info "Physical robot only"
This section applies only when working with a physical KUKA LBR IIWA 7. For simulation, proceed to [Project installation](installation.md).
---
## Physical hardware setup
### Ethernet connection
Connect an Ethernet cable from your PC or control server to one of the KUKA controller's network ports:
- **KLI** (KUKA Line Interface) — the primary port used for control and programming;
- **KONI** (KUKA Optional Network Interface) — the additional port used for FRI.
Both ports can be connected at the same time. You can select the interface when configuring the server.
> Connect the KLI and KONI ports according to the KUKA controller wiring diagram.
---
## Synchronizing the SunriseWorkbench project
### Checking for ServerFriRos2
Make sure that your Sunrise project contains `ServerFriRos2.java`. If the file is missing, download it from the repository. Its path is `src/iiwa_sunrise/src/ServerFriRos2.java`.
=== "curl"
```bash
curl -fsSL https://gitverse.ru/api/repos/daniel-robotics/lightweight-cobot/raw/branch/master/src/iiwa_sunrise/src/ServerFriRos2.java \
-o ServerFriRos2.java
```
=== "wget"
```bash
wget -O ServerFriRos2.java \
https://gitverse.ru/api/repos/daniel-robotics/lightweight-cobot/raw/branch/master/src/iiwa_sunrise/src/ServerFriRos2.java
```
After downloading it, add the file to the Sunrise project and synchronize the project with the controller.
### Synchronizing with the controller
Open **SunriseWorkbench** and click the project synchronization button:
> In SunriseWorkbench, use the project synchronization button.
Before synchronizing, make sure that the PC and KUKA controller are on the same network. The current controller network settings can be checked directly in SunriseWorkbench:
> The controller network parameters are available in the SunriseWorkbench settings window.
---
## Configuring ServerFriRos2
Open `ServerFriRos2.java` in SunriseWorkbench and change the following parameters to match your network configuration:
```java
// IP address of the KONI interface
KONI_IP = "192.170.10.10";
// IP address of the KLI interface
KLI_IP = "192.168.21.31";
// Zero position (all joints at 0°)
ZERO_POSITION = {0, 0, 0, 0, 0, 0, 0};
// Working position for monitoring
MONITOR_WORKING_POSITION = {0, 0, 0, -1.57, 0, 1.57, 0};
// Tool used by default
@Named("tool1")
```
!!! warning "Important"
`KONI_IP` and `KLI_IP` in the Java program are addresses of the ROS 2 computer that the controller can reach through the corresponding networks. Conversely, `robot.ip` in `cobot-setting.yaml` is the address of the KUKA controller as seen from the computer. Incorrect or swapped addresses prevent the FRI connection from being established.
After making the changes, synchronize the project with the controller again.
---
**Next step:** [Connecting to the control server](remote-access.md)
@@ -17,7 +17,7 @@
Вы можете подключить оба порта одновременно — при конфигурации сервера будет выбор, какой интерфейс использовать.
![Подключение KONI и KLI](assets/koni-kli-connection.png)
> Подключите порты KLI и KONI согласно схеме подключения контроллера KUKA.
---
@@ -48,11 +48,11 @@
Откройте **SunriseWorkbench** и нажмите кнопку синхронизации проекта:
![Кнопка синхронизации проекта](assets/sync-button.png)
> В SunriseWorkbench используйте кнопку синхронизации проекта.
Перед синхронизацией убедитесь, что ПК и контроллер KUKA находятся в одной сети. Текущие сетевые параметры контроллера можно быстро проверить прямо в SunriseWorkbench:
![Быстрый просмотр параметров сети](assets/network-params.png)
> Сетевые параметры контроллера доступны в окне настроек SunriseWorkbench.
---