Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions physical_ai_interfaces/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog for package physical_ai_interfaces
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.7.3 (2026-01-19)
------------------
* None

0.7.2 (2025-12-01)
------------------
* None
Expand Down
2 changes: 1 addition & 1 deletion physical_ai_interfaces/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>physical_ai_interfaces</name>
<version>0.7.2</version>
<version>0.7.3</version>
<description>
ROS 2 interfaces for Physical AI tools
</description>
Expand Down
4 changes: 4 additions & 0 deletions physical_ai_manager/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog for package physical_ai_manager
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.7.3 (2026-01-19)
------------------
* None

0.7.2 (2025-12-01)
------------------
* None
Expand Down
4 changes: 2 additions & 2 deletions physical_ai_manager/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion physical_ai_manager/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "physical_ai_manager",
"version": "0.7.2",
"version": "0.7.3",
"description": "Web UI for Physical AI Platform",
"author": "Kiwoong Park <pkw@robotis.com>",
"contributors": [
Expand Down
5 changes: 5 additions & 0 deletions physical_ai_server/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changelog for package physical_ai_server
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.7.3 (2026-01-19)
------------------
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog entry is incomplete. It mentions recording /tf, /robot_description, and /camera_info topics but omits /tf_static which is actually added in all configuration files. The changelog should accurately list all topics being added, including /tf_static.

Suggested change
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
* Modified to record /tf, /tf_static, /robot_description, /camera_info topics in rosbag2

Copilot uses AI. Check for mistakes.
* Contributors: Dongyun Kim

0.7.2 (2025-12-01)
------------------
* Fixed an issue where the task_index was being merged based on the first episode when merging episodes in the *.parquet data.
Expand Down
10 changes: 10 additions & 0 deletions physical_ai_server/config/ffw_bg2_rev4_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ physical_ai_server:
- leader_head
- leader_lift

rosbag_extra_topic_list:
- /tf
- /tf_static
- /robot_description
- /zed/zed_node/rgb/camera_info
- /zed/zed_node/left/camera_info
- /zed/zed_node/right/camera_info
- /camera_left/camera_left/color/camera_info
- /camera_right/camera_right/color/camera_info

Comment on lines 33 to 39
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions adding /tf_status to the recorded topics, but this topic is not present in any of the configuration files. Only /tf and /tf_static are added. If /tf_status was intended to be recorded, it should be added to the rosbag_extra_topic_list in the configuration files.

Copilot uses AI. Check for mistakes.
joint_order:
leader_left:
- arm_l_joint1
Expand Down
12 changes: 12 additions & 0 deletions physical_ai_server/config/ffw_sg2_rev1_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ physical_ai_server:
- leader_lift
- leader_mobile

rosbag_extra_topic_list:
- /tf
- /tf_static
- /robot_description
- /odom
- /cmd_vel
- /zed/zed_node/rgb/camera_info
- /zed/zed_node/left/camera_info
- /zed/zed_node/right/camera_info
- /camera_left/camera_left/color/camera_info
- /camera_right/camera_right/color/camera_info
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions recording /*/camera_info topics (wildcard pattern), but the implementation adds specific camera_info topics like /zed/zed_node/rgb/camera_info. The PR description should accurately reflect what was implemented, or the implementation should support the wildcard pattern as described.

Suggested change
- /zed/zed_node/rgb/camera_info
- /zed/zed_node/left/camera_info
- /zed/zed_node/right/camera_info
- /camera_left/camera_left/color/camera_info
- /camera_right/camera_right/color/camera_info
- /*/camera_info

Copilot uses AI. Check for mistakes.

Comment on lines 36 to 45
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions adding /tf_status to the recorded topics, but this topic is not present in any of the configuration files. Only /tf and /tf_static are added. If /tf_status was intended to be recorded, it should be added to the rosbag_extra_topic_list in the configuration files.

Copilot uses AI. Check for mistakes.
joint_order:
leader_left:
- arm_l_joint1
Expand Down
5 changes: 5 additions & 0 deletions physical_ai_server/config/omx_f_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ physical_ai_server:
joint_list:
- leader

rosbag_extra_topic_list:
- /tf
- /tf_static
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions adding /tf_status to the recorded topics, but this topic is not present in any of the configuration files. Only /tf and /tf_static are added. If /tf_status was intended to be recorded, it should be added to the rosbag_extra_topic_list in the configuration files.

Suggested change
- /tf_static
- /tf_static
- /tf_status

Copilot uses AI. Check for mistakes.
- /robot_description

joint_order:
leader:
- joint1
Expand Down
5 changes: 5 additions & 0 deletions physical_ai_server/config/omy_f3m_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ physical_ai_server:
joint_list:
- leader

rosbag_extra_topic_list:
- /tf
- /tf_static
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions adding /tf_status to the recorded topics, but this topic is not present in any of the configuration files. Only /tf and /tf_static are added. If /tf_status was intended to be recorded, it should be added to the rosbag_extra_topic_list in the configuration files.

Suggested change
- /tf_static
- /tf_static
- /tf_status

Copilot uses AI. Check for mistakes.
- /robot_description

joint_order:
leader:
- joint1
Expand Down
2 changes: 1 addition & 1 deletion physical_ai_server/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>physical_ai_server</name>
<version>0.7.2</version>
<version>0.7.3</version>
<description>
ROS 2 package for Open Platform AI Kit integration
</description>
Expand Down
2 changes: 1 addition & 1 deletion physical_ai_server/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

setup(
name=package_name,
version='0.7.2',
version='0.7.3',
packages=find_packages(),
data_files=[
('share/ament_index/resource_index/packages', ['resource/' + package_name]),
Expand Down
5 changes: 5 additions & 0 deletions physical_ai_tools/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changelog for package physical_ai_tools
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.7.3 (2026-01-19)
------------------
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog entry is incomplete. It mentions recording /tf, /robot_description, and /camera_info topics but omits /tf_static which is actually added in all configuration files. The changelog should accurately list all topics being added, including /tf_static.

Suggested change
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
* Modified to record /tf, /tf_static, /robot_description, /camera_info topics in rosbag2

Copilot uses AI. Check for mistakes.
* Contributors: Dongyun Kim

0.7.2 (2025-12-01)
------------------
* Fixed an issue where the task_index was being merged based on the first episode when merging episodes in the *.parquet data.
Expand Down
2 changes: 1 addition & 1 deletion physical_ai_tools/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>physical_ai_tools</name>
<version>0.7.2</version>
<version>0.7.3</version>
<description>
physical_ai_tools meta ROS 2 package
</description>
Expand Down
5 changes: 5 additions & 0 deletions rosbag_recorder/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changelog for package rosbag_recorder
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0.7.3 (2026-01-19)
------------------
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog entry is incomplete. It mentions recording /tf, /robot_description, and /camera_info topics but omits /tf_static which is actually added in all configuration files. The changelog should accurately list all topics being added, including /tf_static.

Suggested change
* Modified to record /tf, /robot_description, /camera_info topics in rosbag2
* Modified to record /tf, /tf_static, /robot_description, /camera_info topics in rosbag2

Copilot uses AI. Check for mistakes.
* Contributors: Dongyun Kim

0.7.2 (2025-12-01)
------------------
* None
Expand Down
14 changes: 14 additions & 0 deletions rosbag_recorder/include/rosbag_recorder/service_bag_recorder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,26 @@ class ServiceBagRecorder : public rclcpp::Node
const std::map<std::string, std::vector<std::string>> & names_and_types);
void delete_bag_directory(const std::string & bag_uri);
void create_subscriptions();
rclcpp::QoS get_qos_for_topic(const std::string & topic);
void flush_latched_messages();

rclcpp::Service<rosbag_recorder::srv::SendCommand>::SharedPtr send_command_srv_;

std::vector<rclcpp::GenericSubscription::SharedPtr> subscriptions_;
std::unique_ptr<rosbag2_cpp::Writer> writer_;
std::unordered_map<std::string, std::string> type_for_topic_;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To improve performance by avoiding repeated checks for latched topics, I suggest adding a member to cache the names of latched topics. This cache will be populated once in create_subscriptions.

  std::unordered_map<std::string, std::string> type_for_topic_;
  std::unordered_set<std::string> latched_topics_;


// Cache of latched topic names to avoid repeated publisher info lookups
std::unordered_set<std::string> latched_topics_;
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing include for std::unordered_set. The header file uses std::unordered_set but does not include the required header <unordered_set>. This will cause compilation errors.

Copilot uses AI. Check for mistakes.

// Buffer for latched messages received before recording starts
struct BufferedMessage
{
std::shared_ptr<rclcpp::SerializedMessage> msg;
rclcpp::Time timestamp;
};
std::unordered_map<std::string, BufferedMessage> latched_message_buffer_;
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BufferedMessage struct stores only one message per topic. For latched topics, this is generally correct since they publish once. However, if a latched topic republishes before recording starts (e.g., due to parameter updates or re-initialization), only the latest message will be buffered and previous messages will be lost. Consider whether this behavior is acceptable, or add a comment explaining that only the most recent latched message is preserved, which is the intended behavior.

Copilot uses AI. Check for mistakes.

bool is_recording_ {false};
std::string current_bag_uri_;
std::vector<std::string> topics_to_record_ {};
Expand Down
2 changes: 1 addition & 1 deletion rosbag_recorder/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>rosbag_recorder</name>
<version>0.7.2</version>
<version>0.7.3</version>
<description>
ROS 2 package to record rosbag dataset
</description>
Expand Down
88 changes: 81 additions & 7 deletions rosbag_recorder/src/service_bag_recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ void ServiceBagRecorder::handle_prepare(const std::vector<std::string> & topics)
type_for_topic_[topic] = type;
}

// Create subscriptions early to avoid data loss
// Latched messages will be buffered until recording starts
create_subscriptions();

RCLCPP_INFO(
Expand Down Expand Up @@ -180,7 +182,9 @@ void ServiceBagRecorder::handle_start(const std::string & uri)
throw std::runtime_error(std::string("Failed to start recording: ") + e.what());
}

// Set recording flag and flush buffered latched messages
is_recording_ = true;
flush_latched_messages();
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flush_latched_messages function is called without mutex protection. This function is invoked in handle_start (line 187) after is_recording_ is set to true, but outside the scope of the service handler's mutex lock. Meanwhile, handle_serialized_message (which runs in subscription callbacks) accesses the same latched_message_buffer_ under mutex protection. This creates a race condition where flush_latched_messages could be iterating over latched_message_buffer_ while handle_serialized_message might be modifying it, leading to undefined behavior. The flush_latched_messages call should be moved inside the try block before line 183, or the entire operation including setting is_recording_ and flushing should be protected by the mutex.

Copilot uses AI. Check for mistakes.

RCLCPP_INFO(
this->get_logger(), "Recording started: uri=%s topics=%zu",
Expand Down Expand Up @@ -306,39 +310,109 @@ void ServiceBagRecorder::create_subscriptions()
RCLCPP_INFO(this->get_logger(), "Creating subscriptions");

subscriptions_.clear();
latched_topics_.clear();

// Create generic subscriptions for all topics
for (const auto & [topic, type] : type_for_topic_) {
auto options = rclcpp::SubscriptionOptions();
auto qos = get_qos_for_topic(topic);

// Cache whether this topic is latched to avoid repeated publisher lookups
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
latched_topics_.insert(topic);
}
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing mutex protection for latched_topics_ access. The latched_topics_ set is populated in create_subscriptions (line 322) and read in handle_serialized_message (line 412). While handle_serialized_message is protected by mutex, create_subscriptions is called from handle_prepare which is also protected by mutex in the service handler. However, if create_subscriptions is ever called from a different context or if the locking strategy changes, this could lead to race conditions. Consider documenting that create_subscriptions must always be called under mutex protection, or add assertions to verify this precondition.

Copilot uses AI. Check for mistakes.

auto sub = this->create_generic_subscription(
topic,
type,
rclcpp::QoS(100),
qos,
[this, topic](std::shared_ptr<rclcpp::SerializedMessage> serialized_msg) {
this->handle_serialized_message(topic, serialized_msg);
},
options);
subscriptions_.push_back(sub);
RCLCPP_INFO(
this->get_logger(),
"Subscribed to topic: %s",
topic.c_str());
}
}

void ServiceBagRecorder::handle_serialized_message(
const std::string & topic,
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_msg)
rclcpp::QoS ServiceBagRecorder::get_qos_for_topic(
const std::string & topic)
{
std::scoped_lock<std::mutex> lock(mutex_);
// Get publisher info to determine QoS settings
auto publishers_info = this->get_publishers_info_by_topic(topic);

if (!publishers_info.empty()) {
// Check if any publisher uses TRANSIENT_LOCAL durability
for (const auto & pub_info : publishers_info) {
if (pub_info.qos_profile().durability() == rclcpp::DurabilityPolicy::TransientLocal) {
RCLCPP_INFO(
this->get_logger(),
"Topic '%s' uses TRANSIENT_LOCAL durability, using matching QoS",
topic.c_str());
// Use smaller queue size (10) for latched topics as they typically publish once
// and rely on durability rather than queue depth
return rclcpp::QoS(rclcpp::KeepLast(10))
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment on line 355 states that a queue size of 10 is used for latched topics because they "typically publish once". However, using KeepLast(10) means the subscriber will keep the last 10 messages. For truly latched topics that only publish once, a queue size of 1 would be more appropriate and memory-efficient. Consider changing to KeepLast(1) or clarifying in the comment why a larger queue is needed.

Suggested change
// Use smaller queue size (10) for latched topics as they typically publish once
// and rely on durability rather than queue depth
return rclcpp::QoS(rclcpp::KeepLast(10))
// Use minimal queue size (1) for latched topics as they typically publish once
// and rely on durability rather than queue depth
return rclcpp::QoS(rclcpp::KeepLast(1))

Copilot uses AI. Check for mistakes.
.reliable()
.transient_local();
}
}
}

// Use default QoS for other topics
return rclcpp::QoS(100);
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The get_qos_for_topic function calls get_publishers_info_by_topic which can be an expensive operation as it queries the ROS graph. This function is called for every topic during subscription creation. While the latched status is cached afterward, the initial call during create_subscriptions could be slow if there are many topics or if publishers haven't fully initialized yet. Consider adding error handling for the case where publisher info is not yet available, or implement a retry mechanism with appropriate logging.

Copilot uses AI. Check for mistakes.
}

if (!is_recording_ || !writer_) {
void ServiceBagRecorder::flush_latched_messages()
{
if (latched_message_buffer_.empty()) {
return;
}

RCLCPP_INFO(
this->get_logger(),
"Flushing %zu buffered latched messages",
latched_message_buffer_.size());

for (const auto & [topic, buffered] : latched_message_buffer_) {
if (writer_) {
const auto it = type_for_topic_.find(topic);
if (it != type_for_topic_.end()) {
writer_->write(buffered.msg, topic, it->second, buffered.timestamp);
RCLCPP_DEBUG(this->get_logger(), "Flushed latched message from: %s", topic.c_str());
}
}
}

latched_message_buffer_.clear();
}

void ServiceBagRecorder::handle_serialized_message(
const std::string & topic,
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_msg)
{
std::scoped_lock<std::mutex> lock(mutex_);

const auto it = type_for_topic_.find(topic);
if (it == type_for_topic_.end()) {
return;
}
const std::string & type = it->second;
writer_->write(serialized_msg, topic, type, this->now());

// If recording, write directly to bag
if (is_recording_ && writer_) {
writer_->write(serialized_msg, topic, type, this->now());
return;
}
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential race condition with is_recording_ flag. The is_recording_ flag is read without atomic guarantees in the callback thread (line 405) while it's written in the service handler thread (line 186). Although both accesses are protected by mutex in their respective contexts, the ordering between setting is_recording_ = true and calling flush_latched_messages() could still lead to a narrow race window where messages arrive between these two operations and are buffered instead of being written directly. Consider setting is_recording_ after flush_latched_messages() completes, or ensure both operations are atomic with respect to message handling.

Copilot uses AI. Check for mistakes.

// If not recording yet but this is a latched topic, buffer it
// Use cached latched topic status to avoid repeated publisher info lookups
if (!is_recording_ && latched_topics_.count(topic)) {
latched_message_buffer_[topic] = {serialized_msg, this->now()};
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the most recent latched message is stored per topic. If a latched topic publishes multiple updates before recording starts, earlier messages will be overwritten. Consider whether this is the intended behavior or if all messages should be buffered.

Copilot uses AI. Check for mistakes.
RCLCPP_DEBUG(this->get_logger(), "Buffered latched message from topic: %s", topic.c_str());
}
}

int main(int argc, char ** argv)
Expand Down
Loading