Overview
FERAL treats robots as first-class hardware nodes. Any actuator — robotic arms, mobile platforms, drones, custom builds — can connect to the brain through the Hardware Unified Protocol (HUP). The brain sends commands, receives sensor data, and can orchestrate multi-robot workflows through natural language.
Architecture
Voice / Text Command → FERAL Brain → HUP Protocol → Robot Node → Actuators
↑
Sensor data / Status
Robot Node Template
The Python SDK includes a robot template that handles HUP registration, command dispatch, and sensor reporting:
from feral_sdk.hardware import HUPNode, DeviceManifest
manifest = DeviceManifest(
device_id = "robot_arm_01" ,
device_type = "robot" ,
name = "Desktop Robot Arm" ,
capabilities = [ "move" , "grip" , "home" , "status" ],
sensors = [ "position" , "force" , "temperature" ],
)
node = HUPNode(
brain_url = "ws://localhost:9091/v1/node" ,
manifest = manifest,
)
@node.on_command ( "move" )
async def handle_move ( params ):
x, y, z = params[ "x" ], params[ "y" ], params[ "z" ]
speed = params.get( "speed" , 50 )
await robot.move_to(x, y, z, speed = speed)
return { "status" : "moved" , "position" : [x, y, z]}
@node.on_command ( "grip" )
async def handle_grip ( params ):
force = params.get( "force" , 30 )
await robot.set_gripper(force)
return { "status" : "gripped" , "force" : force}
@node.on_command ( "home" )
async def handle_home ( params ):
await robot.home()
return { "status" : "homed" }
node.run()
The template is at sdk/python-node-sdk/robot_template.py in the FERAL repo. Copy it as a starting point for your robot.
HUP Device Manifest
Every robot must declare a manifest when it connects to the brain:
{
"device_id" : "robot_arm_01" ,
"device_type" : "robot" ,
"name" : "Desktop Robot Arm" ,
"protocol_version" : "1.0" ,
"capabilities" : [
{
"name" : "move" ,
"description" : "Move end effector to XYZ coordinates" ,
"params" : {
"x" : { "type" : "float" , "unit" : "mm" },
"y" : { "type" : "float" , "unit" : "mm" },
"z" : { "type" : "float" , "unit" : "mm" },
"speed" : { "type" : "int" , "unit" : "percent" , "default" : 50 }
}
},
{
"name" : "grip" ,
"description" : "Close gripper with specified force" ,
"params" : {
"force" : { "type" : "int" , "unit" : "percent" , "default" : 30 }
}
}
],
"sensors" : [ "position" , "force" , "temperature" ]
}
The brain uses the manifest to understand what the robot can do and exposes those capabilities to the LLM for natural-language control.
ROS Bridge
For ROS-based robots, FERAL provides a bridge node that translates between HUP and ROS topics:
pip install feral-ros-bridge
feral-ros-bridge \
--brain ws://localhost:9091/v1/node \
--ros-master http://localhost:11311 \
--device-id "turtlebot_01" \
--cmd-topic /cmd_vel \
--sensor-topics /odom,/scan,/camera/image
Flag Description --brainFERAL brain HUP endpoint --ros-masterROS master URI --device-idUnique device identifier --cmd-topicROS topic for movement commands --sensor-topicsComma-separated sensor topics to stream
Serial & I2C Adapters
For microcontroller-based robots (Arduino, ESP32), use the serial or I2C adapter:
Serial (USB)
I2C (Raspberry Pi)
from feral_sdk.hardware import SerialAdapter
adapter = SerialAdapter(
port = "/dev/ttyUSB0" ,
baud = 115200 ,
brain_url = "ws://localhost:9091/v1/node" ,
device_id = "arduino_bot" ,
)
adapter.run()
Example: Commanding a Robot Arm
Once connected, control the robot through natural language:
> "Move the robot arm to pick up the cup on the left"
FERAL Brain:
1. Queries glasses vision → identifies cup at position (120, 45, 30)mm
2. Sends HUP command: move(x=120, y=45, z=50) → approach from above
3. Sends HUP command: move(x=120, y=45, z=30) → descend to cup
4. Sends HUP command: grip(force=40) → grasp
5. Sends HUP command: move(x=120, y=45, z=100) → lift
Response: "Done — I've picked up the cup."
Multi-step robot operations require hybrid or loose autonomy mode. In strict mode, each step requires approval.
Troubleshooting
Robot node won't connect to brain
Verify the brain is running with feral status and that hup_port (default 9091) is accessible. Check firewall rules.
The default command timeout is 10 seconds. For slow actuators, increase it in the node config or return an async acknowledgment.
ROS bridge can't find topics
Ensure roscore is running and the topics exist. Run rostopic list to verify.