Example Project: Quad-Deploy
quad_deploy shows how ros_base is used in a high-frequency control stack. Compared with the task-oriented flow in SigLoMa-VLM, this repository emphasizes:
- High-frequency main loops
- RL-agent switching
- Joystick-driven state machines
- Bridging with the upper-level system
- External-process isolation when necessary
1. Current entry file
The current main entry is:
It defines:
and assembles the system in setup_environment():
Nodes
robot:UnitreeGo2SDKNodevlm:VLM2BobotBridgegripper:GripperNodejoystick:JoystickNode
Agents
standloconavturnauto_trigger
2. What the manager does in a high-frequency control setup
SigLoMaRunSDK stays disciplined and only handles:
- Injecting
SigLoMaHandler - Defining handshake rules
For example:
if wait_robot:
self.add_handshake_rule(
"Robot Connection",
lambda: hasattr(self.nodes.get("robot"), "low_state"),
)
The actual loop rate is controlled by constructor arguments:
- Simulation:
200Hz - Real robot:
50Hz
3. The handler drives global control-state transitions
The core logic lives in:
This handler uses the "write manager.state directly" style. Common states include:
cold_startrecoveryhuman_teleopturnnavigationgripper_startemergency
Transitions are jointly determined by:
- Joystick buttons
- Whether VLM messages have arrived
- Whether the current agent is
done - Auto-trigger conditions
4. BaseRLAgent shows how high-frequency agents are organized
quad_deploy/agents/base_rl_agent.py is especially valuable as a reference because it keeps the common structure of high-frequency agents very clean:
- Read
robotandjoystickfrom nodes - Parse configuration
- Maintain observation history with
CircularBuffer - Use
decimationto control real inference frequency
Key logic:
def handle(self):
if self.timestamp % self.decimation == 0:
action, p_gains, d_gains, done = self.step()
else:
action, p_gains, d_gains, done = None, None, None, None
self.robot.send_action(action, p_gains, d_gains)
This design allows:
- The manager to keep a stable main loop
- Agents to avoid running the full model on every cycle
- Control outputs to remain on one unified interface
5. How joystick input and safety states are handled
Inside SigLoMaHandler.get_state_transition(), many practical field rules are written explicitly:
L2->emergencyL1->recoveryR2-> force return tohuman_teleopR1-> enter the automatic control flow from manual modestart-> trigger the gripper directly
This is a good example of how ros_base can keep the chain from human input to state transition to current-agent selection inside one handler.
6. Bridging with the upper-level system
VLM2BobotBridge receives the following messages from the high-level side:
/control/turn/control/grasp/geometry_msgs/sigma_points_filtered/control/object_ready
and sends back:
/control/rl_ready/control/turn_done/control/grasp_done/control/euler_rpy
Together with Robot2VLMBridge in SigLoMa-VLM, it forms an upper/lower-level bridge pair.
7. How multi-process isolation is connected
Inside sigloma_run_sdk.py, the code calls:
before rclpy.init().
Typical uses in the current code include:
socatfor simulated serial ports- Keyboard-input nodes used in simulation
These are exactly the kind of side processes that should follow the system lifecycle without polluting the main control loop.
8. What this project teaches ros_base users
For a high-frequency robot control layer, the structure in quad_deploy is a strong reference:
- The manager only owns timing, handshakes, and shutdown
- The handler owns state transitions and agent selection
- High-frequency agents share one base class and use
decimation - Protocol bridging stays in nodes
- Edge tool processes are mounted through the multi-process interface