-
Notifications
You must be signed in to change notification settings - Fork 16
/
rviz_cam_synchronizer.cpp
194 lines (143 loc) · 5.67 KB
/
rviz_cam_synchronizer.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/** \file
\brief Defines class that will synchronize rviz camera position and orientation according to gazebo camera.
\author Petr Štibinger - [email protected] (original implementation)
\author Vojtěch Spurný - [email protected] (rewrite)
*/
// Include the headers
#include <ros/ros.h>
#include <geometry_msgs/TransformStamped.h>
#include <tf2_ros/transform_broadcaster.h>
#include <gazebo/gazebo.hh>
#include <gazebo/msgs/pose.pb.h>
#include <gazebo/msgs/poses_stamped.pb.h>
namespace gazebo
{
typedef boost::shared_ptr<const msgs::Pose> GazeboPoseConstPtr;
typedef boost::shared_ptr<const msgs::PosesStamped> GazeboPosesStampedConstPtr;
/* class CamSynchronizer //{ */
class CamSynchronizer : public WorldPlugin {
public:
virtual ~CamSynchronizer();
void Load(physics::WorldPtr model, sdf::ElementPtr sdf);
private:
ignition::math::Vector3d target_position_;
std::mutex mutex_target_position_;
std::atomic_bool got_target_position_;
// Gazebo subscribers
transport::NodePtr gz_node_;
transport::SubscriberPtr gz_cam_sub_;
transport::SubscriberPtr target_pose_sub_;
// ROS publisher
tf2_ros::TransformBroadcaster* broadcaster_;
ros::Time last_msg_timestamp_; // default constructor fills sec(0), nsec(0)
// parameters
std::string _target_frame_id_;
std::string _world_origin_frame_id_;
std::string _frame_to_follow_;
// callbacks
void callbackGazeboCameraPose(const GazeboPoseConstPtr& msg);
void callbackGazeboTargetPose(const GazeboPosesStampedConstPtr& msg);
// help functions
void publishTF(const ignition::math::Pose3d& cam_pose);
ignition::math::Quaterniond getCamOrientation(const ignition::math::Vector3d& cam_position);
ignition::math::Vector3d msg2position(const GazeboPoseConstPtr& msg);
geometry_msgs::Transform pose2transform(const ignition::math::Pose3d& pose);
};
//}
/* ~CamSynchronizer() //{ */
CamSynchronizer::~CamSynchronizer() {
delete broadcaster_;
}
//}
/* Load(...) //{ */
void CamSynchronizer::Load([[maybe_unused]] physics::WorldPtr model, sdf::ElementPtr sdf) {
// Make sure the ROS node for Gazebo has already been initialized
if (!ros::isInitialized()) {
ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
<< "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
return;
}
_target_frame_id_ = sdf->Get<std::string>("target_frame_id");
_world_origin_frame_id_ = sdf->Get<std::string>("world_origin_frame_id");
_frame_to_follow_ = sdf->Get<std::string>("frame_to_follow");
gz_node_ = transport::NodePtr(new transport::Node());
gz_node_->Init();
got_target_position_ = false;
broadcaster_ = new tf2_ros::TransformBroadcaster();
gz_cam_sub_ = gz_node_->Subscribe("~/user_camera/pose", &CamSynchronizer::callbackGazeboCameraPose, this, 1);
target_pose_sub_ = gz_node_->Subscribe("~/pose/info", &CamSynchronizer::callbackGazeboTargetPose, this, 1);
ROS_INFO("[GazeboRvizCamSynchronizer]: Initialized");
}
//}
/* callbackGazeboCameraPoseCallback(...) //{ */
void CamSynchronizer::callbackGazeboCameraPose(const GazeboPoseConstPtr& msg) {
if (!got_target_position_.load()) {
return;
}
const ignition::math::Vector3d cam_position = msg2position(msg);
const ignition::math::Quaterniond cam_orientation = getCamOrientation(cam_position);
const ignition::math::Pose3d cam_pose(cam_position, cam_orientation);
publishTF(cam_pose);
}
//}
/* callbackGazeboTargetPose(...) //{ */
void CamSynchronizer::callbackGazeboTargetPose(const GazeboPosesStampedConstPtr& msg) {
for (int i = 0; i < msg->pose_size(); i++) {
if (msg->pose(i).name() == _frame_to_follow_) {
std::scoped_lock lock(mutex_target_position_);
target_position_.X() = msg->pose(i).position().x();
target_position_.Y() = msg->pose(i).position().y();
target_position_.Z() = msg->pose(i).position().z();
got_target_position_ = true;
return;
}
}
}
//}
/* getCamOrientation(...)//{ */
ignition::math::Quaterniond CamSynchronizer::getCamOrientation(const ignition::math::Vector3d& cam_pose) {
std::scoped_lock lock(mutex_target_position_);
ignition::math::Matrix4d rotation_matrix = ignition::math::Matrix4d::LookAt(cam_pose, target_position_);
return rotation_matrix.Rotation();
}
//}
/* msg2position (...)//{ */
ignition::math::Vector3d CamSynchronizer::msg2position(const GazeboPoseConstPtr& msg) {
ignition::math::Vector3d pos;
pos.X() = msg->position().x();
pos.Y() = msg->position().y();
pos.Z() = msg->position().z();
return pos;
}
//}
/* pose2transform(...) //{ */
geometry_msgs::Transform CamSynchronizer::pose2transform(const ignition::math::Pose3d& pose) {
geometry_msgs::Transform tf;
tf.translation.x = pose.Pos().X();
tf.translation.y = pose.Pos().Y();
tf.translation.z = pose.Pos().Z();
tf.rotation.w = pose.Rot().W();
tf.rotation.x = pose.Rot().X();
tf.rotation.y = pose.Rot().Y();
tf.rotation.z = pose.Rot().Z();
return tf;
}
//}
/* publishTF(...) //{ */
void CamSynchronizer::publishTF(const ignition::math::Pose3d& cam_pose) {
ros::Time current_time = ros::Time::now();
if (!(current_time > last_msg_timestamp_)) {
return;
}
geometry_msgs::TransformStamped tf;
tf.header.frame_id = _world_origin_frame_id_;
tf.header.stamp = current_time;
tf.child_frame_id = _target_frame_id_;
tf.transform = pose2transform(cam_pose);
broadcaster_->sendTransform(tf);
last_msg_timestamp_ = current_time;
}
//}
// Register this plugin with the simulator
GZ_REGISTER_WORLD_PLUGIN(CamSynchronizer)
} // namespace gazebo