From 03954bef5484badbfdada1117b535524dda126bd Mon Sep 17 00:00:00 2001 From: JobvAlewijk Date: Sun, 4 Jan 2026 19:47:18 +0100 Subject: [PATCH] feat: face recognition agent ref: N25B-397 --- .../communication/ri_communication_agent.py | 9 +++- .../agents/perception/face_rec_agent | 53 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/control_backend/agents/perception/face_rec_agent diff --git a/src/control_backend/agents/communication/ri_communication_agent.py b/src/control_backend/agents/communication/ri_communication_agent.py index 34e5b25..9aaf0db 100644 --- a/src/control_backend/agents/communication/ri_communication_agent.py +++ b/src/control_backend/agents/communication/ri_communication_agent.py @@ -10,7 +10,7 @@ from control_backend.agents.actuation.robot_gesture_agent import RobotGestureAge from control_backend.core.config import settings from ..actuation.robot_speech_agent import RobotSpeechAgent -from ..perception import VADAgent +from ..perception import FacePerceptionAgent, VADAgent class RICommunicationAgent(BaseAgent): @@ -201,6 +201,13 @@ class RICommunicationAgent(BaseAgent): case "audio": vad_agent = VADAgent(audio_in_address=addr, audio_in_bind=bind) await vad_agent.start() + case "face": + face_agent = FacePerceptionAgent( + settings.agent_settings.face_agent_name, + address=addr, + bind=bind, + ) + await face_agent.start() case _: self.logger.warning("Unhandled negotiation id: %s", id) diff --git a/src/control_backend/agents/perception/face_rec_agent b/src/control_backend/agents/perception/face_rec_agent new file mode 100644 index 0000000..ddb7433 --- /dev/null +++ b/src/control_backend/agents/perception/face_rec_agent @@ -0,0 +1,53 @@ +import asyncio +import zmq +import zmq.asyncio as azmq + +from control_backend.agents import BaseAgent +from control_backend.core.config import settings + + +class FacePerceptionAgent(BaseAgent): + """ + Receives and processes face detection events from Pepper. + """ + + def __init__(self, name, address, bind=False): + super().__init__(name) + self._address = address + self._bind = bind + self._socket: azmq.Socket | None = None + + async def setup(self): + self.logger.info("Starting FacePerceptionAgent") + + ctx = azmq.Context.instance() + self._socket = ctx.socket(zmq.SUB) + self._socket.setsockopt_string(zmq.SUBSCRIBE, "") + + if self._bind: + self._socket.bind(self._address) + else: + self._socket.connect(self._address) + + self.add_behavior(self._listen_loop()) + + async def _listen_loop(self): + while self._running: + try: + msg = await self._socket.recv_json() + await self._process_face_data(msg) + except Exception: + self.logger.exception("Error receiving face data") + + async def _process_face_data(self, data: dict): + """ + Central place to handle face perception. + """ + face_count = data.get("face_count", 0) + + if face_count > 0: + self.logger.debug("Detected %d face(s)", face_count) + + #Post belief + else: + self.logger.debug("No faces detected")