hermes_bringup starts the face, camera, face detector and audio levels from one launch file with their parameters in robot.yaml, each node its own respawned process, the face first and the others after start_delay. robot.service runs it at boot, so everything is ROS and the face is up whenever the robot is powered. Reboot-tested: all services and nodes return by themselves, the face draws at about 28 s on the boot clock, the mic gain survives, nothing throttles. Cut the CPU: the camera runs at 15 fps (20% of a core, vs 40% at 30), and the detector went from 131% to 40% by pinning OpenCV to one thread (its DNN burns 3-4x its elapsed time across cores), decoding the JPEG at half size, and re-identifying a tracked face at most once a second. The audio scope is published only while someone is speaking or listening. A standalone face unit that skipped `ros2 launch` saved only 3.7 s and was dropped: the owner prefers everything in ROS and is fine with up to a minute. trim-boot.sh disables the unused snapd and ModemManager. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFN8nRRCiDiMN7ChBpHJhs
46 lines
2.2 KiB
Python
46 lines
2.2 KiB
Python
"""Bring up the robot: camera, face, face detection, audio levels.
|
|
|
|
ros2 launch hermes_bringup robot.launch.py [camera:=false] [face:=false] [vision:=false] [audio:=false]
|
|
[start_delay:=6.0]
|
|
|
|
Every node is its own process and is respawned if it exits, so one crash cannot take the others
|
|
down: the face keeps running when the camera does not. Parameters are in config/robot.yaml.
|
|
|
|
The face starts at once; the camera, vision and audio nodes wait start_delay seconds, so the four
|
|
Python processes do not fight over the CPU while the face imports and draws its first frame.
|
|
"""
|
|
import os
|
|
|
|
from ament_index_python.packages import get_package_share_directory
|
|
from launch import LaunchDescription
|
|
from launch.actions import DeclareLaunchArgument, TimerAction
|
|
from launch.conditions import IfCondition
|
|
from launch.substitutions import LaunchConfiguration
|
|
from launch_ros.actions import Node
|
|
|
|
# (launch argument, package, executable, node name in robot.yaml)
|
|
NODES = [
|
|
('camera', 'camera_ros', 'camera_node', 'camera'),
|
|
('face', 'hermes_face', 'face_node', 'hermes_face'),
|
|
('vision', 'hermes_vision', 'face_detector', 'hermes_face_detector'),
|
|
('audio', 'hermes_audio', 'audio_state', 'hermes_audio_state'),
|
|
]
|
|
|
|
|
|
DELAYED = {'camera', 'vision', 'audio'}
|
|
|
|
|
|
def generate_launch_description():
|
|
params = os.path.join(get_package_share_directory('hermes_bringup'), 'config', 'robot.yaml')
|
|
actions = [DeclareLaunchArgument(arg, default_value='true', description=f'run the {name} node')
|
|
for arg, _, _, name in NODES]
|
|
actions.append(DeclareLaunchArgument('start_delay', default_value='6.0',
|
|
description='seconds the camera, vision and audio wait for the face'))
|
|
for arg, package, executable, name in NODES:
|
|
node = Node(package=package, executable=executable, name=name, output='screen',
|
|
parameters=[params], respawn=True, respawn_delay=2.0,
|
|
condition=IfCondition(LaunchConfiguration(arg)))
|
|
actions.append(TimerAction(period=LaunchConfiguration('start_delay'), actions=[node])
|
|
if arg in DELAYED else node)
|
|
return LaunchDescription(actions)
|