Skip to content

Commit 9b808ee

Browse files
Fix pose/twist publisher rate drop when downsampling publish rate (#18)
* Updated how time between pose/twist publish is computed * cleaned up cmake. clamped publish rate accumulation. reset time accumulator in on_activate --------- Co-authored-by: Vidullan Surendran <vsurendran@theaiinstitute.com>
1 parent 563842f commit 9b808ee

5 files changed

Lines changed: 99 additions & 49 deletions

File tree

CMakeLists.txt

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,37 @@ endif()
1818
# Enable precompiled headers
1919
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
2020

21-
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
22-
add_compile_options(-Wall -Wextra -Wpedantic)
21+
option(CHECK_TIDY "Adds clang-tidy tests" OFF)
22+
23+
option(ENABLE_NATIVE_OPTIMIZATION
24+
"Enable CPU-specific optimizations (-march=native)"
25+
OFF
26+
)
27+
28+
# Default to release build
29+
if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
30+
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
2331
endif()
2432

25-
option(CHECK_TIDY "Adds clang-tidy tests" OFF)
33+
# Compiler flags by build type
34+
add_library(project_compile_options INTERFACE)
35+
target_compile_options(project_compile_options INTERFACE
36+
# Warnings (build only)
37+
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic>
38+
39+
# Debug
40+
$<$<AND:$<CONFIG:Debug>,$<CXX_COMPILER_ID:GNU,Clang>>:-O0 -g>
41+
42+
# Release
43+
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU,Clang>>:-O3 -DNDEBUG>
44+
)
45+
46+
# Optional CPU-specific optimizations (non-portable)
47+
if(ENABLE_NATIVE_OPTIMIZATION)
48+
target_compile_options(project_compile_options INTERFACE
49+
$<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU,Clang>>:-march=native>
50+
)
51+
endif()
2652

2753
# find dependencies
2854
find_package(ament_cmake REQUIRED)
@@ -65,6 +91,11 @@ add_library(
6591
src/twist_broadcaster.cpp
6692
)
6793

94+
target_link_libraries(${PROJECT_NAME}
95+
PRIVATE
96+
project_compile_options
97+
)
98+
6899
target_include_directories(${PROJECT_NAME}
69100
PUBLIC
70101
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>

include/crisp_controllers/pose_broadcaster.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ class PoseBroadcaster
6464
{"JointModelRUBX", "JointModelRUBY", "JointModelRUBZ"};
6565

6666
Eigen::VectorXd q;
67-
rclcpp::Time last_publish_time_;
67+
68+
rclcpp::Duration publish_elapsed_{0,0};
69+
rclcpp::Duration publish_interval_{0,0};
6870
};
6971

7072
} // namespace crisp_controllers

include/crisp_controllers/twist_broadcaster.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ class TwistBroadcaster
6565

6666
Eigen::VectorXd q;
6767
Eigen::VectorXd q_dot;
68-
rclcpp::Time last_publish_time_;
68+
69+
rclcpp::Duration publish_elapsed_{0,0};
70+
rclcpp::Duration publish_interval_{0,0};
6971
};
7072

7173
} // namespace crisp_controllers

src/pose_broadcaster.cpp

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ PoseBroadcaster::state_interface_configuration() const {
3535

3636
controller_interface::return_type
3737
PoseBroadcaster::update(const rclcpp::Time &time,
38-
const rclcpp::Duration & /*period*/) {
38+
const rclcpp::Duration &period) {
3939

4040
size_t num_joints = params_.joints.size();
4141
Eigen::VectorXd q_pin = Eigen::VectorXd::Zero(model_.nq);
@@ -63,28 +63,28 @@ PoseBroadcaster::update(const rclcpp::Time &time,
6363
Eigen::Quaterniond(current_pose.rotation());
6464

6565
// Decide whether to publish the pose or not
66-
bool should_publish = true;
67-
if (params_.publish_frequency > 0.0) {
68-
auto time_since_last = time - last_publish_time_;
69-
auto min_interval = rclcpp::Duration::from_seconds(1.0 / params_.publish_frequency);
70-
should_publish = time_since_last >= min_interval;
71-
}
72-
73-
if (should_publish && realtime_pose_publisher_ && realtime_pose_publisher_->trylock())
66+
publish_elapsed_ = publish_elapsed_ + period;
67+
bool should_publish = (publish_elapsed_ >= publish_interval_) ||
68+
(publish_interval_.nanoseconds() == 0);
69+
if (should_publish && realtime_pose_publisher_)
7470
{
75-
auto & pose_msg = realtime_pose_publisher_->msg_;
76-
77-
pose_msg.header.stamp = time;
78-
pose_msg.header.frame_id = params_.base_frame;
79-
pose_msg.pose.position.x = current_pose.translation()[0];
80-
pose_msg.pose.position.y = current_pose.translation()[1];
81-
pose_msg.pose.position.z = current_pose.translation()[2];
82-
pose_msg.pose.orientation.x = current_quaternion.x();
83-
pose_msg.pose.orientation.y = current_quaternion.y();
84-
pose_msg.pose.orientation.z = current_quaternion.z();
85-
pose_msg.pose.orientation.w = current_quaternion.w();
86-
realtime_pose_publisher_->unlockAndPublish();
87-
last_publish_time_ = time;
71+
if (realtime_pose_publisher_->trylock()) {
72+
auto & pose_msg = realtime_pose_publisher_->msg_;
73+
pose_msg.header.stamp = time;
74+
pose_msg.header.frame_id = params_.base_frame;
75+
pose_msg.pose.position.x = current_pose.translation()[0];
76+
pose_msg.pose.position.y = current_pose.translation()[1];
77+
pose_msg.pose.position.z = current_pose.translation()[2];
78+
pose_msg.pose.orientation.x = current_quaternion.x();
79+
pose_msg.pose.orientation.y = current_quaternion.y();
80+
pose_msg.pose.orientation.z = current_quaternion.z();
81+
pose_msg.pose.orientation.w = current_quaternion.w();
82+
realtime_pose_publisher_->unlockAndPublish();
83+
84+
publish_elapsed_ = publish_elapsed_ - publish_interval_;
85+
// clamp to publish only 1 time even if missed multiple intervals
86+
publish_elapsed_ = std::min(publish_elapsed_, publish_interval_);
87+
}
8888
}
8989

9090
return controller_interface::return_type::OK;
@@ -168,12 +168,19 @@ CallbackReturn PoseBroadcaster::on_configure(
168168
std::make_shared<realtime_tools::RealtimePublisher<geometry_msgs::msg::PoseStamped>>(
169169
pose_publisher_);
170170

171-
last_publish_time_ = this->get_node()->now();
171+
if (params_.publish_frequency > 0.0) {
172+
publish_interval_ = rclcpp::Duration::from_seconds(1.0 / params_.publish_frequency);
173+
} else {
174+
publish_interval_ = rclcpp::Duration(0, 0); // publish every cycle
175+
}
176+
172177
return CallbackReturn::SUCCESS;
173178
}
174179

175180
CallbackReturn PoseBroadcaster::on_activate(
176181
const rclcpp_lifecycle::State & /*previous_state*/) {
182+
// reset publish time accumulation
183+
publish_elapsed_ = rclcpp::Duration(0, 0);
177184
return CallbackReturn::SUCCESS;
178185
}
179186

src/twist_broadcaster.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ TwistBroadcaster::state_interface_configuration() const {
3636

3737
controller_interface::return_type
3838
TwistBroadcaster::update(const rclcpp::Time &time,
39-
const rclcpp::Duration & /*period*/) {
39+
const rclcpp::Duration &period) {
4040

4141
size_t num_joints = params_.joints.size();
4242
Eigen::VectorXd q_pin = Eigen::VectorXd::Zero(model_.nq);
@@ -67,27 +67,28 @@ TwistBroadcaster::update(const rclcpp::Time &time,
6767
auto current_velocity = pinocchio::getFrameVelocity(model_, data_, end_effector_frame_id);
6868

6969
// Decide whether to publish the twist or not
70-
bool should_publish = true;
71-
if (params_.publish_frequency > 0.0) {
72-
auto time_since_last = time - last_publish_time_;
73-
auto min_interval = rclcpp::Duration::from_seconds(1.0 / params_.publish_frequency);
74-
should_publish = time_since_last >= min_interval;
75-
}
70+
publish_elapsed_ = publish_elapsed_ + period;
71+
bool should_publish = (publish_elapsed_ >= publish_interval_) ||
72+
(publish_interval_.nanoseconds() == 0);
7673

77-
if (should_publish && realtime_twist_publisher_ && realtime_twist_publisher_->trylock())
74+
if (should_publish && realtime_twist_publisher_)
7875
{
79-
auto & twist_msg = realtime_twist_publisher_->msg_;
80-
81-
twist_msg.header.stamp = time;
82-
twist_msg.header.frame_id = params_.end_effector_frame;
83-
twist_msg.twist.linear.x = current_velocity.linear()[0];
84-
twist_msg.twist.linear.y = current_velocity.linear()[1];
85-
twist_msg.twist.linear.z = current_velocity.linear()[2];
86-
twist_msg.twist.angular.x = current_velocity.angular()[0];
87-
twist_msg.twist.angular.y = current_velocity.angular()[1];
88-
twist_msg.twist.angular.z = current_velocity.angular()[2];
89-
realtime_twist_publisher_->unlockAndPublish();
90-
last_publish_time_ = time;
76+
if (realtime_twist_publisher_->trylock()) {
77+
auto & twist_msg = realtime_twist_publisher_->msg_;
78+
twist_msg.header.stamp = time;
79+
twist_msg.header.frame_id = params_.end_effector_frame;
80+
twist_msg.twist.linear.x = current_velocity.linear()[0];
81+
twist_msg.twist.linear.y = current_velocity.linear()[1];
82+
twist_msg.twist.linear.z = current_velocity.linear()[2];
83+
twist_msg.twist.angular.x = current_velocity.angular()[0];
84+
twist_msg.twist.angular.y = current_velocity.angular()[1];
85+
twist_msg.twist.angular.z = current_velocity.angular()[2];
86+
realtime_twist_publisher_->unlockAndPublish();
87+
88+
publish_elapsed_ = publish_elapsed_ - publish_interval_;
89+
// clamp to publish only 1 time even if missed multiple intervals
90+
publish_elapsed_ = std::min(publish_elapsed_, publish_interval_);
91+
}
9192
}
9293

9394
return controller_interface::return_type::OK;
@@ -172,12 +173,19 @@ CallbackReturn TwistBroadcaster::on_configure(
172173
std::make_shared<realtime_tools::RealtimePublisher<geometry_msgs::msg::TwistStamped>>(
173174
twist_publisher_);
174175

175-
last_publish_time_ = this->get_node()->now();
176+
if (params_.publish_frequency > 0.0) {
177+
publish_interval_ = rclcpp::Duration::from_seconds(1.0 / params_.publish_frequency);
178+
} else {
179+
publish_interval_ = rclcpp::Duration(0, 0); // publish every cycle
180+
}
181+
176182
return CallbackReturn::SUCCESS;
177183
}
178184

179185
CallbackReturn TwistBroadcaster::on_activate(
180186
const rclcpp_lifecycle::State & /*previous_state*/) {
187+
// reset publish time accumulation
188+
publish_elapsed_ = rclcpp::Duration(0, 0);
181189
return CallbackReturn::SUCCESS;
182190
}
183191

0 commit comments

Comments
 (0)