Flow Base
Flow Base is I2RT's omnidirectional holonomic mobile platform. Designed to pair with YAM arms, it enables precise whole-body mobile manipulation for tasks that demand exact positioning and free orientation.

Tagline
"It likes to move it move it" — precise, omnidirectional control for tasks where positioning and stability are critical.
Key Features
- Holonomic drive — simultaneous XY translation and rotation with no kinematic constraints
- On-board Raspberry Pi — pre-configured with i2rt SDK; SSH-accessible over Wi-Fi or Ethernet
- CAN bus motor control — same DM-series protocol as YAM arms
- Remote controller — joystick remote included for manual operation
- API control — full network Python API via
FlowBaseClient - Odometry — wheel odometry with reset; external sensor integration supported
- Safety — E-stop, velocity timeout (0.25 s), remote override
Specifications
| Parameter | Value |
|---|---|
| Drive | Holonomic (4-wheel) |
| Communication (external) | Ethernet (static IP 172.6.2.20) / Wi-Fi |
| Communication (motors) | CAN bus |
| On-board computer | Raspberry Pi |
| Power | Internal battery |
| SSH credentials | i2rt / root |
| API port | 11323 |
| Velocity timeout | 0.25 s |
Photos & Videos







Hardware Setup
Get the Flow Base omnidirectional mobile platform unboxed, powered, and joystick-ready.
Prerequisite
SW Setup is not required — the Flow Base ships with a Raspberry Pi pre-configured with the SDK. You only need network access to SSH in.
1. Unbox
- [ ] Flow Base chassis
- [ ] Battery pack (already installed)
- [ ] Joystick remote controller
- [ ] Ethernet cable (for wired SSH)
- [ ] Charger
2. Power on
- [ ] Twist the E-stop button counter-clockwise to release it
- [ ] Set the CAN selector switch to UP position (selects the on-board Pi as CAN master)
- [ ] Press the power button — the Pi display should light up
- [ ] Wait ~30 seconds for the Pi to finish booting
3. Connect to the Pi
# Wired (recommended) — static IP
ssh i2rt@172.6.2.20
# Password: rootWi-Fi setup
If you prefer Wi-Fi, connect a keyboard + monitor to the Pi the first time and run sudo raspi-config to join your network.
4. Verify the SDK is current
cd ~/i2rt && git pull5. Test with the joystick
On the Pi:
python i2rt/flow_base/flow_base_controller.py- [ ] Left joystick → base translates (XY)
- [ ] Right joystick X → base rotates (yaw)
- [ ] Press Left2 to override API commands (safety)
Quick Start Demo
Drive the Flow Base with the joystick remote, then control it programmatically.
1. Joystick demo (on the Pi)
ssh i2rt@172.6.2.20
python i2rt/flow_base/flow_base_controller.pySee the Remote Control Layout below for the full button reference.
2. Python API — drive forward from a laptop
From your laptop (on the same network):
from i2rt.flow_base.flow_base_client import FlowBaseClient
import numpy as np
import time
client = FlowBaseClient(host="172.6.2.20")
# Drive forward at 0.1 m/s for 2 seconds
start = time.time()
while time.time() - start < 2.0:
client.set_target_velocity(np.array([0.1, 0.0, 0.0]), frame="local")
time.sleep(0.05)
# Read odometry
print(client.get_odometry())
client.close()Velocity timeout
The base stops automatically if no command arrives within 0.25 seconds. The client maintains a heartbeat thread (20 ms) while connected.
For the full SDK (linear rail, frame conventions, advanced commands), see the API Reference section below.
Remote Control Layout
| Input | Function |
|---|---|
| Left joystick | XY translation |
| Right joystick X | Rotation (yaw) |
| Right joystick Y | Linear rail lift (if equipped) |
| Left1 | Reset odometry |
| Mode | Toggle local ↔ global frame |
| Left2 | Override API commands (safety) |
Coordinate Systems
The base supports two control frames toggled with the Mode button on the remote:
| Mode | Behaviour |
|---|---|
| Local | XY motion is relative to the base's current heading |
| Global | XY motion is relative to the world frame (headless mode) |
Odometry drift
Wheel odometry accumulates error, especially during aggressive movements. For precise mobile manipulation, integrate a visual odometry sensor (RealSense T265, ZED Camera). Press Left1 to reset odometry at any time.
API Reference
The Flow Base SDK has two layers:
| Class | Location | Use |
|---|---|---|
Vehicle | flow_base_controller.py | Runs on-board the Pi — joystick demo |
FlowBaseClient | flow_base_client.py | Runs remotely — network Python API |
FlowBaseClient
For remote control from your development machine.
from i2rt.flow_base.flow_base_client import FlowBaseClient
client = FlowBaseClient(
host="172.6.2.20",
with_linear_rail=False,
)| Parameter | Type | Default | Description |
|---|---|---|---|
host | str | "localhost" | IP address of the Flow Base Pi |
with_linear_rail | bool | False | Set True if the linear rail module is installed |
No port parameter
The port is hardcoded internally using BASE_DEFAULT_PORT. You only need to specify the host IP.
Movement Commands
set_target_velocity(velocity, frame)
import numpy as np
# 3D (base only)
client.set_target_velocity(np.array([vx, vy, omega]), frame="local")
# 4D (base + linear rail)
client.set_target_velocity(np.array([vx, vy, omega, rail_vel]), frame="local")| Parameter | Unit | Description |
|---|---|---|
vx | m/s | Forward/backward |
vy | m/s | Left/right (strafe) |
omega | rad/s | Rotation (yaw rate) |
rail_vel | rad/s | Linear rail speed (positive = up) |
frame | — | "local" (relative to base) or "global" (world frame) |
Velocity must be a NumPy array
set_target_velocity() expects a np.ndarray with shape (3,) or (4,). Pass np.array([...]), not a plain Python list.
Velocity timeout
The base stops automatically if no command arrives within 0.25 seconds. FlowBaseClient maintains a heartbeat automatically while connected via a background thread (20 ms interval).
Odometry
get_odometry() → dict
odom = client.get_odometry()
# {'translation': array([x, y]), 'rotation': array(theta)}Wheel odometry only. Errors accumulate over time — integrate visual odometry (RealSense T265, ZED) for precise localization.
reset_odometry() → None
Resets position and heading to zero.
Linear Rail API
Only available when with_linear_rail=True.
get_linear_rail_state() → dict
state = client.get_linear_rail_state()
# {
# 'position': float,
# 'velocity': float,
# 'upper_limit_triggered': bool,
# 'lower_limit_triggered': bool,
# }set_linear_rail_velocity(velocity: float) → None
client.set_linear_rail_velocity(0.5) # raise
client.set_linear_rail_velocity(0.0) # stop
client.set_linear_rail_velocity(-0.5) # lowerCombined base + rail command
client.set_target_velocity(np.array([vx, vy, omega, rail_vel]), frame="local")Auto-homing
The rail homes to the lower limit switch on init. Ensure clearance below before powering on.
Cleanup
Always close the client when done to stop the background heartbeat thread:
client.close()Command-line Client
Quick functional tests without writing Python:
# Read odometry
python i2rt/flow_base/flow_base_client.py --command get_odometry --host 172.6.2.20
# Reset odometry
python i2rt/flow_base/flow_base_client.py --command reset_odometry --host 172.6.2.20
# Run a short movement test (base will move)
python i2rt/flow_base/flow_base_client.py --command test_command --host 172.6.2.20
# Test linear rail (rail will move)
python i2rt/flow_base/flow_base_client.py --command test_linear_rail --host 172.6.2.20
# Monitor linear rail state
python i2rt/flow_base/flow_base_client.py --command get_linear_rail_state --host 172.6.2.20Vehicle (On-board Controller)
Runs directly on the Pi. Used for the joystick demo.
from i2rt.flow_base.flow_base_controller import Vehicle
import time
v = Vehicle()
v.start_control()
start = time.time()
while time.time() - start < 2.0:
v.set_target_velocity((0.15, 0.0, 0.0), frame="local")Coordinate Frames
| Frame | Description |
|---|---|
local | Relative to the current base orientation. Joystick forward = robot forward regardless of heading. |
global | World frame from odometry zero. Similar to drone headless mode. Accumulates error. |
Switch frames at runtime via the remote Mode button, or programmatically by passing frame= to set_target_velocity.
External CAN Control
To bypass the on-board Pi and control the base from an external computer:
- Connect your CAN adapter to the external CAN connector
- Set the CAN selector switch to the DOWN position
- Clone the i2rt repo on your external machine and control via CAN directly
Troubleshooting
| Symptom | Fix |
|---|---|
| Remote unresponsive | Toggle remote off and on to wake from sleep |
| Slow boot | Normal — screen firmware adds delay, SSH is available quickly |
| Inaccurate odometry | Expected with wheel odometry; use external visual sensor for precision |
| Linear rail not homing | Check GPIO connections and limit switches |
| Linear rail stuck at limit | Run get_linear_rail_state() to check switch status |
See Also
- Linear Bot — Flow Base + linear rail lift + YAM arm
- Flow Base hardware setup
- Flow Base demo