Gestures in the CB. #36

Merged
9828273 merged 16 commits from feat/cb2ri-gestures into dev 2025-12-16 09:24:26 +00:00
4 changed files with 45 additions and 25 deletions
Showing only changes of commit daf31ac6a6 - Show all commits

View File

@@ -36,10 +36,7 @@ class RobotGestureAgent(BaseAgent):
bind=False, bind=False,
gesture_data=None, gesture_data=None,
): ):
if gesture_data is None: self.gesture_data = gesture_data or []
self.gesture_data = []
else:
self.gesture_data = gesture_data
super().__init__(name) super().__init__(name)
self.address = address self.address = address
self.bind = bind self.bind = bind
@@ -71,7 +68,7 @@ class RobotGestureAgent(BaseAgent):
# REP socket for replying to gesture requests # REP socket for replying to gesture requests
self.repsocket = context.socket(zmq.REP) self.repsocket = context.socket(zmq.REP)
self.repsocket.bind("tcp://localhost:7788") self.repsocket.bind(settings.zmq_settings.internal_gesture_rep_adress)
self.add_behavior(self._zmq_command_loop()) self.add_behavior(self._zmq_command_loop())
self.add_behavior(self._fetch_gestures_loop()) self.add_behavior(self._fetch_gestures_loop())

View File

@@ -29,7 +29,7 @@ class RobotSpeechAgent(BaseAgent):
def __init__( def __init__(
self, self,
name: str, name: str,
address=settings.zmq_settings.ri_command_address, address: str,
bind=False, bind=False,
): ):
super().__init__(name) super().__init__(name)

View File

@@ -16,14 +16,40 @@ logger = logging.getLogger(__name__)
router = APIRouter() router = APIRouter()
@router.post("/command", status_code=202) @router.post("/command/speech", status_code=202)
async def receive_command(command: SpeechCommand, request: Request): async def receive_command_speech(command: SpeechCommand, request: Request):
""" """
Send a direct speech command to the robot. Send a direct speech command to the robot.
Publishes the command to the internal 'command' topic. The Publishes the command to the internal 'command' topic. The
:class:`~control_backend.agents.actuation.robot_speech_agent.RobotSpeechAgent` :class:`~control_backend.agents.actuation.robot_speech_agent.RobotSpeechAgent`
or will forward this to the robot.
:param command: The speech command payload.
:param request: The FastAPI request object.
"""
# Validate and retrieve data.
try:
validated = SpeechCommand.model_validate(command)
except ValidationError as e:
raise HTTPException(
status_code=422, detail=f"Payload is not valid SpeechCommand: {e}"
) from e
topic = b"command"
pub_socket: Socket = request.app.state.endpoints_pub_socket
await pub_socket.send_multipart([topic, validated.model_dump_json().encode()])
return {"status": "Speech command received"}
@router.post("/command/gesture", status_code=202)
async def receive_command_gesture(command: GestureCommand, request: Request):
"""
Send a direct gesture command to the robot.
Publishes the command to the internal 'command' topic. The
:class:`~control_backend.agents.actuation.robot_speech_agent.RobotGestureAgent` :class:`~control_backend.agents.actuation.robot_speech_agent.RobotGestureAgent`
will forward this to the robot. will forward this to the robot.
@@ -31,23 +57,19 @@ async def receive_command(command: SpeechCommand, request: Request):
:param request: The FastAPI request object. :param request: The FastAPI request object.
""" """
# Validate and retrieve data. # Validate and retrieve data.
validated = None
valid_commands = (GestureCommand, SpeechCommand)
for command_model in valid_commands:
try: try:
validated = command_model.model_validate(command) validated = GestureCommand.model_validate(command)
except ValidationError: except ValidationError as e:
continue raise HTTPException(
status_code=422, detail=f"Payload is not valid GestureCommand: {e}"
if validated is None: ) from e
raise HTTPException(status_code=422, detail="Payload is not valid for command models")
topic = b"command" topic = b"command"
pub_socket: Socket = request.app.state.endpoints_pub_socket pub_socket: Socket = request.app.state.endpoints_pub_socket
await pub_socket.send_multipart([topic, validated.model_dump_json().encode()]) await pub_socket.send_multipart([topic, validated.model_dump_json().encode()])
return {"status": "Command received"} return {"status": "Gesture command received"}
@router.get("/ping_check") @router.get("/ping_check")
@@ -58,8 +80,8 @@ async def ping(request: Request):
pass pass
@router.get("/get_available_gesture_tags") @router.get("/commands/gesture/tags")
async def get_available_gesture_tags(request: Request): async def get_available_gesture_tags(request: Request, count=0):
""" """
Endpoint to retrieve the available gesture tags for the robot. Endpoint to retrieve the available gesture tags for the robot.
@@ -67,10 +89,10 @@ async def get_available_gesture_tags(request: Request):
:return: A list of available gesture tags. :return: A list of available gesture tags.
""" """
req_socket = Context.instance().socket(zmq.REQ) req_socket = Context.instance().socket(zmq.REQ)
req_socket.connect("tcp://localhost:7788") req_socket.connect(request.app.state.gesture_rep_address)
# TODO: Implement a way to get a certain ammount from the UI, rather than everything. # Check to see if we've got any count given in the query parameter
amount = None amount = count or None
timeout = 5 # seconds timeout = 5 # seconds
await req_socket.send(f"{amount}".encode() if amount else b"None") await req_socket.send(f"{amount}".encode() if amount else b"None")

View File

@@ -17,6 +17,7 @@ class ZMQSettings(BaseModel):
internal_sub_address: str = "tcp://localhost:5561" internal_sub_address: str = "tcp://localhost:5561"
ri_command_address: str = "tcp://localhost:0000" ri_command_address: str = "tcp://localhost:0000"
ri_communication_address: str = "tcp://*:5555" ri_communication_address: str = "tcp://*:5555"
internal_gesture_rep_adress: str = "tcp://localhost:7788"
class AgentSettings(BaseModel): class AgentSettings(BaseModel):