Adjust ROI usage and add voice control docs
This commit is contained in:
100
dora_voice_control/docs/add_robot.md
Normal file
100
dora_voice_control/docs/add_robot.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# Add a New Robot
|
||||
|
||||
This project uses a simple adapter + behavior pattern.
|
||||
|
||||
## 1) Create a robot adapter
|
||||
|
||||
Implement the common command interface:
|
||||
|
||||
- File: `dora_voice_control/dora_voice_control/robots/<robot_name>/adapter.py`
|
||||
- Base class: `RobotAdapter` (`dora_voice_control/dora_voice_control/core/robot.py`)
|
||||
|
||||
Example (vacuum style):
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from ...core.robot import RobotAdapter
|
||||
from ...core.state import RobotStep
|
||||
|
||||
NAME = "my_robot"
|
||||
ALIASES = {"my_robot", "my_alias"}
|
||||
|
||||
class MyRobotAdapter(RobotAdapter):
|
||||
def grab(self) -> List[RobotStep]:
|
||||
return [RobotStep(action="vacuum_on", payload={})]
|
||||
|
||||
def release(self) -> List[RobotStep]:
|
||||
return [RobotStep(action="vacuum_off", payload={})]
|
||||
|
||||
def move(self, payload: Dict[str, Any]) -> List[RobotStep]:
|
||||
return [RobotStep(action="move_to_pose", payload=payload)]
|
||||
|
||||
def reset_tool(self) -> List[RobotStep]:
|
||||
return [RobotStep(action="vacuum_off", payload={})]
|
||||
```
|
||||
|
||||
The `action` strings must match what your robot node understands.
|
||||
|
||||
## 2) Create robot actions
|
||||
|
||||
- File: `dora_voice_control/dora_voice_control/robots/<robot_name>/actions.py`
|
||||
- Use `ActionInfo` to define names, aliases, and requirements.
|
||||
|
||||
```python
|
||||
from ...core.behavior import ActionInfo
|
||||
|
||||
MY_ACTIONS = {
|
||||
"tomar": ActionInfo(name="tomar", aliases=["toma"], requires_object=False),
|
||||
"soltar": ActionInfo(name="soltar", aliases=["suelta"], requires_object=False),
|
||||
}
|
||||
```
|
||||
|
||||
## 3) Create robot behavior
|
||||
|
||||
- File: `dora_voice_control/dora_voice_control/robots/<robot_name>/behavior.py`
|
||||
- Subclass `RobotBehavior` and implement `action_handlers()`.
|
||||
|
||||
```python
|
||||
from typing import Callable
|
||||
from ...core.behavior import ActionContext, RobotBehavior
|
||||
from .actions import MY_ACTIONS
|
||||
|
||||
class MyRobotBehavior(RobotBehavior):
|
||||
ACTIONS = MY_ACTIONS
|
||||
|
||||
def action_tomar(self, ctx: ActionContext) -> bool:
|
||||
self._queue_steps(ctx, self.robot_adapter.grab())
|
||||
return True
|
||||
|
||||
def action_soltar(self, ctx: ActionContext) -> bool:
|
||||
self._queue_steps(ctx, self.robot_adapter.release())
|
||||
return True
|
||||
|
||||
def action_handlers(self) -> dict[str, Callable[[ActionContext], bool]]:
|
||||
return {
|
||||
"tomar": self.action_tomar,
|
||||
"soltar": self.action_soltar,
|
||||
}
|
||||
```
|
||||
|
||||
## 4) Register the robot
|
||||
|
||||
- File: `dora_voice_control/dora_voice_control/robots/__init__.py`
|
||||
|
||||
Add a resolver entry that maps `ROBOT_TYPE` to your adapter/behavior.
|
||||
|
||||
## 5) Update dataflow
|
||||
|
||||
Set `ROBOT_TYPE` in your dataflow:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
ROBOT_TYPE: "my_robot"
|
||||
```
|
||||
|
||||
## Safety notes
|
||||
|
||||
- Keep bounds checks in behavior methods (`_queue_move` already checks workspace limits).
|
||||
- For real hardware, validate with a staged plan: simulation → dry-run → full run.
|
||||
Reference in New Issue
Block a user