Corentin Chauvin-Hameau – 2019-2020
Coverage Path Planning for an underwater robot surveying a marine farm
robot_simulator.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  *
4  * \brief Definition of underwater robot simulator node
5  * \author Corentin Chauvin-Hameau
6  * \date 2019
7  */
8 
9 #include "robot_simulator.hpp"
11 #include "mf_robot_simulator/Command.h"
12 #include "mf_robot_simulator/CartesianCommand.h"
13 #include "mf_common/Float32Array.h"
14 #include <visualization_msgs/Marker.h>
15 #include <nav_msgs/Odometry.h>
16 #include <geometry_msgs/TransformStamped.h>
17 #include <geometry_msgs/Pose.h>
18 #include <tf2/LinearMath/Matrix3x3.h>
19 #include <tf2_geometry_msgs/tf2_geometry_msgs.h>
20 #include <tf2_ros/transform_broadcaster.h>
21 #include <ros/ros.h>
22 #include <string>
23 #include <vector>
24 
25 using namespace std;
26 
27 
28 namespace mfcpp {
29 
30 RobotSimulator::RobotSimulator():
31  nh_("~")
32 {
33 
34 }
35 
36 
38 {
39 
40 }
41 
42 
44 {
45  // ROS parameters
46  vector<double> model_csts; // model constants
47 
48  nh_.param<float>("update_freq", update_freq_, 1.0);
49  nh_.param<string>("fixed_frame", fixed_frame_, "ocean");
50  nh_.param<string>("robot_frame", robot_frame_, "base_link");
51  nh_.param<float>("robot_length", robot_length_, 1.0);
52  nh_.param<float>("robot_radius", robot_radius_, 0.3);
53  nh_.param<int>("nbr_int_steps", nbr_int_steps_, 10);
54  nh_.param<vector<double>>("model_constants", model_csts, vector<double>(15, 0.0));
55  nh_.param<vector<double>>("init_state", state_, vector<double>(13, 0.0));
56  nh_.param<float>("bnd_delta_m", bnd_delta_m_, 0.02);
57  nh_.param<vector<double>>("bnd_input", bnd_input_, vector<double>(4, 0.0));
58 
59  // ROS publishers
60  odom_pub_ = nh_.advertise<nav_msgs::Odometry>("odom", 1);
61  state_pub_ = nh_.advertise<mf_common::Float32Array>("state", 1);
62  rviz_pub_ = nh_.advertise<visualization_msgs::Marker>("rviz_markers", 1);
63 
64  // ROS subscribers
65  control_input_sub_ = nh_.subscribe<mf_robot_simulator::Command>("control_input", 1, &RobotSimulator::control_input_cb, this);
66  cart_input_sub_ = nh_.subscribe<mf_robot_simulator::CartesianCommand>(
67  "cart_input", 1, &RobotSimulator::cart_input_cb, this
68  );
69  pose_input_sub_ = nh_.subscribe<geometry_msgs::Pose>("pose_input", 1, &RobotSimulator::pose_input_cb, this);
70 
71  // Simulator initialisation
72  input_ = {0, 0, 0, 0};
73  cart_input_ = {0, 0, 0};
74  robot_model_ = RobotModel(model_csts);
75 
76 }
77 
78 
80 {
81  init_node();
82 
83  ros::Rate loop_rate(update_freq_);
84  float dt = 1/update_freq_;
85 
86  while(ros::ok()) {
87  ros::spinOnce();
88 
89  update_state(dt);
90  publish_state();
91 
92  loop_rate.sleep();
93  }
94 
95  ros::spin();
96 }
97 
98 
100 {
101  cout << "Robot state: " << endl
102  << "pos=(" << state_[0] << ", " << state_[1] << ", " << state_[2] << ")\n"
103  << "rot=(" << state_[3] << ", " << state_[4] << ", " << state_[5] << ")\n"
104  << "lin_speed=(" << state_[6] << ", " << state_[7] << ", " << state_[8] << ")\n"
105  << "ang_speed=(" << state_[9] << ", " << state_[10] << ", " << state_[11] << ")\n"
106  << "delta_m=" << state_[12] << endl;
107 }
108 
109 
110 void RobotSimulator::control_input_cb(const mf_robot_simulator::Command::ConstPtr &msg)
111 {
112  input_[0] = msg->n;
113  input_[1] = msg->delta_r;
114  input_[2] = msg->delta_e;
115  input_[3] = msg->P;
116 
117  for (int i = 0; i < input_.size(); i++) {
118  if (abs(input_[i]) > bnd_input_[i])
119  input_[i] = copysign(bnd_input_[i], input_[i]);
120  }
121 }
122 
123 
124 void RobotSimulator::cart_input_cb(const mf_robot_simulator::CartesianCommand::ConstPtr &msg)
125 {
126  cart_input_[0] = msg->v_x;
127  cart_input_[1] = msg->v_y;
128  cart_input_[2] = msg->v_z;
129 }
130 
131 
132 void RobotSimulator::pose_input_cb(const geometry_msgs::Pose::ConstPtr &msg)
133 {
134  state_[0] = msg->position.x;
135  state_[1] = msg->position.y;
136  state_[2] = msg->position.z;
137 
138  tf2::Quaternion quat(msg->orientation.x, msg->orientation.y, msg->orientation.z,
139  msg->orientation.w);
140  tf2::Matrix3x3(quat).getRPY(state_[3], state_[4], state_[5]);
141 }
142 
143 
145 {
146  // Integrate the model
148 
149  // Bound the ballast state
150  if (abs(state_[12]) >= bnd_delta_m_) {
151  state_[12] = copysign(bnd_delta_m_, state_[12]);
152  }
153 
154  // Apply the debug cartesian control signal
155  state_[0] += cart_input_[0] * dt;
156  state_[1] += cart_input_[1] * dt;
157  state_[2] += cart_input_[2] * dt;
158 
159 }
160 
161 
163 {
164  // Publish state
165  mf_common::Float32Array state_msg;
166  vector<float> float_state(state_.begin(), state_.end());
167  state_msg.data = float_state;
168  state_pub_.publish(state_msg);
169 
170  // Publish odometry
171  nav_msgs::Odometry odom;
172  odom.header.stamp = ros::Time::now();
173  odom.header.frame_id = fixed_frame_;
174  odom.child_frame_id = robot_frame_;
175  odom.pose.pose.position.x = state_[0];
176  odom.pose.pose.position.y = state_[1];
177  odom.pose.pose.position.z = state_[2];
178 
179  tf2::Quaternion quat;
180  quat.setRPY(state_[3], state_[4], state_[5]);
181  tf2::convert(quat, odom.pose.pose.orientation);
182 
183  odom.twist.twist.linear.x = state_[6];
184  odom.twist.twist.linear.y = state_[7];
185  odom.twist.twist.linear.z = state_[8];
186  odom.twist.twist.angular.x = state_[9];
187  odom.twist.twist.angular.y = state_[10];
188  odom.twist.twist.angular.z = state_[11];
189 
190  odom_pub_.publish(odom);
191 
192  // Broadcast transform
193  geometry_msgs::TransformStamped transform;
194  transform.header.stamp = ros::Time::now();
195  transform.header.frame_id = fixed_frame_;
196  transform.child_frame_id = robot_frame_;
197  transform.transform.translation.x = odom.pose.pose.position.x;
198  transform.transform.translation.y = odom.pose.pose.position.y;
199  transform.transform.translation.z = odom.pose.pose.position.z;
200  transform.transform.rotation.x = odom.pose.pose.orientation.x;
201  transform.transform.rotation.y = odom.pose.pose.orientation.y;
202  transform.transform.rotation.z = odom.pose.pose.orientation.z;
203  transform.transform.rotation.w = odom.pose.pose.orientation.w;
204  tf_br_.sendTransform(transform);
205 
206  // Publish Rviz marker
207  visualization_msgs::Marker marker;
208  marker.header.frame_id = robot_frame_;
209  marker.header.stamp = ros::Time::now();
210  marker.ns = "robot";
211  marker.lifetime = ros::Duration(1/update_freq_);
212  marker.color.r = 0.4;
213  marker.color.g = 0.4;
214  marker.color.b = 0.4;
215  marker.color.a = 1.0;
216 
217  marker.type = visualization_msgs::Marker::CYLINDER;
218  marker.action = visualization_msgs::Marker::ADD;
219 
220  marker.pose.orientation.x = 0;
221  marker.pose.orientation.y = 0.7071068;
222  marker.pose.orientation.z = 0;
223  marker.pose.orientation.w = 0.7071068;
224 
225  marker.scale.x = 2*robot_radius_;
226  marker.scale.y = 2*robot_radius_;
227  marker.scale.z = robot_length_;
228 
229  rviz_pub_.publish(marker);
230 }
231 
232 
233 
234 } // namespace mfcpp
235 
236 
237 /**
238  * \brief Main function called before node initialisation
239  */
240 int main(int argc, char **argv)
241 {
242  ros::init(argc, argv, "robot_simulator");
243  mfcpp::RobotSimulator robot_simulator;
244  robot_simulator.run_node();
245  return 0;
246 }
float update_freq_
State update frequency.
Robot simulator.
Definition: common.hpp:23
Declaration of physical underwater robot model.
ros::Subscriber pose_input_sub_
ROS subscriber for setting the pose.
void init_node()
Initialise the node and its parameters.
ros::Publisher rviz_pub_
ROS publisher for rviz markers.
void control_input_cb(const mf_robot_simulator::Command::ConstPtr &msg)
Callback for the control input.
void pose_input_cb(const geometry_msgs::Pose::ConstPtr &msg)
Callback for setting the pose.
ros::Subscriber cart_input_sub_
ROS subscriber for the debug cartesian control input.
void run_node()
Run the simulator.
tf2_ros::TransformBroadcaster tf_br_
Tf broadcaster.
std::string fixed_frame_
Frame in which the pose is expressed.
int nbr_int_steps_
Initial number of integration steps during the update.
ros::Publisher state_pub_
ROS publisher for the current state.
void integrate(state_type &state, const input_type &input, double t1, double t2, double init_step)
Integrates the model over a period of time.
Definition: robot_model.cpp:51
RobotModel::input_type bnd_input_
void cart_input_cb(const mf_robot_simulator::CartesianCommand::ConstPtr &msg)
Callback for the debug cartesian control input.
Class defining the robot model.
Definition: robot_model.hpp:47
RobotModel::state_type state_
Current state of the robot.
void disp_state()
Display the current state.
void update_state(float dt)
Updates the robot state by integrating the ODE.
int main(int argc, char **argv)
Main function called before node initialisation.
float bnd_delta_m_
Bound on delta_m (ballast control)
Declaration of underwater robot simulator.
ros::Publisher odom_pub_
ROS publisher for the odometry output.
float robot_radius_
Radius of the robot (assuming cylindrical shape)
std::vector< float > cart_input_
Current debug cartesian control input.
void publish_state()
Publishes the robot state.
RobotModel robot_model_
Robot model.
ros::Subscriber control_input_sub_
ROS subscriber for the control input.
ros::NodeHandle nh_
ROS node handler.
RobotModel::input_type input_
Current control input.
float robot_length_
Length of the robot (assuming cylindrical shape)
std::string robot_frame_
Frame of the robot.