7#include <condition_variable>
10#include <rclcpp/rclcpp.hpp>
11#include <pluginlib/class_loader.hpp>
13#include <opencv2/opencv.hpp>
14#include <cv_bridge/cv_bridge.hpp>
36#include <fp_perception_msgs/msg/perception_audio.hpp>
37#include <fp_perception_msgs/msg/perception_text.hpp>
38#include <fp_perception_msgs/srv/perception_speech.hpp>
39#include <fp_perception_msgs/srv/perception_transcribe.hpp>
40#include <fp_perception_msgs/srv/perception_sentiment.hpp>
41#include <fp_perception_msgs/srv/perception_image_analysis.hpp>
57 using Audio = fp_perception_msgs::msg::PerceptionAudio;
58 using Speech = fp_perception_msgs::srv::PerceptionSpeech;
59 using Transcribe = fp_perception_msgs::srv::PerceptionTranscribe;
60 using Sentiment = fp_perception_msgs::srv::PerceptionSentiment;
64 "vision driver",
"VisionSourceDriver" };
66 "vision driver",
"VisionSourceDriver" };
68 "microphone driver",
"AudioSourceDriver" };
70 "speaker driver",
"AudioSinkDriver" };
72 "transcription driver",
"TranscriptionDriver" };
74 "speech synthesis driver",
"SpeechSynthesisDriver" };
76 "sentiment driver",
"SentimentAnalysisDriver" };
78 "fp_perception::OpenAIImageAnalysisDriver",
79 "image analysis driver",
"ImageAnalysisDriver" };
87 : Node(
"perception_server", options),
driver_loader_(
"fp_perception",
"fp_perception::DriverBase")
103 RCLCPP_INFO(this->get_logger(),
"Initializing PerceptionServer...");
130 std::placeholders::_1, std::placeholders::_2));
161 catch (
const std::exception& e)
163 RCLCPP_ERROR(this->get_logger(),
"Deferred initialization failed: %s", e.what());
187 this->declare_parameter(
"use_ros_vision_driver",
false);
188 this->declare_parameter(
"use_non_ros_vision_driver",
false);
189 this->declare_parameter(
"use_microphone_driver",
false);
190 this->declare_parameter(
"use_speaker_driver",
false);
191 this->declare_parameter(
"use_transcription_driver",
false);
192 this->declare_parameter(
"use_sentiment_driver",
false);
193 this->declare_parameter(
"use_speech_driver",
false);
194 this->declare_parameter(
"use_image_analysis_driver",
false);
195 this->declare_parameter(
"use_diagnostics",
false);
196 this->declare_parameter(
"run_tests",
false);
206 run_tests_ = this->get_parameter(
"run_tests").as_bool();
211 this->declare_parameter(
"interface.audio_input.topic",
"perception/microphone");
212 this->declare_parameter(
"interface.audio_input.frame_id",
"microphone_frame");
213 this->declare_parameter(
"interface.audio_input.publish",
false);
214 this->declare_parameter(
"interface.audio_input.frequency", 10);
215 this->declare_parameter(
"interface.audio_input.audio_retention_window", 10);
216 this->declare_parameter(
"interface.audio_input.default_audio_request_window", 10);
218 this->declare_parameter(
"interface.audio_output.topic",
"perception/speaker");
219 this->declare_parameter(
"interface.audio_output.subscribe",
false);
221 this->declare_parameter(
"interface.vision_input.topic",
"perception/camera");
222 this->declare_parameter(
"interface.vision_input.frame_id",
"camera_frame");
223 this->declare_parameter(
"interface.vision_input.publish",
false);
224 this->declare_parameter(
"interface.vision_input.frequency", 10);
226 this->declare_parameter(
"interface.transcription.service",
"perception/transcription");
227 this->declare_parameter(
"interface.transcription.provide_service",
false);
229 this->declare_parameter(
"interface.speech.service_name",
"perception/speech");
230 this->declare_parameter(
"interface.speech.provide_service",
false);
232 this->declare_parameter(
"interface.sentiment.service_name",
"perception/sentiment_analysis");
233 this->declare_parameter(
"interface.sentiment.provide_service",
false);
235 this->declare_parameter(
"interface.image_analysis.service_name",
"perception/image_analysis");
236 this->declare_parameter(
"interface.image_analysis.provide_service",
false);
257 speech_enabled_ = this->get_parameter(
"interface.speech.provide_service").as_bool();
260 sentiment_enabled_ = this->get_parameter(
"interface.sentiment.provide_service").as_bool();
265 RCLCPP_INFO(this->get_logger(),
"Audio input publish: %s",
audio_input_publish_ ?
"true" :
"false");
275 RCLCPP_INFO(this->get_logger(),
"Vision input publish: %s",
vision_input_publish_ ?
"true" :
"false");
282 RCLCPP_INFO(this->get_logger(),
"Speech synthesis enabled: %s",
speech_enabled_ ?
"true" :
"false");
283 RCLCPP_INFO(this->get_logger(),
"Speech synthesis service name: %s",
speech_service_name_.c_str());
285 RCLCPP_INFO(this->get_logger(),
"Sentiment analysis enabled: %s",
sentiment_enabled_ ?
"true" :
"false");
292 template <
typename DriverType>
374 msg.sample_rate =
data.sample_rate;
376 msg.chunk_size =
data.chunk_size;
377 msg.chunk_count =
data.chunk_count;
383 catch (
const std::exception&
e)
401 auto msg = cv_bridge::CvImage(std_msgs::msg::Header(),
"bgr8", frame.image).toImageMsg();
402 msg->header.stamp = frame.stamp;
403 msg->header.frame_id = frame.frame_id;
412 auto msg = cv_bridge::CvImage(std_msgs::msg::Header(),
"bgr8", frame.image).toImageMsg();
413 msg->header.stamp = frame.stamp;
414 msg->header.frame_id = frame.frame_id;
448 else if (
request.audio.header.stamp.sec != 0 ||
request.audio.header.stamp.nanosec != 0)
462 response.transcription =
result.text;
463 response.success =
true;
467 response.success =
false;
468 response.transcription =
result.error.empty() ?
"No transcription result received." :
result.error;
481 else if (
request.header.stamp.sec != 0 ||
request.header.stamp.nanosec != 0)
492 response.analyzed_text =
result.analyzed_text;
496 response.label =
result.label;
497 response.score =
result.score;
501 response.label =
result.error.empty() ?
"Error: No sentiment analysis result available" :
result.error;
502 response.score = 0.0;
511 if (!
request.use_device_vision)
538 std::shared_ptr<Transcribe::Response> response)
544 response->success =
false;
545 response->transcription =
"Transcription driver is not loaded.";
546 response->header.stamp = this->
now();
552 response->header.stamp = this->
now();
563 catch (
const std::exception&
e)
565 response->success =
false;
567 if (
error_message.find(
"public audio buffer") != std::string::npos ||
569 error_message.find(
"Timeout waiting for audio data") != std::string::npos)
571 response->transcription = std::string(
"Device audio not available: ") +
error_message;
575 response->transcription = std::string(
"Transcription service error: ") +
error_message;
598 RCLCPP_INFO(this->
get_logger(),
"Received speech request with text: %s", request->input.text.c_str());
605 if (
result.used_device_audio)
608 response->success =
true;
614 response->success =
true;
620 response->success =
false;
634 std::shared_ptr<Sentiment::Response> response)
638 response->label =
"Error: sentiment driver not loaded";
639 response->score = 0.0;
653 catch (
const std::exception&
e)
655 response->label = std::string(
"Error: ") +
e.what();
656 response->score = 0.0;
663 RCLCPP_INFO(this->
get_logger(),
"Sending sentiment response: label='%s' score=%.3f analyzed_text='%s'",
664 response->label.c_str(), response->score, response->analyzed_text.c_str());
669 duration_seconds = std::max(1, duration_seconds);
673 const int sample_rate = std::max(1,
out.sample_rate);
674 const int channels = std::max(1,
out.channels);
676 static_cast<size_t>(sample_rate) *
static_cast<size_t>(channels) *
static_cast<size_t>(duration_seconds);
679 static_cast<double>(
samples_to_copy) /
static_cast<double>(std::max(1, sample_rate * channels));
685 "Using latest device audio window: requested=%d seconds start=%.9f end=%.9f returned=%.3f seconds "
686 "sample_rate=%d channels=%d frames=%d",
688 channels,
out.chunk_size);
693 "Requested %d seconds of device audio, but only %.2f seconds are buffered. Transcribing latest "
703 const int duration_seconds = std::max(1,
request.duration_seconds);
710 "Waiting for timestamped device audio window: requested=[%.9f, %.9f] timeout=%d seconds",
714 std::chrono::seconds(std::max(5, duration_seconds + 5)));
720 static_cast<double>(
out.chunk_size) /
static_cast<double>(std::max(1,
out.sample_rate));
722 if (
out.samples.empty() ||
out.chunk_size <= 0)
725 "Requested timestamped device audio window has no overlap with the buffered range. Falling back to "
726 "latest %d seconds of buffered audio. requested=[%.9f, %.9f] buffered=[%.9f, %.9f]",
735 "Requested timestamped device audio window is only partially available. Transcribing %.3f seconds "
736 "of overlapping audio. requested=[%.9f, %.9f] buffered=[%.9f, %.9f]",
742 "Timestamped device audio window ready: requested=[%.9f, %.9f] buffered=[%.9f, %.9f] returned=%.3f "
754 std::shared_ptr<ImageAnalysis::Response> response)
760 response->response =
"Image analysis driver is not loaded.";
770 catch (
const std::exception&
e)
772 response->response = std::string(
"Failed to acquire image: ") +
e.what();
782 catch (
const std::exception&
e)
784 response->response = std::string(
"Image analysis driver error: ") +
e.what();
Definition audio_buffer.hpp:19
rclcpp::Time endTime() const
Definition audio_buffer.hpp:273
rclcpp::Time startTime() const
Definition audio_buffer.hpp:267
audio_data readWindow(const rclcpp::Time &start_time, int duration_seconds)
Definition audio_buffer.hpp:176
void waitForWindow(const rclcpp::Time &start_time, int duration_seconds, std::chrono::seconds timeout=std::chrono::seconds(30))
Definition audio_buffer.hpp:226
audio_data readLatest(int duration_seconds)
Definition audio_buffer.hpp:146
void append(const audio_data &data, int max_duration_seconds)
Definition audio_buffer.hpp:24
Definition driver_manager.hpp:16
static void testDriver(const rclcpp::Logger &logger, const std::shared_ptr< DriverType > &driver, const std::string &driver_description)
Definition driver_manager.hpp:49
std::shared_ptr< DriverType > loadDriver(const std::string ¶meter_name, const std::string &default_plugin_name, const std::string &driver_description, const std::string &interface_description) const
Definition driver_manager.hpp:24
Definition perception_server.hpp:47
void publishVideo()
Definition perception_server.hpp:394
int audio_input_retention_window_
Definition perception_server.hpp:812
void initialize_pipelines()
Definition perception_server.hpp:323
void write_image_analysis_response(const image_analysis_result &result, ImageAnalysis::Response &response)
Definition perception_server.hpp:523
std::unique_ptr< SpeechPipeline > speech_pipeline_
Definition perception_server.hpp:868
rclcpp::Subscription< Audio >::SharedPtr audio_subscriber_
Definition perception_server.hpp:876
std::mutex transcription_driver_mutex_
Definition perception_server.hpp:804
void audioCallback(const Audio &msg)
Set the latest audio data to the driver from topic subscription. This function is called when new aud...
Definition perception_server.hpp:429
std::string image_analysis_service_name_
Definition perception_server.hpp:838
bool sentiment_enabled_
Definition perception_server.hpp:834
void start_background_tasks()
Definition perception_server.hpp:168
fp_perception_msgs::srv::PerceptionImageAnalysis ImageAnalysis
Definition perception_server.hpp:61
static constexpr DriverSpec kSentimentDriverSpec
Definition perception_server.hpp:75
void write_transcription_response(const transcription_result &result, Transcribe::Response &response)
Definition perception_server.hpp:458
std::shared_ptr< fp_perception::TranscriptionDriver > transcription_driver_
Definition perception_server.hpp:856
static constexpr DriverSpec kNonRosVisionDriverSpec
Definition perception_server.hpp:65
bool initialized_
Definition perception_server.hpp:895
int vision_input_frequency_
Definition perception_server.hpp:823
std::shared_ptr< fp_perception::SpeechSynthesisDriver > speech_driver_
Definition perception_server.hpp:862
std::shared_ptr< fp_perception::ImageAnalysisDriver > image_analysis_driver_
Definition perception_server.hpp:865
rclcpp::Publisher< sensor_msgs::msg::Image >::SharedPtr image_publisher_
Definition perception_server.hpp:891
std::unique_ptr< TranscriptionPipeline > transcription_pipeline_
Definition perception_server.hpp:867
std::mutex sentiment_driver_mutex_
Definition perception_server.hpp:805
bool audio_input_publish_
Definition perception_server.hpp:808
std::shared_ptr< fp_perception::VisionSourceDriver > non_ros_vision_driver_
Definition perception_server.hpp:847
bool audio_output_subscribe_
Definition perception_server.hpp:817
bool speech_enabled_
Definition perception_server.hpp:830
virtual void publishAudio()
Definition perception_server.hpp:352
bool use_ros_vision_driver_
Definition perception_server.hpp:793
bool use_speech_driver_
Definition perception_server.hpp:799
pluginlib::ClassLoader< fp_perception::DriverBase > driver_loader_
Definition perception_server.hpp:841
std::shared_ptr< DriverType > load_driver_if_enabled(const bool enabled, const DriverSpec &spec, const DriverManager &driver_manager)
Definition perception_server.hpp:293
std::string audio_input_frame_id_
Definition perception_server.hpp:810
fp_perception_msgs::msg::PerceptionAudio Audio
Definition perception_server.hpp:57
int default_audio_request_window_
Definition perception_server.hpp:813
bool image_analysis_enabled_
Definition perception_server.hpp:837
void transcribe_callback(const std::shared_ptr< Transcribe::Request > request, std::shared_ptr< Transcribe::Response > response)
Service callback for transcription requests.
Definition perception_server.hpp:537
sentiment_request make_sentiment_request(const Sentiment::Request &request)
Definition perception_server.hpp:471
bool use_transcription_driver_
Definition perception_server.hpp:797
bool use_microphone_driver_
Definition perception_server.hpp:795
void run_tests()
Definition perception_server.hpp:338
fp_perception::audio_data read_latest_public_audio(int duration_seconds)
Definition perception_server.hpp:667
~PerceptionServer()
Definition perception_server.hpp:92
static constexpr DriverSpec kImageAnalysisDriverSpec
Definition perception_server.hpp:77
static constexpr DriverSpec kMicrophoneDriverSpec
Definition perception_server.hpp:67
std::string audio_output_topic_
Definition perception_server.hpp:816
fp_perception::audio_data read_public_audio(const audio_buffer_request &request)
Definition perception_server.hpp:701
bool use_sentiment_driver_
Definition perception_server.hpp:798
PerceptionServer(const rclcpp::NodeOptions &options=rclcpp::NodeOptions())
Construct a new Perception Server object.
Definition perception_server.hpp:86
std::shared_ptr< fp_perception::AudioSourceDriver > microphone_driver_
Definition perception_server.hpp:850
rclcpp::TimerBase::SharedPtr deferred_initialize_timer_
Definition perception_server.hpp:893
fp_perception_msgs::srv::PerceptionSpeech Speech
Definition perception_server.hpp:58
std::string vision_input_frame_id_
Definition perception_server.hpp:822
bool use_image_analysis_driver_
Definition perception_server.hpp:800
rclcpp::Service< Sentiment >::SharedPtr sentiment_service_
Definition perception_server.hpp:888
bool run_tests_
Definition perception_server.hpp:791
void configure_interfaces()
Definition perception_server.hpp:209
std::shared_ptr< fp_perception::AudioSinkDriver > speaker_driver_
Definition perception_server.hpp:853
rclcpp::Service< Speech >::SharedPtr speech_service_
Definition perception_server.hpp:885
bool transcription_enabled_
Definition perception_server.hpp:826
std::string audio_input_topic_
Definition perception_server.hpp:809
std::string transcription_service_
Definition perception_server.hpp:827
void stop_background_tasks()
Definition perception_server.hpp:176
std::unique_ptr< SentimentPipeline > sentiment_pipeline_
Definition perception_server.hpp:869
std::thread audio_publish_thread_
Definition perception_server.hpp:896
void write_sentiment_response(const sentiment_result &result, Sentiment::Response &response)
Definition perception_server.hpp:490
void image_analysis_callback(const std::shared_ptr< ImageAnalysis::Request > request, std::shared_ptr< ImageAnalysis::Response > response)
Definition perception_server.hpp:753
void configure_driver_selection()
Definition perception_server.hpp:185
std::string sentiment_service_name_
Definition perception_server.hpp:835
std::shared_ptr< fp_perception::SentimentAnalysisDriver > sentiment_driver_
Definition perception_server.hpp:859
bool use_non_ros_vision_driver_
Definition perception_server.hpp:794
fp_perception_msgs::srv::PerceptionSentiment Sentiment
Definition perception_server.hpp:60
std::mutex initialization_mutex_
Definition perception_server.hpp:894
void load_drivers(const DriverManager &driver_manager)
Definition perception_server.hpp:303
static constexpr DriverSpec kSpeechDriverSpec
Definition perception_server.hpp:73
rclcpp::Service< Transcribe >::SharedPtr transcription_
Definition perception_server.hpp:879
AudioBuffer public_audio_buffer_
Definition perception_server.hpp:802
static constexpr DriverSpec kSpeakerDriverSpec
Definition perception_server.hpp:69
static constexpr DriverSpec kRosVisionDriverSpec
Definition perception_server.hpp:63
fp_perception_msgs::srv::PerceptionTranscribe Transcribe
Definition perception_server.hpp:59
void speech_callback(const std::shared_ptr< Speech::Request > request, std::shared_ptr< Speech::Response > response)
Service callback for the speech service.
Definition perception_server.hpp:596
void schedule_deferred_initialization()
Definition perception_server.hpp:151
std::shared_ptr< fp_perception::VisionSourceDriver > ros_vision_driver_
Definition perception_server.hpp:844
transcription_request make_transcription_request(const Transcribe::Request &request, std_msgs::msg::Header &header)
Definition perception_server.hpp:435
int audio_input_frequency_
Definition perception_server.hpp:811
rclcpp::Service< ImageAnalysis >::SharedPtr image_analysis_service_
Definition perception_server.hpp:882
bool vision_input_publish_
Definition perception_server.hpp:820
std::string vision_input_topic_
Definition perception_server.hpp:821
std::unique_ptr< ImageAnalysisPipeline > image_analysis_pipeline_
Definition perception_server.hpp:870
image_analysis_request make_image_analysis_request(const ImageAnalysis::Request &request)
Definition perception_server.hpp:505
static constexpr DriverSpec kTranscriptionDriverSpec
Definition perception_server.hpp:71
void sentiment_callback(const std::shared_ptr< Sentiment::Request > request, std::shared_ptr< Sentiment::Response > response)
Callback function for the sentiment analysis service.
Definition perception_server.hpp:633
std::string speech_service_name_
Definition perception_server.hpp:831
rclcpp::Publisher< Audio >::SharedPtr audio_publisher_
Definition perception_server.hpp:873
bool use_speaker_driver_
Definition perception_server.hpp:796
void initialize()
Definition perception_server.hpp:97
Definition audio_buffer.hpp:16
text_data msg_to_text_data(const fp_perception_msgs::msg::PerceptionText &msg)
Definition structs.hpp:94
fp_perception_msgs::msg::PerceptionAudio audio_data_to_msg(const audio_data &data)
Convert fp_perception::audio_data to fp_perception_msgs::msg::PerceptionAudio message.
Definition structs.hpp:45
audio_data msg_to_audio_data(const fp_perception_msgs::msg::PerceptionAudio &msg)
Convert fp_perception_msgs::msg::PerceptionAudio message to audio_data.
Definition structs.hpp:67
Definition perception_server.hpp:50
const char * parameter_name
Definition perception_server.hpp:51
const char * default_plugin_name
Definition perception_server.hpp:52
const char * driver_description
Definition perception_server.hpp:53
const char * interface_description
Definition perception_server.hpp:54
Definition structs.hpp:26
rclcpp::Time start_time
Definition structs.hpp:29
Struct to hold audio data.
Definition structs.hpp:16
std::vector< int16_t > samples
Audio samples.
Definition structs.hpp:17
Definition structs.hpp:11
bool use_device_vision
Definition structs.hpp:14
Definition structs.hpp:18
Definition structs.hpp:11
int audio_request_window
Definition structs.hpp:14
Definition structs.hpp:20
Definition structs.hpp:33
Definition structs.hpp:13
int audio_request_window
Definition structs.hpp:16
Definition structs.hpp:22
bool success
Definition structs.hpp:24