PointCloud Motion Capture
Pointcloud Motion Capture is a ROS 2 package designed to process point clouds for capturing object movements. It detects objects using color filters and infers data about their position, velocity, and acceleration. This package has been tested under [ROS] Humble and Ubuntu 22.04
Loading...
Searching...
No Matches
motion_capture.cpp
Go to the documentation of this file.
1// Copyright 2024 João Vitor Silva Mendes
2
3#include "motion_capture.hpp"
4
6{
8: Node("motion_capture"),
9 previous_position_(Eigen::Vector4f::Zero()),
10 previous_velocity_(Eigen::Vector3f::Zero()),
11 previous_time_(this->now()), previous_velocity_time_(this->now())
12{
14
15 subscription_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
17 std::bind(&MotionCapture::pointCloudCallback, this, std::placeholders::_1));
18
19 position_publisher_ = this->create_publisher<geometry_msgs::msg::Point>(
21
22 velocity_publisher_ = this->create_publisher<geometry_msgs::msg::Vector3>(
24
25 acceleration_publisher_ = this->create_publisher<geometry_msgs::msg::Vector3>(
27
28 timer_ = this->create_wall_timer(
29 std::chrono::milliseconds(static_cast<int>(kMillisecondsPerSecond / publish_rate_)),
30 std::bind(&MotionCapture::publishData, this));
31
32 RCLCPP_INFO(this->get_logger(), "MotionCapture node initialized.");
33}
34
36{
37 this->declare_parameter<std::string>(
38 "point_cloud_topic_filtered",
40 this->declare_parameter<std::string>("position_publish_topic", kDefaultPositionPublishTopic);
41 this->declare_parameter<std::string>("velocity_publish_topic", kDefaultVelocityPublishTopic);
42 this->declare_parameter<std::string>(
43 "acceleration_publish_topic",
45 this->declare_parameter<int>("position_samples", kDefaultPositionSamples);
46 this->declare_parameter<int>("velocity_samples", kDefaultVelocitySamples);
47 this->declare_parameter<double>("publish_rate", kDefaultPublishRate);
48 this->declare_parameter<int>("queue_size", kDefaultQueueSize);
49 point_cloud_topic_filtered_ = this->get_parameter("point_cloud_topic_filtered").as_string();
50 position_publish_topic_ = this->get_parameter("position_publish_topic").as_string();
51 velocity_publish_topic_ = this->get_parameter("velocity_publish_topic").as_string();
52 acceleration_publish_topic_ = this->get_parameter("acceleration_publish_topic").as_string();
53 position_samples_ = this->get_parameter("position_samples").as_int();
54 velocity_samples_ = this->get_parameter("velocity_samples").as_int();
55 publish_rate_ = this->get_parameter("publish_rate").as_double();
56 queue_size_ = this->get_parameter("queue_size").as_int();
57}
58
59void MotionCapture::pointCloudCallback(const sensor_msgs::msg::PointCloud2::SharedPtr msg)
60{
61 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
62 pcl::fromROSMsg(*msg, *cloud);
63
64 Eigen::Vector4f centroid;
65 pcl::compute3DCentroid(*cloud, centroid);
66
67 updatePositionSamples(centroid);
68}
69
70void MotionCapture::updatePositionSamples(const Eigen::Vector4f & centroid)
71{
72 if (static_cast<int>(position_queue_.size()) >= position_samples_) {
73 position_queue_.pop();
74 }
75 position_queue_.push(centroid);
76}
77
79{
80 Eigen::Vector4f sum = Eigen::Vector4f::Zero();
81 std::queue<Eigen::Vector4f> temp_queue = position_queue_;
82 while (!temp_queue.empty()) {
83 sum += temp_queue.front();
84 temp_queue.pop();
85 }
86 return sum / position_queue_.size();
87}
88
89void MotionCapture::updateVelocitySamples(const Eigen::Vector3f & velocity)
90{
91 if (static_cast<int>(velocity_queue_.size()) >= velocity_samples_) {
92 velocity_queue_.pop();
93 }
94 velocity_queue_.push(velocity);
95}
96
98{
99 Eigen::Vector3f sum = Eigen::Vector3f::Zero();
100 std::queue<Eigen::Vector3f> temp_queue = velocity_queue_;
101 while (!temp_queue.empty()) {
102 sum += temp_queue.front();
103 temp_queue.pop();
104 }
105 return sum / velocity_queue_.size();
106}
107
109{
110 if (!position_queue_.empty()) {
111 Eigen::Vector4f filtered_position = getFilteredPosition();
112 publishPosition(filtered_position);
113
114 Eigen::Vector3f current_velocity = publishVelocity(filtered_position);
115 updateVelocitySamples(current_velocity);
116
117 if (!velocity_queue_.empty()) {
118 Eigen::Vector3f filtered_velocity = getFilteredVelocity();
119 publishAcceleration(filtered_velocity);
120 }
121
122 previous_position_ = filtered_position;
123 previous_time_ = this->now();
124 }
125}
126
127void MotionCapture::publishPosition(const Eigen::Vector4f & centroid)
128{
129 geometry_msgs::msg::Point position_msg;
130 position_msg.x = centroid[kCentroidX];
131 position_msg.y = centroid[kCentroidY];
132 position_msg.z = centroid[kCentroidZ];
133
134 position_publisher_->publish(position_msg);
135}
136
137Eigen::Vector3f MotionCapture::publishVelocity(const Eigen::Vector4f & current_position)
138{
139 rclcpp::Time current_time = this->now();
140 double time_difference = (current_time - previous_time_).seconds();
141 Eigen::Vector3f velocity = Eigen::Vector3f::Zero();
142
143 if (time_difference > 0) {
144 velocity[kCentroidX] = (current_position[kCentroidX] - previous_position_[kCentroidX]) /
145 time_difference;
146 velocity[kCentroidY] = (current_position[kCentroidY] - previous_position_[kCentroidY]) /
147 time_difference;
148 velocity[kCentroidZ] = (current_position[kCentroidZ] - previous_position_[kCentroidZ]) /
149 time_difference;
150
151 geometry_msgs::msg::Vector3 velocity_msg;
152 velocity_msg.x = velocity[kCentroidX];
153 velocity_msg.y = velocity[kCentroidY];
154 velocity_msg.z = velocity[kCentroidZ];
155
156 velocity_publisher_->publish(velocity_msg);
157 }
158
159 return velocity;
160}
161
162void MotionCapture::publishAcceleration(const Eigen::Vector3f & current_velocity)
163{
164 rclcpp::Time current_time = this->now();
165 double time_difference = (current_time - previous_velocity_time_).seconds();
166 Eigen::Vector3f acceleration = Eigen::Vector3f::Zero();
167
168 if (time_difference > 0) {
169 acceleration[kVectorX] = (current_velocity[kVectorX] - previous_velocity_[kVectorX]) /
170 time_difference;
171 acceleration[kVectorY] = (current_velocity[kVectorY] - previous_velocity_[kVectorY]) /
172 time_difference;
173 acceleration[kVectorZ] = (current_velocity[kVectorZ] - previous_velocity_[kVectorZ]) /
174 time_difference;
175
176 geometry_msgs::msg::Vector3 acceleration_msg;
177 acceleration_msg.x = acceleration[kVectorX];
178 acceleration_msg.y = acceleration[kVectorY];
179 acceleration_msg.z = acceleration[kVectorZ];
180
181 acceleration_publisher_->publish(acceleration_msg);
182 }
183
184 previous_velocity_ = current_velocity;
185 previous_velocity_time_ = current_time;
186}
187
188} // namespace pointcloud_motion_capture
189
190int main(int argc, char ** argv)
191{
192 rclcpp::init(argc, argv);
193 rclcpp::spin(std::make_shared<pointcloud_motion_capture::MotionCapture>());
194 rclcpp::shutdown();
195 return 0;
196}
rclcpp::Publisher< geometry_msgs::msg::Vector3 >::SharedPtr acceleration_publisher_
ROS2 publisher to send the calculated object acceleration.
@ kCentroidY
Index for the Y-coordinate of the centroid.
@ kCentroidX
Index for the X-coordinate of the centroid.
@ kCentroidZ
Index for the Z-coordinate of the centroid.
void publishData()
Publishes the calculated position, velocity, and acceleration.
double kDefaultPublishRate
Default publish rate in Hz for publishing position, velocity, and acceleration.
int kDefaultQueueSize
Default queue size for ROS publishers and subscriptions.
Eigen::Vector4f getFilteredPosition()
Retrieves the filtered position of the object.
@ kVectorZ
Index for the Z-component of the velocity vector.
@ kVectorY
Index for the Y-component of the velocity vector.
@ kVectorX
Index for the X-component of the velocity vector.
std::string kDefaultPointCloudTopicFiltered
Default topic name for subscribing to the filtered point cloud data.
Eigen::Vector4f previous_position_
The previous position of the object in 3D space.
void updatePositionSamples(const Eigen::Vector4f &centroid)
Updates the position samples queue with a new centroid value.
std::string acceleration_publish_topic_
Topic name for publishing the calculated acceleration of an object.
void loadParameters()
Loads parameters from the ROS2 parameter server.
rclcpp::Time previous_time_
The timestamp of the previous position sample.
std::queue< Eigen::Vector4f > position_queue_
Queue to store recent position samples for calculating position.
int kDefaultPositionSamples
Default number of position samples used for calculations.
Eigen::Vector3f publishVelocity(const Eigen::Vector4f &current_position)
Publishes the object's velocity to a ROS topic.
std::string kDefaultAccelerationPublishTopic
Default topic name for publishing the calculated object acceleration.
std::queue< Eigen::Vector3f > velocity_queue_
Queue to store recent velocity samples for calculating velocity.
int kDefaultVelocitySamples
Default number of velocity samples used for calculations.
Eigen::Vector3f getFilteredVelocity()
Retrieves the filtered velocity of the object.
int velocity_samples_
Number of velocity samples used for calculations.
std::string kDefaultPositionPublishTopic
Default topic name for publishing the calculated object position.
int position_samples_
Number of position samples used for calculations.
rclcpp::Publisher< geometry_msgs::msg::Vector3 >::SharedPtr velocity_publisher_
ROS2 publisher to send the calculated object velocity.
std::string point_cloud_topic_filtered_
Topic name for subscribing to filtered point cloud data.
double kMillisecondsPerSecond
Conversion factor from seconds to milliseconds.
std::string kDefaultVelocityPublishTopic
Default topic name for publishing the calculated object velocity.
MotionCapture()
Constructor for the MotionCapture class.
int queue_size_
Queue size for message publishers and subscriptions.
rclcpp::TimerBase::SharedPtr timer_
Timer used for scheduling the publication of data.
Eigen::Vector3f previous_velocity_
The previous velocity of the object in 3D space.
rclcpp::Subscription< sensor_msgs::msg::PointCloud2 >::SharedPtr subscription_
ROS2 subscription to receive PointCloud2 messages.
void pointCloudCallback(const sensor_msgs::msg::PointCloud2::SharedPtr msg)
Callback function for processing incoming PointCloud2 messages.
void publishPosition(const Eigen::Vector4f &centroid)
Publishes the object's position to a ROS topic.
void updateVelocitySamples(const Eigen::Vector3f &velocity)
Updates the velocity samples queue with a new velocity value.
void publishAcceleration(const Eigen::Vector3f &current_velocity)
Publishes the object's acceleration to a ROS topic.
std::string velocity_publish_topic_
Topic name for publishing the calculated velocity of an object.
rclcpp::Publisher< geometry_msgs::msg::Point >::SharedPtr position_publisher_
ROS2 publisher to send the calculated object position.
rclcpp::Time previous_velocity_time_
The timestamp of the previous velocity sample.
std::string position_publish_topic_
Topic name for publishing the calculated position of an object.
double publish_rate_
Publish rate for sending position, velocity, and acceleration data.
int main(int argc, char **argv)