This repository is part of a research project ANR MITCH.
The provided code is research-grade and not intended for industrial or safety‑critical deployment.
This repository is primarily hosted on GitHub. For the moment, pushes are mirrored to GitLab because the project is linked to my lab environment. However, I’m not certain I’ll retain access to the lab’s GitLab after my PhD, so GitHub is the long‑term home of the project.
If you need access to my laboratory GitLab instance, you can find it here
- ✅ GitHub: This is the main platform for the project. Please use it to open Pull Requests, report issues and discuss features and bugs.
⚠️ GitLab: The repository is mirrored. Please do not open issues or merge requests there — use GitHub instead
URModbus enables external control of Universal Robots (UR) via the Modbus and Dashboard interfaces while keeping task logic on the robot itself.
The core idea is simple:
✨ Program tasks directly on the teach pendant but manage execution and scheduling externally.
Quick demo of the capabilities

The script is running in
AUTO, therefore it is currently following the associated process file.
Offline:
- UR CB3 Offline Simulator
ursim cb3 docker - Used for developing
Online:
- Tasks are implemented directly on the teach pendant
- A Modbus-based switch controls execution
- Robot publishes its current state continuously
- External task scheduling and monitoring
- Execution timing and logging
- Interactive terminal-based control interface (TUI)
| File | Description |
|---|---|
| RobotController.py | Main controller; manages task execution using a task queue |
| TimeTracker.py | Measures and logs task execution times |
| ModbusTools.py | Modbus communication layer |
| DashTools.py | Dashboard server interface |
| ProcessTool.py | Loads and manages task process files |
| CommandServer.py | Interactive terminal (TUI) |
| Constants.py | Settings for the code |
- Enable Modbus on the robot
- Create an input word
- Address:
131 - Name:
Next_Action
- Address:
- Create an output word
- Address:
130 - Name:
Current_Action
- Address:
- Create a program named
test_modbus.urpcontaining a switch based onNext_Action
⚠️ Ensure:
- A default case
- Proper initial variable values
- Task
0is reserved for idle
- Clone the repository
git clone https://github.com/Le-Nain-Capable/URModbus.git
- Navigate to it
cd URModbus
- Install dependencies
pip install -r requirements.txt
- Configure
constants.py
- Robot IP (real robot)
- OR container name (simulation)
- Run the controller
python3 main.py
or
python3 -m URModbus
✅ The controller is now running.
Open another terminal:
nc localhost 9999
You should see the interactive TUI.

- Type
playor - Start the UR program manually
The system relies on Modbus word exchange:
Next_Action→ what the robot should do nextCurrent_Action→ what the robot is currently executing
sequenceDiagram
participant Robot
participant Controller
Robot -->> Controller: Current_Action
Controller -->> Robot: Next_Action
- Each task is identified by a unique integer
- The integer corresponds to a
switchcase on the robot - Example:
1→ Pick part2→ Place part
- ✅ Set
Current_Actionat task start - ✅ Always implement a default case
- ✅ Initialize all variables
⚠️ Task0is strictly reserved for “Do Nothing”
| Variable | Description | Default |
|---|---|---|
| MODE | AUTO or MANUAL |
AUTO |
| AUTO_LOAD | Auto-load YAML based on UR program | True |
| TERMINAL_PORT | TUI port | 9999 |
| TERMINAL_HOST | TUI host | 127.0.0.1 |
| ROBOT_SLEEP_TIME | Loop sleep time (must match UR sleep!) | 0.1 |
| UR5_IP | Robot IP address | 192.168.1.10 |
| CONTAINER | URSim container name | ursim |
| DATA_DIR | Data folder | data |
| AUTOGEN_DIR | Time logs directory | data/autogenerated |
| TEST_FILE | Simulator YAML file | test.yaml |
| PROCESS_FILE | Real robot YAML file | data.yaml |
| MOTS | Modbus word mapping | see file |
Settings can be configured in 3 ways:
-
Edit defaults
Modify values directly inURModbus/config/constants.py -
Script arguments
Override settings at runtime
python3 main.py --<argument> <value>
Example:
python3 main.py --MODE MANUAL -
Module arguments
Run URModbus as a module
python3 -m URModbus --<argument> <value>
Example:
python3 -m URModbus --MODE MANUAL
⚠️ Command-line arguments (2 and 3) are temporary and will not be saved.
Ensure the container exposes:
502(Modbus)29999(Dashboard)
Set the container name in CONTAINER.
YAML files define task sequencing and dependencies.
Example – test_modbus.yaml:
version: 0
name: Test
tasks:
0:
name: Intermediate
requires:
1:
name: Task 1
requires: 0
2:
name: Task 2
requires: 1
ordering: [1,2]
⚠️ Task0is mandatory and acts as a safe idle state between tasks.
- Executes tasks sequentially using
ordering
- Tasks must be injected dynamically by the user
- If enabled:
- Reads the active UR program name
- Attempts to auto-load the matching YAML file
- Falls back to
TEST_FILEorPROCESS_FILEif unavailable
By default:
- The TUI should be available at localhost:9999. It is a pure TCP connection and not a true TUI
- You can establish a TCP connection to it with any tool like
ncor anysocketlibrary. - You have to send it
strof requested functions call with arguments.
help is a good way to start, as it should display all available commands. Then running <command> -h will get you information on how to use such command.
The TCP will accept only 1 connection.
The greetings' interaction is as follows:
sequenceDiagram
participant TUI
participant TCP
TCP -->> TUI: Establish connection
TUI -->> TCP: Send Logo
TUI -->> TCP: Send Greetings message
TUI -->> TCP: Send Status results
Keep the socket open and send commands to it. Per command, you will receive a response.
Here is a breakdown of commands, usage and parameters.
| Command | Details | Usage | Special Parameters | Example |
|---|---|---|---|---|
| add | Add tasks to the task pile | add <task_id> |
-f: force adding a task to the pile |
add 1add -f 500 |
| clear | Clear the task pile | clear |
None | clear |
| gantt | Draw a gantt | gantt |
<task(s)_id(s)>: plot only requested tasks.-cli: render the graph in the CLI -car <caracter> caracter used for a full cell in cli chart mode -name <name>: change the graph name |
ganttgantt -cli 8 7 9gantt -name MyGantt |
| gaussian | Draw a gaussian | gaussian |
<task(s)_id(s)>: plot only requested tasks. -name <name>: change the graph name |
gaussiangaussian 8 7 9gaussian -name MyGaussian |
| help | Display help | help |
None | help |
| info | Display information on a specific task | info <task_id> |
None | info 1 |
| load | Load a new process file | load <process_file_name> |
None | load myfileload myfile.yaml |
| pause | Pause the program execution | pause |
None | pause |
| play | Play the program execution | play |
None | play |
| sequence | Add a sequence to the task pile | sequence <tasks_ids> |
-f: force adding a task to the pile |
sequence 1 2 3 4 5sequence -f 500 |
| process | Display information of the current process | process |
None | process |
| program | Display information of the current program | program |
None | program |
| stop | Stop the program execution | stop |
None | stop |
| stats | Obtain a stats report | stats |
<task(s)>: request data for selected tasks-full:whole process report-p:only general process info |
statsstats 1 2 3stats -fullstats -p |
| status | Status report | status |
None | status |