feat: publish face detection instead of req/res

ref: N25B-395
This commit is contained in:
Twirre Meulenbelt
2026-01-29 17:18:39 +01:00
parent 3bbe97579d
commit 815fc7bcde
2 changed files with 21 additions and 56 deletions

View File

@@ -19,6 +19,8 @@ class AgentSettings(object):
:vartype audio_sender_port: int
:ivar face_detection_port: Port used for sending face detection events, defaults to 5559.
:vartype face_detection_port: int
:ivar face_detection_interval: Time between face detection events, defaults to 1000 ms.
:vartype face_detection_interval: int
"""
def __init__(
self,
@@ -28,6 +30,7 @@ class AgentSettings(object):
video_sender_port=None,
audio_sender_port=None,
face_detection_port=None,
face_detection_interval=None,
):
self.control_backend_host = get_config(control_backend_host, "AGENT__CONTROL_BACKEND_HOST", "localhost")
self.actuation_receiver_port = get_config(actuation_receiver_port, "AGENT__ACTUATION_RECEIVER_PORT", 5557, int)
@@ -35,6 +38,7 @@ class AgentSettings(object):
self.video_sender_port = get_config(video_sender_port, "AGENT__VIDEO_SENDER_PORT", 5556, int)
self.audio_sender_port = get_config(audio_sender_port, "AGENT__AUDIO_SENDER_PORT", 5558, int)
self.face_detection_port = get_config(face_detection_port, "AGENT__FACE_DETECTION_PORT", 5559, int)
self.face_detection_interval = get_config(face_detection_interval, "AGENT__FACE_DETECTION_INTERVAL", 1000, int)
class VideoConfig(object):

View File

@@ -13,61 +13,47 @@ from robot_interface.core.config import settings
class FaceDetectionSender(SocketBase):
"""
Face detection REP endpoint.
Face detection endpoint.
- Polls ALMemory["FaceDetected"]
- Maintains a rolling boolean state
- Responds to REQ polling over ZMQ REP
Subscribes to and polls ALMemory["FaceDetected"], sends events to CB.
"""
def __init__(self, zmq_context, port=settings.agent_settings.face_detection_port):
super(FaceDetectionSender, self).__init__("face")
if port:
self.create_socket(zmq_context, zmq.REP, port)
self.create_socket(zmq_context, zmq.PUB, port)
self._face_service = None
self._memory_service = None
self.face_detected = False
self._last_seen_face_time = 0
self._face_thread = None
self._rep_thread = None
def endpoint_description(self):
return "face"
# ------------------------------------------------------------------
# Face detection logic (runs independently)
# ------------------------------------------------------------------
def start_face_detection(self):
if not state.qi_session:
logging.warning("No Qi session available. Face detection not started.")
return
import qi
self._face_service = state.qi_session.service("ALFaceDetection")
self._memory_service = state.qi_session.service("ALMemory")
self._face_service.setTrackingEnabled(False)
self._face_service.setRecognitionEnabled(False)
self._face_service.subscribe("FaceDetectionSender", 500, 0.0)
self._face_service.subscribe(
"FaceDetectionSender",
settings.agent_settings.face_detection_interval,
0.0,
)
self._face_thread = threading.Thread(target=self._face_loop)
self._face_thread.start()
self._rep_thread = threading.Thread(target=self._rep_loop)
self._rep_thread.start()
logging.info("Face detection + REP endpoint started.")
logging.info("Face detection started.")
def _face_loop(self):
"""
Continuously updates `self.face_detected`.
Continuously send face detected to the CB, at the interval set in the
``start_face_detection`` method.
"""
while not state.exit_event.is_set():
try:
@@ -81,40 +67,11 @@ class FaceDetectionSender(SocketBase):
and len(value[1][0]) > 0
)
now = time.time()
if face_present:
self._last_seen_face_time = now
# Face considered lost after 3 seconds
self.face_detected = (now - self._last_seen_face_time) < 3
self.socket.send(json.dumps({"face_detected": face_present}).encode("utf-8"))
except Exception:
logging.exception("Error reading FaceDetected")
time.sleep(0.1)
def _rep_loop(self):
"""
Handles ZMQ REQ/REP polling from the Control Backend.
"""
while not state.exit_event.is_set():
try:
# Receive request (content ignored)
_ = self.socket.recv()
# Respond with current face state
response = {
"endpoint": "face",
"data": self.face_detected,
}
self.socket.send_json(response)
except Exception:
logging.exception("Error in face detection REP loop")
time.sleep(0.1)
time.sleep(settings.agent_settings.face_detection_interval / 1000.0)
def stop_face_detection(self):
try:
@@ -124,3 +81,7 @@ class FaceDetectionSender(SocketBase):
logging.info("Face detection stopped.")
except Exception:
logging.warning("Error during face detection cleanup.")
def close(self):
super(FaceDetectionSender, self).close()
self.stop_face_detection()