yahboom
HomeTutorialsProduct
Solution
Blog
Online Store
About Us
EN/中文
Store
ROSMASTER M1 PRO📖
0.Robot Configuration and Operation Guidelines
  • 0.Unboxing and Review
  • 1.Assembly Videos
  • 2.User Manual
  • 3.Enter Docker (For Raspberry Pi)
  • 4.FAQ
  • 5.RobotManager User Guide
1.Chassis Control Course
  • 1.Robot Information Publishing
  • 2.Robot Handle Control
  • 3.Robot Keyboard Control
  • 4.Linear Velocity Calibration
  • 5.Angular Velocity Calibration
  • 6.Robot URDF Model
  • 7.Robot EKF State Estimation
2.Lidar Course
  • 1.Lidar Introduction And Use
  • 2.Lidar Obstacle Avoidance
  • 3.Lidar Following
  • 4.Lidar Guard
  • 5.Lidar Patrol
  • 6.GMapping-SLAM Mapping
  • 7.Cartographer-SLAM Mapping
  • 8.Slam-Toolbox Mapping
  • 9.Lifelong Mode Mapping
  • 10.Navigation2 Single Point Navigation
  • 11.Navigation2 Multi Point Navigation
  • 12.Cartographer Relocalization Navigation
  • 13.Slam-Toolbox Localization Navigation
  • 14.Synchronous Mapping And Navigation
  • 15.Aruco Visual Relocalization Navigation
  • 16.Mobile App Mapping And Navigation
3.USB Camera-Depth Camera Course
  • 1.USB Camera Introduction
  • 2.USB Camera Intrinsic Calibration
  • 3.Nuwa-HP60C Camera Introduction (Depth Camera Only)
  • 4.Depth Pseudo Color Image (Depth Camera Only)
  • 5.Depth Camera Distance Measurement (Depth Camera Only)
  • 6.Block Volume Calculation (Depth Camera Only)
  • 7.Edge Detection (Depth Camera Only)
  • 8.RTAB-Map SLAM Mapping (Depth Camera Only)
  • 9.RTAB-Map Navigation (Depth Camera Only)
4.Robotic Arm and 3D Space Gripping Course
  • 1.Robotic Arm Basic Usage
  • 2.Robotic Arm Kinematics
  • 3.Robotic Arm Chassis Coordination Control
  • 4.AprilTag ID Sorting
  • 5.AprilTag Height Anomaly Sorting
  • 6.AprilTag Tracking and Grasping
  • 7.Color Block Sorting
  • 8.Color Block Height Anomaly Sorting
  • 9.Color Block Tracking and Grasping
  • 10.Wood Block Shape Sorting
  • 11.KCF Tracking and Grasping Objects
  • 12.Mediapipe Gesture ID Sorting AprilTag
  • 13.Mediapipe Gesture Height Sorting AprilTag
  • 14.Desktop Tracking and Grasping AprilTag
  • 15.3D Spatial Tracking AprilTag
  • 16.Transformer Model Tracking Algorithm
  • 17.Line Following Obstacle Clearing
5.Road network planning and navigation
  • 1.Introduction To Road Network Planning
  • 2.Road Network Annotation
  • 3.Planning And Navigation Between Waypoints
  • 4.Road Network Navigation In Any Pose
  • 5.Path Re-planning
6.OpenClaw Basic Course
  • 1.Introduction to OpenClaw
  • 2.OpenClaw Core Concepts
  • 3.OpenClaw API-KEY Configuration
  • 4.OpenClaw Switch Models
  • 5.OpenClaw System Prompt Words
  • 6.OpenClaw Common CLI Commands
7.OpenClaw Interaction Method
  • 1.OpenClaw Webchat Interaction
  • 2.OpenClaw Tui Interaction
  • 3.OpenClaw Voice Dialogue Interaction
  • 4.OpenClaw WhatsApp Interaction
8.OpenClaw Development
  • 1.OpenClaw Connecting to Robot MCP Service
  • 2.Robot CLI Command Tool
  • 3.robot-control Plugin Tool
  • 4.reply-bridge Plugin Tool
  • 5.OpenClaw Multimodal Vision
  • 6.OpenClaw Chassis Control
  • 7.OpenClaw Robotic Arm Control
  • 8.OpenClaw Skills Development
  • 9.OpenClaw Scheduled Tasks
  • 10.OpenClaw Multi-Agent Intelligent Agent
  • 11.OpenClaw Active Interaction
  • 12.OpenClaw Vector Memory
9.OpenClaw Embodied intelligent application
  • 1.OpenClaw Target Tracking
  • 2.OpenClaw Arm Tracking And Grasping
  • 3.OpenClaw Arm Fixed-point Placement
  • 4.OpenClaw Waste Sorting
  • 5.OpenClaw SLAM Mapping And Navigation
  • 6.OpenClaw Navigation Transport
  • 7.OpenClaw AprilTag Grasping
  • 8.OpenClaw Color Line Patrol
  • 9.OpenClaw Visual Distance Measurement
10.OpenClaw scenario sandbox
  • 1.Map Description and Props Placement
  • 2.Building the Sandbox Map
  • 3.Visual Relocalization Marker
  • 4.Map Mapping Marker
  • 5.Sandbox Scenario Comprehensive Case
11.AI Large Model Basics
  • 1.AI Large Model Types and Principles
  • 2.RAG Retrieval Enhancement and Model Training Samples
  • 3.Embodied Intelligent Robot System Architecture
  • 4.Embodied Intelligent Functions Core Source Code
12.AI large Model Development
  • 1.Register a Model Service Provider Account
  • 2.Configuring API-KEY
  • 3.Introduction to Dify
  • 4.Basic Dify Features
  • 5.AI Large Model Development - Chatbot
  • 6.Deploy the RAG Knowledge Base
  • 7.RAG Knowledge Base + Chatbot
  • 8.AI Agent Workflow
  • 9.Custom Wake-up Response
13.AI Model - Voice Version
  • 1.Semantic Understanding and Command Following
  • 2.Multimodal Visual Understanding
  • 3.Multimodal Visual Understanding and Robotic Arm Gripping
  • 4.Multimodal Visual Understanding and SLAM Navigation
  • 5.Robotic arm gripping+Multimodal visual understand+SLAM navigation
  • 6.Intention Understanding
14.AI Model - Text Version
  • 1.Semantic Understanding and Command Following
  • 2.Multimodal Visual Understanding
  • 3.Multimodal Visual Understanding and Robotic Arm Gripping
  • 4.Multimodal Visual Understanding and SLAM Navigation
  • 5.Robotic arm gripping+Multimodal visual understand+SLAM navigation
  • 6.Intention estimation
15.Mediapipe Visual Course
  • 1.Hand detection
  • 2.Posture detection
  • 3.Overall detection
  • 4.Facial Landmark Detection
  • 5.Face detection
  • 6.Face special effects
  • 7.3D object recognition
  • 8.Brush
  • 9.Finger control
  • 10.Palm target positioning
  • 11.Fingertip trajectory recognition
  • 12.Fingertip gesture control robotic arm
  • 13.Gesture grabbing and releasing objects
  • 14.Finger control robotic arm
  • 15.Medipipe gesture control robotic arm action group
16.MoveIt2 Simulation Course
  • 1.MovelT2 configuration
  • 2.MovelT2 simulation-reality linkage
  • 3.Random movement
  • 4.Forward kinematics design
  • 5.Inverse kinematics design
  • 6.Cartesian path
  • 7.Trajectory Planning
  • 8.Collision Detection
  • 9.Scene Design
  • 10.3D perception obstacle‑avoidance
17.Multi-vehicle Course
  • 1.Multi-vehicle Control
  • 2.Multi-vehicle Navigation
  • 3.Multi-vehicle Formation
18.YOLO26 Development
  • 1.CLI Use
  • 2.Object Detection
  • 3.Instance Segmentation
  • 4.Pose Estimation
  • 5.Image Classification
  • 6.Oriented Object Detection
  • 7.YOLOv26 + DeepSORT Tracking
  • 8.Monocular Depth Estimation
19.Control Board STM32 Driver Course
  • 0.Notes (Must Read)
  • 1.About Expansion Board
  • 2.STM32 Development Environment
  • 3.Button Control
  • 4.FreeRTOS Application
  • 5.Serial Communication
  • 6.SBUS Model Aircraft Remote Control
  • 7.CAN Bus Communication
  • 8.RGB Colorful Light Bar
  • 9.Timer Interrupt to Control PWM Servo
  • 10.Control Serial Port Servos
  • 11.Nine-axis Attitude Sensor to Obtain Data
  • 12.Control Motor
  • 13.Timer Captures the Encoder Data
  • 14.1 Kinematic Analysis of Mecanum Wheel
  • 14.2 Kinematic Analysis of Ackerman
  • 14.3 Kinematic Analysis of 4WD
  • 15.PID Control Robot Movement
20.Docker Course
  • 1.Docker Introduction and Installation
  • 2.Docker Basic Commands
  • 3.Docker Submission and Multi-Terminal Access
  • 4. Docker Startup Script
  • 5.Docker-Vscode Environment Construction
21.Image Processing Basics Course
  • 1. Introduction to Open Source CV
  • 2. Image reading and display
  • 3. Image writing
  • 4. Image quality
  • 5. Pixel Operation
  • 6. Image zoom
  • 7. Image cutting
  • 8. Image translation
  • 9. Image Mirroring
  • 10. Affine Transformation
  • 11. Image Rotation
  • 12. Perspective Transformation
  • 13. Grayscale processing
  • 14. Image Binarization
  • 15. Edge Detection
  • 16. Line drawing
  • 17. Rectangle and circle drawing
  • 18. Drawing text and pictures
22.Linux System Course
  • 1.Introduction to Linux system
  • 2.Ubuntu file system
  • 3.Ubuntu common commands
  • 4.Ubuntu common editors
  • 5.Ubuntu software operation commands
  • 6.Virtual machine installation
  • 7.SSH remote control
  • 8.VNC remote control
  • 9.Transfer files remotely
  • 10.Driver library and communication
  • 11.Static IP and hotspot mode
  • 12.Bind device ID
  • 13.Capacity expansion and resource allocation
  • 14.Update system software sources
  • 15.Set root user password
  • 16.sudo free password
  • 17.Connect to WiFi network
  • 18.View system version
  • 19.Customized service management
  • 20.Back up system image
23.ROS2 Basic Course
  • 1.Introduction to ROS2
  • 2.ROS2 install Humble
  • 3.ROS2 development environment
  • 4.ROS2 workspace
  • 5.ROS2 function package
  • 6.ROS2 node
  • 7.ROS2 topic communication
  • 8.ROS2 service communication
  • 9.ROS2 action communication
  • 10.ROS2 custom interface message
  • 11.ROS2 parameter service case
  • 12.ROS2 meta-function package
  • 13.ROS2 distributed communication
  • 14.ROS2 DDS
  • 15.ROS2 time related API
  • 16.ROS2 common command tools
  • 17.ROS2 rviz2 use
  • 18.ROS2 rqt toolbox
  • 19.ROS2 Launch startup file configuration
  • 20.ROS2 recording and playback tool
  • 21.ROS2 URDF model
  • 22.ROS2 Gazebo simulation platform
  • 23.ROS2 TF2 coordinate transformation
24.Main Control Course
Jetson Orin Nano_NX
  • 1.Jetson Orin board introduction
  • 2.Restore the factory image system
  • 3.Backup SSD system
  • 4.SSD expansion
  • 5.Network configuration
  • 6.SSH remote login
  • 7.VNC remote control
  • 8.Remote file transfer
  • 9.Jtop tool
  • 10.Exchange space expansion
Raspberry Pi
  • 1. Introduction to Raspberry PI 5
  • 2. Raspberry PI system installation and backup
  • 3. Powering the Raspberry PI 5
  • 4. Startup of Raspberry PI 5
  • 5. Update and upgrade operating system
  • 6. Introduction to raspi-config tool
  • 7. config.txt file description
  • 8. Network Configuration
  • 9. remote access
  • 10. Transfer files remotely
  • 11. Set display resolution and rotation
  • 12. Set screen to sleep
  • 13. Play audio and video
  • 14. Using USB camera
  • 15. Using MIPI camera
  • 16. Get real-time temperature of Raspberry Pi
RDKX5
  • 1.Introduction to RDK X5 board
  • 2.Write system file
  • 3.Hardware interface description
  • 4.Install case and other accessories
  • 5.Network configuration
  • 6.Remote login
  • 7.Update system
  • 8.srpi-config user guide
  • 9.config. txt configuration file
  • 10.Self-startup setting
  • 11.RDK exclusive command usage
  • 12.Linux command usage
  • 13.GPIO readwrite operation
  • 14.Image classification algorithm
  • 15.Use USB camera
  • 16.Use MIPI camera
  • 17.Binocular camera depth algorithm
  • 18. Controlling RGB Cooling Fans
Download
  • System File
  • Code
  • 3D Model File
  • Software Tools
  • Hardware_Info
  • Deb function package
  • Dify AI Agent
Download ZIP

Welcome to ROSMASTER M1 PRO repository

4.reply-bridge Plugin Tool

reply-bridge Plugin Tool

reply-bridge Plugin Tool1. Course ContentCourse OverviewLearning Objectives3. reply-bridge Plugin Introduction4. Case Demonstration5. Source Code Analysis5.1 Plugin Entry and Hook Registration5.2 TTS Tag Extraction and Deduplication Mechanism5.3 TTS Server

1. Course Content

Course Overview

  • The reply-bridge plugin is the speech synthesis bridge plugin of OpenClaw. It listens to OpenClaw's AI reply messages, parses the <tts>...</tts> voice tag from them, automatically calls the TTS tool on the MCP server for speech synthesis, and broadcasts through the USB audio device.

  • Used together with the robot-control plugin, it enables voice dialogue interaction with the robot, letting the robot "speak".

Learning Objectives

  1. Understand the features of the reply-bridge plugin

  2. Master how to install, view, and perform basic management operations on plugins

  3. Understand the working principle of the plugin calling TTS speech synthesis through the MCP protocol

  4. Be able to use the <tts> tag to implement the voice broadcast feature in OpenClaw interaction scenarios

 

3. reply-bridge Plugin Introduction

The reply-bridge plugin is a speech synthesis bridge plugin adapted for the OpenClaw robot side. Its working principle is as follows:

  • Listening mechanism: The plugin registers two Hooks, before_message_write and message_sending, to listen for the <tts>...</tts> tag in AI reply messages

  • Text extraction: When an AI reply contains <tts>tag text</tts>, the plugin automatically extracts the text content within the tag

  • Speech synthesis: Through the built-in MCP client, it calls the TTS tool on the MCP server to convert the text into speech

  • Audio broadcast: The MCP server calls the TTS engine through the openclaw_bridge node, and finally broadcasts the speech through the USB audio device

  • Deduplication mechanism: The plugin has a built-in session-level deduplication mechanism, so the same TTS text is not broadcast repeatedly within a session, avoiding redundant speech

The plugin communication architecture is as follows:

                                                        ┌───────────────────────────┐
                                                        │          OpenClaw         │
                                                        └─────────────┬─────────────┘
                                                                      │
                                                                      ▼
                                                        ┌───────────────────────────┐
                                                        │        reply-bridge       │
                                                        │           Plugin          │
                                                        └─────────────┬─────────────┘
                                                                      │MCP Protocol
                                                                      ▼
                                                        ┌───────────────────────────┐
                                                        │         MCP Server        │
                                                        └─────────────┬─────────────┘
                                                                      │
                                                                      ▼
                                                        ┌───────────────────────────┐
                                                        │      openclaw_bridge      │
                                                        └─────────────┬─────────────┘
                                                                      │
                                                                      ▼
                                                        ┌───────────────────────────┐
                                                        │         TTS Engine        │
                                                        └─────────────┬─────────────┘
                                                                      │
                                                                      ▼
                                                        ┌───────────────────────────┐
                                                        │      USB Audio Device     │
                                                        └───────────────────────────┘

 

4. Case Demonstration

  • Refer to the prerequisite chapter 【OpenClaw Interaction Method】—【OpenClaw Voice Dialogue Interaction】 for the dialogue feature; this section only explains the implementation principle of the voice dialogue feature

     

5. Source Code Analysis

5.1 Plugin Entry and Hook Registration

Source code directory:

xxxxxxxxxx
$HOME/.openclaw/extensions/reply-bridge/index.ts

The plugin source code is located in index.ts under the plugin directory. It uses the registerReplyBridge function as the entry point and registers event listening Hooks using the OpenClaw Plugin API. The core code is as follows:

​x
export default function registerReplyBridge(api: OpenClawPluginApi) {
  // Hook: before_message_write — triggered whenever a message is written to the session record
  api.on("before_message_write", (event, ctx) => {
    const message = event.message as AgentMessage;
    const sessionId = ctx.sessionId;

    // Only handle messages with the assistant role
    if (message.role !== "assistant") return;

    const text = extractTextFromAgentMessage(message);
    if (!text) return;

    const ttsTexts = extractTtsTags(text);
    if (ttsTexts.length === 0) return;

    api.logger.info(`[reply-bridge] extracted ${ttsTexts.length} TTS segment(s)`);
    sendTtsTextsFireAndForget(ttsTexts, sessionId, (msg) => api.logger.info(msg));
  });

  api.logger.info("reply-bridge: Plugin registered (hooks: before_message_write, message_sending)");
}

Code Description:

  1. Registration entry: export default function registerReplyBridge(api) is the plugin's default export function. OpenClaw calls it automatically when loading the plugin, passing in the OpenClawPluginApi instance

  2. api.on("before_message_write"): Registers the pre-message-write Hook, triggered when the AI generates a reply and writes it to the session record; this is the main channel for TTS processing

  3. Role filtering: message.role !== "assistant" ensures that only AI assistant reply messages are processed, ignoring user messages

  4. Extraction flow: extractTextFromAgentMessage → extractTtsTags → sendTtsTextsFireAndForget, three steps completing the full pipeline from message text to TTS broadcast

  5. fire-and-forget mode: TTS calls use fire-and-forget mode, not blocking the message write flow, ensuring a smooth user experience

Key Function Description:

  • extractTextFromAgentMessage(message): Extracts the plain text content from the AgentMessage object, handling the multimodal content that the message may contain (text, images, etc.)

  • extractTtsTags(text): Parses all content within <tts>...</tts> tags from the text and returns a list of TTS text segments

  • sendTtsTextsFireAndForget(ttsTexts, sessionId, logger): Asynchronously sends the extracted TTS text to the MCP server for speech synthesis, using fire-and-forget mode so as not to block the main flow

  • ctx.sessionId: The current session ID, used for session-level TTS deduplication, ensuring the same text is not broadcast repeatedly within the same session

5.2 TTS Tag Extraction and Deduplication Mechanism

The code for the plugin to extract the content of the <tts> tag from the AI reply text is as follows:

xxxxxxxxxx
/**
 * Extract plain text segments wrapped in <tts>...</tts> tags
 * Uses indexOf instead of regular expressions to avoid pattern matching boundary issues
 */
function extractTtsTags(content: string): string[] {
  const matches: string[] = [];
  const openTag = "<tts>";
  const closeTag = "</tts>";
  let start = 0;

  while (true) {
    const openIdx = content.indexOf(openTag, start);
    if (openIdx === -1) break;
    const closeIdx = content.indexOf(closeTag, openIdx + openTag.length);
    if (closeIdx === -1) break;
    const text = content.slice(openIdx + openTag.length, closeIdx).trim();
    if (text) matches.push(text);
    start = closeIdx + closeTag.length;
  }

  return matches;
}

Code Description:

  1. extractTtsTags(): Uses indexOf to scan the text segment by segment, extracting all content within <tts>...</tts> tags. indexOf is chosen over regular expressions to avoid boundary issues with special characters and nested pattern matching, improving parsing stability

  2. Deduplication mechanism: Records the text already broadcast for each session through sentTtsTexts (Map<string, Set<string>>), so the same text is not broadcast repeatedly within a session, avoiding redundant speech

Code Detail Description:

  • indexOf(openTag, start): Searches for the <tts> opening tag starting from the start position, returning the tag's starting index, or -1 if not found

  • indexOf(closeTag, openIdx + openTag.length): Searches for the </tts> closing tag after the opening tag, ensuring correct matching of the nearest closing position

  • content.slice(openIdx + openTag.length, closeIdx).trim(): Extracts the text content between the opening and closing tags and removes leading and trailing whitespace

  • start = closeIdx + closeTag.length: Updates the search start position to after the closing tag, supporting multiple <tts> tags in the same text

  • sentTtsTexts: A Map<sessionId, Set<text>> structure, keyed by session ID with the set of broadcast texts as the value, achieving session-level deduplication

5.3 TTS Server

xxxxxxxxxx
~/yahboomcar_ros2_ws/yahboomcar_ws/src/multi_brains_pre/multi_brains_pre/openclaw_bridge.py

 

  • init_tts_engine: Initialize the TTS speech synthesis engine

    • When USE_OLINE_TTS is False: Load the local PiperTTS engine and use offline speech synthesis

    • When tts_supplier is aliyun: Load TongyiTTS (Alibaba Cloud Tongyi), requiring configuration of the API Key, model, and voice timbre

    • When tts_supplier is xunfei: Load XunfeiTTS (iFlytek), requiring configuration of the key path and encryption key

  • _process_tts_queue: TTS queue processing worker thread

    • Loops to check the stop flag, and gets the text to be synthesized from the queue (timeout 0.5s)

    • Calls _handle_tts to process each piece of text

  • _handle_tts: Handle a single TTS request

    • Waits for the play_audio Action server to be ready

    • Calls tts_engine.synthesize to synthesize the text into an audio file

    • Sends the PlayAudio Action goal, handling goal acceptance/rejection through callbacks

    • Waits for playback to complete, checking the stop flag during this period, and supports canceling the ongoing playback

Code Detail Description:

  • self.USE_OLINE_TTS: Offline TTS switch; when False, it loads the local PiperTTS engine, and when True, it loads the online engine according to tts_supplier

  • self.tts_supplier: Online TTS provider selection, supporting aliyun (Alibaba Cloud Tongyi) and xunfei (iFlytek)

  • self.tts_engine.synthesize(text, self.tts_out_path): Calls the TTS engine to synthesize the text into an audio file, saving it to the tts_out_path path

  • self.audio_client.wait_for_server(timeout_sec=3.0): Waits for the play_audio Action server to come online; if it times out after 3 seconds, it skips this broadcast

  • PlayAudio.Goal(): Constructs the Action goal message for playing audio, with file_path specifying the synthesized audio file path

  • _goal_response_cb: Action goal send callback; checks whether the server accepts the goal, and if rejected, logs a warning and ends

  • _tts_goal_handle_lock: Thread lock protecting concurrent access to _current_tts_goal_handle, ensuring the safety of cancellation operations

  • _result_cb: Action execution completion callback; clears the current goal handle and sets done_event to notify the main thread

  • done_event.wait(timeout=0.1): The main loop polls the playback completion status at 0.1-second intervals, checking the stop flag during this period to support canceling playback

  • gh.cancel_goal_async(): When the stop flag is detected, asynchronously cancels the currently playing Action goal

xxxxxxxxxx

    def init_tts_engine(self):
        if not self.USE_OLINE_TTS:
            from multi_brains_pre.utils.tts import  PiperTTS
            self.tts_engine=PiperTTS(self.language)
            if self.tts_engine.init_tts_engine() :
                self.get_logger().info(Fore.GREEN+"Piper TTS_Engine initialized successfully"+Fore.RESET)
            else:
                error_msg="Piper TTS_Engine initialized failed"
                
                self.get_logger().error(Fore.RED+error_msg+Fore.RESET)
                raise RuntimeError(error_msg)
            return
        
        if self.tts_supplier=="aliyun":
            from multi_brains_pre.utils.tts import TongyiTTS
            self.tts_engine=TongyiTTS(self.aliyun_api_key,self.tts_model,self.tts_voice_tone)
            result=self.tts_engine.init_tts_engine()
            if result[0]:
                self.get_logger().info(Fore.GREEN+"Tongyi TTS_Engine initialized successfully"+Fore.RESET)
            else:
                self.get_logger().error(Fore.RED+f"Tongyi TTS_Engine initialized failed:{result[1]}"+Fore.RESET)
                
                raise RuntimeError(f"Tongyi TTS_Engine initialized failed:{result[1]}")


        elif self.tts_supplier=="xunfei":
            from multi_brains_pre.utils.tts import  XunfeiTTS
            self.tts_engine=XunfeiTTS(self.key_path,self.xunfei_encrypted_key,self.config_file)

            if self.tts_engine.init_tts_engine():
                self.get_logger().info(Fore.GREEN+"Xunfei TTS_Engine initialized successfully"+Fore.RESET)
            else:
                
                error_msg="Xunfei TTS_Engine initialized failed"
                self.get_logger().error(Fore.RED+error_msg+Fore.RESET)
                raise RuntimeError(error_msg)
    def _process_tts_queue(self):
        """TTS """
        while not self._tts_worker_stop_event.is_set():
            try:
                text = self._tts_queue.get(timeout=0.5)
            except queue.Empty:
                continue
            self._handle_tts(text)

    def _handle_tts(self, text: str):
        if not self.audio_client.wait_for_server(timeout_sec=3.0):
            self.get_logger().warn(Fore.YELLOW + "play_audio action server not available, skip voice" + Fore.RESET)
            return
        if not self.tts_engine.synthesize(text, self.tts_out_path):
            self.get_logger().error(Fore.RED + "Speech synthesis failed. Check whether the TTS model is available" + Fore.RESET)
            return
        
        goal = PlayAudio.Goal()
        goal.file_path = self.tts_out_path
        
        done_event = threading.Event()
        
        def _goal_response_cb(future):
            goal_handle = future.result()
            if not goal_handle or not goal_handle.accepted:
                self.get_logger().warn("TTS play goal rejected")
                done_event.set()
                return
            with self._tts_goal_handle_lock:
                if self._tts_worker_stop_event.is_set():
                    goal_handle.cancel_goal_async()
                    done_event.set()
                    return
                self._current_tts_goal_handle = goal_handle
            result_future = goal_handle.get_result_async()
            result_future.add_done_callback(_result_cb)
        
        def _result_cb(future):
            with self._tts_goal_handle_lock:
                self._current_tts_goal_handle = None
            done_event.set()
        
        send_future = self.audio_client.send_goal_async(goal)
        send_future.add_done_callback(_goal_response_cb)
        
        while not done_event.wait(timeout=0.1):
            if self._tts_worker_stop_event.is_set():
                with self._tts_goal_handle_lock:
                    gh = self._current_tts_goal_handle
                if gh is not None:
                    gh.cancel_goal_async()
                break
        

 

robot-control Plugin Tool
OpenClaw Multimodal Vision

COMPANY

  • About us
  • Team Style
  • Blog

LEARNING & EXPLORATION

  • Tutorials
  • Edge AI hardware
  • Educational robots
  • Embedded intelligent hardware

WHERE TO BUY

  • Yahboom Online Store
  • Amazon
  • Alibaba
  • AliExpress
  • Mercado

TECHNOLOGY SUPPORT

  • Email: support@yahboom.com

BE A DISTRIBUTOR

  • Email: sales@yahboom.com
QR Code

Copyright © 2017-2026 Yahboom. All Rights Reserved.

EN/中文