gimbal_base.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2021, Qiayuan Liao
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *******************************************************************************/
33 
34 //
35 // Created by qiayuan on 1/16/21.
36 //
38 
39 #include <string>
40 #include <angles/angles.h>
42 #include <rm_common/ori_tool.h>
45 #include <tf/transform_datatypes.h>
46 
47 namespace rm_gimbal_controllers
48 {
49 bool Controller::init(hardware_interface::RobotHW* robot_hw, ros::NodeHandle& root_nh, ros::NodeHandle& controller_nh)
50 {
51  XmlRpc::XmlRpcValue xml_rpc_value;
52  bool enable_feedforward;
53  enable_feedforward = controller_nh.getParam("feedforward", xml_rpc_value);
54  if (enable_feedforward)
55  {
56  ROS_ASSERT(xml_rpc_value.hasMember("mass_origin"));
57  ROS_ASSERT(xml_rpc_value.hasMember("gravity"));
58  ROS_ASSERT(xml_rpc_value.hasMember("enable_gravity_compensation"));
59  }
60  mass_origin_.x = enable_feedforward ? (double)xml_rpc_value["mass_origin"][0] : 0.;
61  mass_origin_.z = enable_feedforward ? (double)xml_rpc_value["mass_origin"][2] : 0.;
62  gravity_ = enable_feedforward ? (double)xml_rpc_value["gravity"] : 0.;
63  enable_gravity_compensation_ = enable_feedforward && (bool)xml_rpc_value["enable_gravity_compensation"];
64 
65  ros::NodeHandle chassis_vel_nh(controller_nh, "chassis_vel");
66  chassis_vel_ = std::make_shared<ChassisVel>(chassis_vel_nh);
67  ros::NodeHandle nh_bullet_solver = ros::NodeHandle(controller_nh, "bullet_solver");
68  bullet_solver_ = std::make_shared<BulletSolver>(nh_bullet_solver);
69 
70  config_ = { .yaw_k_v_ = getParam(controller_nh, "controllers/yaw/k_v", 0.),
71  .pitch_k_v_ = getParam(controller_nh, "controllers/pitch/k_v", 0.),
72  .chassis_comp_a_ = getParam(controller_nh, "controllers/yaw/chassis_comp_a", 0.),
73  .chassis_comp_b_ = getParam(controller_nh, "controllers/yaw/chassis_comp_b", 0.),
74  .chassis_comp_c_ = getParam(controller_nh, "controllers/yaw/chassis_comp_c", 0.),
75  .chassis_comp_d_ = getParam(controller_nh, "controllers/yaw/chassis_comp_d", 0.),
76  .accel_pitch_ = getParam(controller_nh, "controllers/pitch/accel", 99.),
77  .accel_yaw_ = getParam(controller_nh, "controllers/yaw/accel", 99.) };
78  config_rt_buffer_.initRT(config_);
79  d_srv_ = new dynamic_reconfigure::Server<rm_gimbal_controllers::GimbalBaseConfig>(controller_nh);
80  dynamic_reconfigure::Server<rm_gimbal_controllers::GimbalBaseConfig>::CallbackType cb =
81  [this](auto&& PH1, auto&& PH2) { reconfigCB(PH1, PH2); };
82  d_srv_->setCallback(cb);
83 
84  hardware_interface::EffortJointInterface* effort_joint_interface =
86  if (controller_nh.getParam("controllers", xml_rpc_value))
87  {
88  for (const auto& it : xml_rpc_value)
89  {
90  ros::NodeHandle nh = ros::NodeHandle(controller_nh, "controllers/" + it.first);
91  ros::NodeHandle nh_pid_pos = ros::NodeHandle(controller_nh, "controllers/" + it.first + "/pid_pos");
92 
93  // Get URDF info about joint
95  int axis;
96  if (!urdf.initParamWithNodeHandle("robot_description", controller_nh))
97  {
98  ROS_ERROR("Failed to parse urdf file");
99  return false;
100  }
101  auto joint_urdf = urdf.getJoint(getParam(nh, "joint", std::string()));
102  if (!joint_urdf)
103  {
104  ROS_ERROR("Could not find joint in urdf");
105  return false;
106  }
107  else
108  {
109  axis = (joint_urdf->axis.x == 1) * 0 + (joint_urdf->axis.y == 1) * 1 + (joint_urdf->axis.z == 1) * 2;
110  joint_urdfs_.insert(std::make_pair(axis, joint_urdf));
111  }
112 
113  ctrls_.insert(std::make_pair(axis, std::make_unique<effort_controllers::JointVelocityController>()));
114  pid_pos_.insert(std::make_pair(axis, std::make_unique<control_toolbox::Pid>()));
115  pos_des_in_limit_.insert(std::make_pair(axis, true));
116  pos_state_pub_.insert(std::make_pair(
117  axis, std::make_unique<realtime_tools::RealtimePublisher<rm_msgs::GimbalPosState>>(nh, "pos_state", 1)));
118 
119  if (!ctrls_.at(axis)->init(effort_joint_interface, nh) || !pid_pos_.at(axis)->init(nh_pid_pos))
120  return false;
121  }
122  }
123 
124  robot_state_handle_ = robot_hw->get<rm_control::RobotStateInterface>()->getHandle("robot_state");
125  if (!controller_nh.hasParam("imu_name"))
126  has_imu_ = false;
127  if (has_imu_)
128  {
129  imu_name_ = getParam(controller_nh, "imu_name", static_cast<std::string>("gimbal_imu"));
130  hardware_interface::ImuSensorInterface* imu_sensor_interface =
132  imu_sensor_handle_ = imu_sensor_interface->getHandle(imu_name_);
133  }
134  else
135  {
136  ROS_INFO("Param imu_name has not set, use motors' data instead of imu.");
137  }
138 
140  odom2gimbal_des_.header.frame_id = "odom";
141  odom2gimbal_des_.child_frame_id = gimbal_des_frame_id_;
142  odom2gimbal_des_.transform.rotation.w = 1.;
143  odom2gimbal_.header.frame_id = "odom";
144  odom2gimbal_.child_frame_id = getGimbalFrameID(joint_urdfs_);
145  odom2gimbal_.transform.rotation.w = 1.;
146  odom2base_.header.frame_id = "odom";
147  odom2base_.child_frame_id = getBaseFrameID(joint_urdfs_);
148  odom2base_.transform.rotation.w = 1.;
149 
150  cmd_gimbal_sub_ = controller_nh.subscribe<rm_msgs::GimbalCmd>("command", 1, &Controller::commandCB, this);
151  data_track_sub_ = controller_nh.subscribe<rm_msgs::TrackData>("/track", 1, &Controller::trackCB, this);
152  publish_rate_ = getParam(controller_nh, "publish_rate", 100.);
153  error_pub_.reset(new realtime_tools::RealtimePublisher<rm_msgs::GimbalDesError>(controller_nh, "error", 100));
154 
155  return true;
156 }
157 
158 void Controller::starting(const ros::Time& /*unused*/)
159 {
160  state_ = RATE;
161  state_changed_ = true;
162  start_ = true;
163 }
164 
165 void Controller::update(const ros::Time& time, const ros::Duration& period)
166 {
169  config_ = *config_rt_buffer_.readFromRT();
170  try
171  {
172  odom2gimbal_ = robot_state_handle_.lookupTransform("odom", odom2gimbal_.child_frame_id, time);
173  odom2base_ = robot_state_handle_.lookupTransform("odom", odom2base_.child_frame_id, time);
174  }
175  catch (tf2::TransformException& ex)
176  {
177  ROS_WARN_THROTTLE(5, "%s\n", ex.what());
178  return;
179  }
181  if (state_ != cmd_gimbal_.mode)
182  {
183  state_ = cmd_gimbal_.mode;
184  state_changed_ = true;
185  }
186  switch (state_)
187  {
188  case RATE:
189  rate(time, period);
190  break;
191  case TRACK:
192  track(time);
193  break;
194  case DIRECT:
195  direct(time);
196  break;
197  case TRAJ:
198  traj(time);
199  break;
200  }
201  moveJoint(time, period);
202 }
203 
204 void Controller::setDes(const ros::Time& time, double yaw_des, double pitch_des)
205 {
206  tf2::Quaternion odom2base, odom2gimbal_des;
207  tf2::fromMsg(odom2base_.transform.rotation, odom2base);
208  odom2gimbal_des.setRPY(0, pitch_des, yaw_des);
209  tf2::Quaternion base2gimbal_des = odom2base.inverse() * odom2gimbal_des;
210  for (const auto& it : joint_urdfs_)
211  pos_des_in_limit_[it.first] = setDesIntoLimit(base2gimbal_des, it.second, base2gimbal_des);
212  odom2gimbal_des_.transform.rotation = tf2::toMsg(odom2base * base2gimbal_des);
213  odom2gimbal_des_.header.stamp = time;
214  robot_state_handle_.setTransform(odom2gimbal_des_, "rm_gimbal_controllers");
215 }
216 
217 void Controller::rate(const ros::Time& time, const ros::Duration& period)
218 {
219  if (state_changed_)
220  { // on enter
221  state_changed_ = false;
222  ROS_INFO("[Gimbal] Enter RATE");
223  if (start_)
224  {
225  odom2gimbal_des_.transform.rotation = odom2gimbal_.transform.rotation;
226  odom2gimbal_des_.header.stamp = time;
227  robot_state_handle_.setTransform(odom2gimbal_des_, "rm_gimbal_controllers");
228  start_ = false;
229  }
230  }
231  else
232  {
233  double roll{}, pitch{}, yaw{};
234  quatToRPY(odom2gimbal_des_.transform.rotation, roll, pitch, yaw);
235  setDes(time, yaw + period.toSec() * cmd_gimbal_.rate_yaw, pitch + period.toSec() * cmd_gimbal_.rate_pitch);
236  }
237 }
238 
239 void Controller::track(const ros::Time& time)
240 {
241  if (state_changed_)
242  { // on enter
243  state_changed_ = false;
244  ROS_INFO("[Gimbal] Enter TRACK");
245  }
246  double roll_real, pitch_real, yaw_real;
247  quatToRPY(odom2gimbal_.transform.rotation, roll_real, pitch_real, yaw_real);
248  double yaw_compute = yaw_real;
249  double pitch_compute = -pitch_real;
250  geometry_msgs::Point target_pos = data_track_.position;
251  geometry_msgs::Vector3 target_vel{};
252  if (data_track_.id != 12)
253  target_vel = data_track_.velocity;
254  try
255  {
256  if (!data_track_.header.frame_id.empty())
257  {
258  geometry_msgs::TransformStamped transform =
259  robot_state_handle_.lookupTransform("odom", data_track_.header.frame_id, data_track_.header.stamp);
260  tf2::doTransform(target_pos, target_pos, transform);
261  tf2::doTransform(target_vel, target_vel, transform);
262  }
263  }
264  catch (tf2::TransformException& ex)
265  {
266  ROS_WARN("%s", ex.what());
267  }
268  double yaw = data_track_.yaw + data_track_.v_yaw * ((time - data_track_.header.stamp).toSec());
269  while (yaw > M_PI)
270  yaw -= 2 * M_PI;
271  while (yaw < -M_PI)
272  yaw += 2 * M_PI;
273  target_pos.x += target_vel.x * (time - data_track_.header.stamp).toSec() - odom2gimbal_.transform.translation.x;
274  target_pos.y += target_vel.y * (time - data_track_.header.stamp).toSec() - odom2gimbal_.transform.translation.y;
275  target_pos.z += target_vel.z * (time - data_track_.header.stamp).toSec() - odom2gimbal_.transform.translation.z;
276  target_vel.x -= chassis_vel_->linear_->x();
277  target_vel.y -= chassis_vel_->linear_->y();
278  target_vel.z -= chassis_vel_->linear_->z();
279  bool solve_success = bullet_solver_->solve(target_pos, target_vel, cmd_gimbal_.bullet_speed, yaw, data_track_.v_yaw,
280  data_track_.radius_1, data_track_.radius_2, data_track_.dz,
281  data_track_.armors_num, chassis_vel_->angular_->z());
282  bullet_solver_->judgeShootBeforehand(time, data_track_.v_yaw);
283 
284  if (publish_rate_ > 0.0 && last_publish_time_ + ros::Duration(1.0 / publish_rate_) < time)
285  {
286  if (error_pub_->trylock())
287  {
288  double error =
289  bullet_solver_->getGimbalError(target_pos, target_vel, data_track_.yaw, data_track_.v_yaw,
290  data_track_.radius_1, data_track_.radius_2, data_track_.dz,
291  data_track_.armors_num, yaw_compute, pitch_compute, cmd_gimbal_.bullet_speed);
292  error_pub_->msg_.stamp = time;
293  error_pub_->msg_.error = solve_success ? error : 1.0;
294  error_pub_->unlockAndPublish();
295  }
296  bullet_solver_->bulletModelPub(odom2gimbal_, time);
297  last_publish_time_ = time;
298  }
299 
300  if (solve_success)
301  setDes(time, bullet_solver_->getYaw(), bullet_solver_->getPitch());
302  else
303  {
304  odom2gimbal_des_.header.stamp = time;
305  robot_state_handle_.setTransform(odom2gimbal_des_, "rm_gimbal_controllers");
306  }
307 }
308 
309 void Controller::direct(const ros::Time& time)
310 {
311  if (state_changed_)
312  { // on enter
313  state_changed_ = false;
314  ROS_INFO("[Gimbal] Enter DIRECT");
315  }
316  geometry_msgs::Point aim_point_odom = cmd_gimbal_.target_pos.point;
317  try
318  {
319  if (!cmd_gimbal_.target_pos.header.frame_id.empty())
320  tf2::doTransform(aim_point_odom, aim_point_odom,
321  robot_state_handle_.lookupTransform("odom", cmd_gimbal_.target_pos.header.frame_id,
322  cmd_gimbal_.target_pos.header.stamp));
323  }
324  catch (tf2::TransformException& ex)
325  {
326  ROS_WARN("%s", ex.what());
327  }
328  double yaw = std::atan2(aim_point_odom.y - odom2gimbal_.transform.translation.y,
329  aim_point_odom.x - odom2gimbal_.transform.translation.x);
330  double pitch = -std::atan2(aim_point_odom.z - odom2gimbal_.transform.translation.z,
331  std::sqrt(std::pow(aim_point_odom.x - odom2gimbal_.transform.translation.x, 2) +
332  std::pow(aim_point_odom.y - odom2gimbal_.transform.translation.y, 2)));
333  setDes(time, yaw, pitch);
334 }
335 
336 void Controller::traj(const ros::Time& time)
337 {
338  if (state_changed_)
339  { // on enter
340  state_changed_ = false;
341  ROS_INFO("[Gimbal] Enter TRAJ");
342  }
343  double traj[3]{ 0. };
344  try
345  {
346  if (!cmd_gimbal_.traj_frame_id.empty())
347  {
348  geometry_msgs::TransformStamped odom2traj =
349  robot_state_handle_.lookupTransform("odom", cmd_gimbal_.traj_frame_id, time);
350  quatToRPY(odom2traj.transform.rotation, traj[0], traj[1], traj[2]);
351  traj[1] += cmd_gimbal_.traj_pitch;
352  traj[2] += cmd_gimbal_.traj_yaw;
353  }
354  else
355  {
356  traj[1] = cmd_gimbal_.traj_pitch;
357  traj[2] = cmd_gimbal_.traj_yaw;
358  }
359  }
360  catch (tf2::TransformException& ex)
361  {
362  ROS_WARN("%s", ex.what());
363  }
364  setDes(time, traj[2], traj[1]);
365 }
366 
367 bool Controller::setDesIntoLimit(const tf2::Quaternion& base2gimbal_des, const urdf::JointConstSharedPtr& joint_urdf,
368  tf2::Quaternion& base2new_des)
369 {
370  double base2gimbal_current_des[3];
371  quatToRPY(toMsg(base2gimbal_des), base2gimbal_current_des[0], base2gimbal_current_des[1], base2gimbal_current_des[2]);
372  double upper_limit = joint_urdf->limits ? joint_urdf->limits->upper : 1e16;
373  double lower_limit = joint_urdf->limits ? joint_urdf->limits->lower : -1e16;
374  int index = (joint_urdf->axis.x == 1) * 0 + (joint_urdf->axis.y == 1) * 1 + (joint_urdf->axis.z == 1) * 2;
375  if ((base2gimbal_current_des[index] <= upper_limit && base2gimbal_current_des[index] >= lower_limit) ||
376  (angles::two_pi_complement(base2gimbal_current_des[index]) <= upper_limit &&
377  angles::two_pi_complement(base2gimbal_current_des[index]) >= lower_limit))
378  {
379  base2new_des = base2gimbal_des;
380  return true;
381  }
382  else
383  {
384  base2gimbal_current_des[index] =
385  std::abs(angles::shortest_angular_distance(base2gimbal_current_des[index], upper_limit)) <
386  std::abs(angles::shortest_angular_distance(base2gimbal_current_des[index], lower_limit)) ?
387  upper_limit :
388  lower_limit;
389  base2new_des.setRPY(base2gimbal_current_des[0], base2gimbal_current_des[1], base2gimbal_current_des[2]);
390  return false;
391  }
392 }
393 
394 void Controller::moveJoint(const ros::Time& time, const ros::Duration& period)
395 {
396  geometry_msgs::Vector3 gyro, angular_vel;
397  if (has_imu_)
398  {
402  try
403  {
404  tf2::doTransform(gyro, angular_vel,
406  time));
407  }
408  catch (tf2::TransformException& ex)
409  {
410  ROS_WARN("%s", ex.what());
411  return;
412  }
413  }
414  else
415  {
416  if (ctrls_.find(0) != ctrls_.end())
417  angular_vel.x = ctrls_.at(0)->joint_.getVelocity();
418  if (ctrls_.find(1) != ctrls_.end())
419  angular_vel.y = ctrls_.at(1)->joint_.getVelocity();
420  if (ctrls_.find(2) != ctrls_.end())
421  angular_vel.z = ctrls_.at(2)->joint_.getVelocity();
422  }
423  double pos_real[3]{ 0. }, pos_des[3]{ 0. }, vel_des[3]{ 0. }, angle_error[3]{ 0. };
424  quatToRPY(odom2gimbal_des_.transform.rotation, pos_des[0], pos_des[1], pos_des[2]);
425  quatToRPY(odom2gimbal_.transform.rotation, pos_real[0], pos_real[1], pos_real[2]);
426  for (int i = 0; i < 3; i++)
427  angle_error[i] = angles::shortest_angular_distance(pos_real[i], pos_des[i]);
428  if (state_ == RATE)
429  {
430  vel_des[2] = cmd_gimbal_.rate_yaw;
431  vel_des[1] = cmd_gimbal_.rate_pitch;
432  }
433  else if (state_ == TRACK)
434  {
435  geometry_msgs::Point target_pos;
436  geometry_msgs::Vector3 target_vel;
437  bullet_solver_->getSelectedArmorPosAndVel(target_pos, target_vel, data_track_.position, data_track_.velocity,
438  data_track_.yaw, data_track_.v_yaw, data_track_.radius_1,
439  data_track_.radius_2, data_track_.dz, data_track_.armors_num);
440  target_vel.x -= chassis_vel_->linear_->x();
441  target_vel.y -= chassis_vel_->linear_->y();
442  target_vel.z -= chassis_vel_->linear_->z();
443  tf2::Vector3 target_pos_tf, target_vel_tf;
444  try
445  {
446  geometry_msgs::TransformStamped transform;
447  if (joint_urdfs_.find(2) != joint_urdfs_.end())
448  {
449  transform = robot_state_handle_.lookupTransform(odom2base_.child_frame_id, data_track_.header.frame_id,
450  data_track_.header.stamp);
451  tf2::doTransform(target_pos, target_pos, transform);
452  tf2::doTransform(target_vel, target_vel, transform);
453  tf2::fromMsg(target_pos, target_pos_tf);
454  tf2::fromMsg(target_vel, target_vel_tf);
455  vel_des[2] = target_pos_tf.cross(target_vel_tf).z() / std::pow((target_pos_tf.length()), 2);
456  }
457  if (joint_urdfs_.find(1) != joint_urdfs_.end())
458  {
459  transform = robot_state_handle_.lookupTransform(joint_urdfs_.at(1)->parent_link_name,
460  data_track_.header.frame_id, data_track_.header.stamp);
461  tf2::doTransform(target_pos, target_pos, transform);
462  tf2::doTransform(target_vel, target_vel, transform);
463  tf2::fromMsg(target_pos, target_pos_tf);
464  tf2::fromMsg(target_vel, target_vel_tf);
465  vel_des[1] = target_pos_tf.cross(target_vel_tf).y() / std::pow((target_pos_tf.length()), 2);
466  }
467  }
468  catch (tf2::TransformException& ex)
469  {
470  ROS_WARN("%s", ex.what());
471  }
472  }
473  for (const auto& in_limit : pos_des_in_limit_)
474  if (!in_limit.second)
475  vel_des[in_limit.first] = 0.;
476 
477  if (pid_pos_.find(1) != pid_pos_.end() && ctrls_.find(1) != ctrls_.end())
478  {
479  pid_pos_.at(1)->computeCommand(angle_error[1], period);
480  ctrls_.at(1)->setCommand(pid_pos_.at(1)->getCurrentCmd() + config_.pitch_k_v_ * vel_des[1] +
481  ctrls_.at(1)->joint_.getVelocity() - angular_vel.y);
482  ctrls_.at(1)->update(time, period);
483  ctrls_.at(1)->joint_.setCommand(ctrls_.at(1)->joint_.getCommand() + feedForward(time));
484  }
485  if (pid_pos_.find(2) != pid_pos_.end() && ctrls_.find(2) != ctrls_.end())
486  {
487  pid_pos_.at(2)->computeCommand(angle_error[2], period);
488  ctrls_.at(2)->setCommand(pid_pos_.at(2)->getCurrentCmd() -
489  updateCompensation(chassis_vel_->angular_->z()) * chassis_vel_->angular_->z() +
490  config_.yaw_k_v_ * vel_des[2] + ctrls_.at(2)->joint_.getVelocity() - angular_vel.z);
491  ctrls_.at(2)->update(time, period);
492  }
493 
494  // publish state
495  if (loop_count_ % 10 == 0)
496  {
497  for (const auto& pub : pos_state_pub_)
498  {
499  if (pub.second && pub.second->trylock())
500  {
501  pub.second->msg_.header.stamp = time;
502  pub.second->msg_.set_point = pos_des[pub.first];
503  pub.second->msg_.set_point_dot = vel_des[pub.first];
504  pub.second->msg_.process_value = pos_real[pub.first];
505  pub.second->msg_.error = angle_error[pub.first];
506  pub.second->msg_.command = pid_pos_[pub.first]->getCurrentCmd();
507  pub.second->unlockAndPublish();
508  }
509  }
510  }
511  loop_count_++;
512 }
513 
514 double Controller::feedForward(const ros::Time& time)
515 {
516  if (joint_urdfs_.find(1) != joint_urdfs_.end())
517  {
518  Eigen::Vector3d gravity(0, 0, -gravity_);
519  tf2::doTransform(gravity, gravity,
520  robot_state_handle_.lookupTransform(joint_urdfs_.at(1)->child_link_name, "base_link", time));
521  Eigen::Vector3d mass_origin(mass_origin_.x, 0, mass_origin_.z);
522  double feedforward = -mass_origin.cross(gravity).y();
524  {
525  Eigen::Vector3d gravity_compensation(0, 0, gravity_);
526  tf2::doTransform(gravity_compensation, gravity_compensation,
527  robot_state_handle_.lookupTransform(joint_urdfs_.at(1)->child_link_name,
528  joint_urdfs_.at(1)->parent_link_name, time));
529  feedforward -= mass_origin.cross(gravity_compensation).y();
530  }
531  return feedforward;
532  }
533  return 0.;
534 }
535 
537 {
538  double tf_period = odom2base_.header.stamp.toSec() - last_odom2base_.header.stamp.toSec();
539  double linear_x = (odom2base_.transform.translation.x - last_odom2base_.transform.translation.x) / tf_period;
540  double linear_y = (odom2base_.transform.translation.y - last_odom2base_.transform.translation.y) / tf_period;
541  double linear_z = (odom2base_.transform.translation.z - last_odom2base_.transform.translation.z) / tf_period;
542  double last_angular_position_x, last_angular_position_y, last_angular_position_z, angular_position_x,
543  angular_position_y, angular_position_z;
544  quatToRPY(odom2base_.transform.rotation, angular_position_x, angular_position_y, angular_position_z);
545  quatToRPY(last_odom2base_.transform.rotation, last_angular_position_x, last_angular_position_y,
546  last_angular_position_z);
547  double angular_x = angles::shortest_angular_distance(last_angular_position_x, angular_position_x) / tf_period;
548  double angular_y = angles::shortest_angular_distance(last_angular_position_y, angular_position_y) / tf_period;
549  double angular_z = angles::shortest_angular_distance(last_angular_position_z, angular_position_z) / tf_period;
550  double linear_vel[3]{ linear_x, linear_y, linear_z };
551  double angular_vel[3]{ angular_x, angular_y, angular_z };
552  chassis_vel_->update(linear_vel, angular_vel, tf_period);
554 }
555 
556 std::string Controller::getGimbalFrameID(std::unordered_map<int, urdf::JointConstSharedPtr> joint_urdfs)
557 {
558  if (joint_urdfs.find(1) != joint_urdfs.end())
559  return joint_urdfs.at(1)->child_link_name.c_str();
560  if (joint_urdfs.find(0) != joint_urdfs.end())
561  return joint_urdfs.at(0)->child_link_name.c_str();
562  if (joint_urdfs.find(2) != joint_urdfs.end())
563  return joint_urdfs.at(2)->child_link_name.c_str();
564  return std::string();
565 }
566 
567 std::string Controller::getBaseFrameID(std::unordered_map<int, urdf::JointConstSharedPtr> joint_urdfs)
568 {
569  if (joint_urdfs.find(2) != joint_urdfs.end())
570  return joint_urdfs.at(2)->parent_link_name.c_str();
571  if (joint_urdfs.find(0) != joint_urdfs.end())
572  return joint_urdfs.at(0)->parent_link_name.c_str();
573  if (joint_urdfs.find(1) != joint_urdfs.end())
574  return joint_urdfs.at(1)->parent_link_name.c_str();
575  return std::string();
576 }
577 
578 double Controller::updateCompensation(double chassis_vel_angular_z)
579 {
581  config_.chassis_comp_a_ * sin(config_.chassis_comp_b_ * chassis_vel_angular_z + config_.chassis_comp_c_) +
583  return chassis_compensation_;
584 }
585 
586 void Controller::commandCB(const rm_msgs::GimbalCmdConstPtr& msg)
587 {
589 }
590 
591 void Controller::trackCB(const rm_msgs::TrackDataConstPtr& msg)
592 {
593  if (msg->id == 0)
594  return;
596 }
597 
598 void Controller::reconfigCB(rm_gimbal_controllers::GimbalBaseConfig& config, uint32_t /*unused*/)
599 {
600  ROS_INFO("[Gimbal Base] Dynamic params change");
602  {
603  GimbalConfig init_config = *config_rt_buffer_.readFromNonRT(); // config init use yaml
604  config.yaw_k_v_ = init_config.yaw_k_v_;
605  config.pitch_k_v_ = init_config.pitch_k_v_;
606  config.chassis_comp_a_ = init_config.chassis_comp_a_;
607  config.chassis_comp_b_ = init_config.chassis_comp_b_;
608  config.chassis_comp_c_ = init_config.chassis_comp_c_;
609  config.chassis_comp_d_ = init_config.chassis_comp_d_;
610  config.accel_pitch_ = init_config.accel_pitch_;
611  config.accel_yaw_ = init_config.accel_yaw_;
613  }
614  GimbalConfig config_non_rt{ .yaw_k_v_ = config.yaw_k_v_,
615  .pitch_k_v_ = config.pitch_k_v_,
616  .chassis_comp_a_ = config.chassis_comp_a_,
617  .chassis_comp_b_ = config.chassis_comp_b_,
618  .chassis_comp_c_ = config.chassis_comp_c_,
619  .chassis_comp_d_ = config.chassis_comp_d_,
620  .accel_pitch_ = config.accel_pitch_,
621  .accel_yaw_ = config.accel_yaw_ };
622  config_rt_buffer_.writeFromNonRT(config_non_rt);
623 }
624 
625 } // namespace rm_gimbal_controllers
626 
rm_gimbal_controllers::Controller::has_imu_
bool has_imu_
Definition: gimbal_base.h:196
rm_control::RobotStateHandle::lookupTransform
geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time)
rm_gimbal_controllers::Controller::RATE
@ RATE
Definition: gimbal_base.h:235
realtime_tools::RealtimeBuffer::writeFromNonRT
void writeFromNonRT(const T &data)
rm_gimbal_controllers::Controller::updateChassisVel
void updateChassisVel()
Definition: gimbal_base.cpp:567
rm_gimbal_controllers::Controller::odom2gimbal_
geometry_msgs::TransformStamped odom2gimbal_
Definition: gimbal_base.h:217
angles::shortest_angular_distance
static double shortest_angular_distance(double from, double to)
gimbal_base.h
rm_gimbal_controllers::Controller::setDesIntoLimit
bool setDesIntoLimit(const tf2::Quaternion &base2gimbal_des, const urdf::JointConstSharedPtr &joint_urdf, tf2::Quaternion &base2new_des)
Definition: gimbal_base.cpp:398
rm_gimbal_controllers::Controller::track
void track(const ros::Time &time)
Definition: gimbal_base.cpp:270
rm_gimbal_controllers::Controller::start_
bool start_
Definition: gimbal_base.h:241
rm_gimbal_controllers::Controller::track_rt_buffer_
realtime_tools::RealtimeBuffer< rm_msgs::TrackData > track_rt_buffer_
Definition: gimbal_base.h:207
rm_gimbal_controllers::Controller::data_track_sub_
ros::Subscriber data_track_sub_
Definition: gimbal_base.h:205
rm_gimbal_controllers::Controller::traj
void traj(const ros::Time &time)
Definition: gimbal_base.cpp:367
rm_gimbal_controllers::Controller::config_rt_buffer_
realtime_tools::RealtimeBuffer< GimbalConfig > config_rt_buffer_
Definition: gimbal_base.h:230
HardwareResourceManager< ImuSensorHandle >::getHandle
ImuSensorHandle getHandle(const std::string &name)
tf2::fromMsg
void fromMsg(const A &, B &b)
rm_gimbal_controllers::Controller::last_publish_time_
ros::Time last_publish_time_
Definition: gimbal_base.h:201
hardware_interface::InterfaceManager::get
T * get()
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
ROS_WARN_THROTTLE
#define ROS_WARN_THROTTLE(period,...)
rm_gimbal_controllers::GimbalConfig
Definition: gimbal_base.h:93
rm_gimbal_controllers::Controller::joint_urdfs_
std::unordered_map< int, urdf::JointConstSharedPtr > joint_urdfs_
Definition: gimbal_base.h:194
rm_gimbal_controllers::Controller::ctrls_
std::unordered_map< int, std::unique_ptr< effort_controllers::JointVelocityController > > ctrls_
Definition: gimbal_base.h:192
tf2::Quaternion::setRPY
void setRPY(const tf2Scalar &roll, const tf2Scalar &pitch, const tf2Scalar &yaw)
rm_control::RobotStateHandle::setTransform
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false) const
rm_gimbal_controllers::Controller::chassis_vel_
std::shared_ptr< ChassisVel > chassis_vel_
Definition: gimbal_base.h:225
rm_control::RobotStateInterface
hardware_interface::ImuSensorHandle::getFrameId
std::string getFrameId() const
rm_gimbal_controllers::Controller::d_srv_
dynamic_reconfigure::Server< rm_gimbal_controllers::GimbalBaseConfig > * d_srv_
Definition: gimbal_base.h:231
hardware_interface::ImuSensorHandle::getAngularVelocity
const double * getAngularVelocity() const
rm_gimbal_controllers::Controller::state_
int state_
Definition: gimbal_base.h:240
rm_gimbal_controllers::Controller::getBaseFrameID
std::string getBaseFrameID(std::unordered_map< int, urdf::JointConstSharedPtr > joint_urdfs)
Definition: gimbal_base.cpp:598
rm_gimbal_controllers::Controller::starting
void starting(const ros::Time &time) override
Definition: gimbal_base.cpp:189
rm_gimbal_controllers::Controller::enable_gravity_compensation_
bool enable_gravity_compensation_
Definition: gimbal_base.h:222
urdf::Model
getHandle
ROSCONSOLE_CONSOLE_IMPL_DECL void * getHandle(const std::string &name)
rm_gimbal_controllers::Controller::imu_name_
std::string imu_name_
Definition: gimbal_base.h:211
realtime_tools::RealtimeBuffer::readFromNonRT
T * readFromNonRT() const
rm_gimbal_controllers::Controller::moveJoint
void moveJoint(const ros::Time &time, const ros::Duration &period)
Definition: gimbal_base.cpp:425
rm_gimbal_controllers::Controller::rate
void rate(const ros::Time &time, const ros::Duration &period)
Definition: gimbal_base.cpp:248
rm_gimbal_controllers::Controller::gimbal_des_frame_id_
std::string gimbal_des_frame_id_
Definition: gimbal_base.h:211
rm_gimbal_controllers::Controller::publish_rate_
double publish_rate_
Definition: gimbal_base.h:212
rm_gimbal_controllers::Controller::cmd_gimbal_sub_
ros::Subscriber cmd_gimbal_sub_
Definition: gimbal_base.h:204
rm_gimbal_controllers::Controller::updateCompensation
double updateCompensation(double chassis_vel_angular_z)
Definition: gimbal_base.cpp:609
realtime_tools::RealtimePublisher
controller_interface::ControllerBase
rm_gimbal_controllers::Controller::DIRECT
@ DIRECT
Definition: gimbal_base.h:237
rm_gimbal_controllers::Controller::mass_origin_
geometry_msgs::Vector3 mass_origin_
Definition: gimbal_base.h:220
PLUGINLIB_EXPORT_CLASS
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
rm_gimbal_controllers::Controller::loop_count_
int loop_count_
Definition: gimbal_base.h:214
rm_gimbal_controllers::Controller::trackCB
void trackCB(const rm_msgs::TrackDataConstPtr &msg)
Definition: gimbal_base.cpp:622
hardware_interface::RobotHW
rm_gimbal_controllers::GimbalConfig::accel_yaw_
double accel_yaw_
Definition: gimbal_base.h:127
realtime_tools::RealtimeBuffer::readFromRT
T * readFromRT()
rm_gimbal_controllers::Controller::robot_state_handle_
rm_control::RobotStateHandle robot_state_handle_
Definition: gimbal_base.h:190
rm_gimbal_controllers
Definition: bullet_solver.h:54
rm_gimbal_controllers::GimbalConfig::chassis_comp_d_
double chassis_comp_d_
Definition: gimbal_base.h:126
rm_gimbal_controllers::GimbalConfig::yaw_k_v_
double yaw_k_v_
Definition: gimbal_base.h:126
rm_gimbal_controllers::Controller::odom2gimbal_des_
geometry_msgs::TransformStamped odom2gimbal_des_
Definition: gimbal_base.h:217
hardware_interface::EffortJointInterface
ros::NodeHandle::hasParam
bool hasParam(const std::string &key) const
rm_gimbal_controllers::Controller::cmd_rt_buffer_
realtime_tools::RealtimeBuffer< rm_msgs::GimbalCmd > cmd_rt_buffer_
Definition: gimbal_base.h:206
ROS_WARN
#define ROS_WARN(...)
hardware_interface::ImuSensorInterface
rm_gimbal_controllers::GimbalConfig::chassis_comp_a_
double chassis_comp_a_
Definition: gimbal_base.h:126
rm_gimbal_controllers::GimbalConfig::chassis_comp_b_
double chassis_comp_b_
Definition: gimbal_base.h:126
ros::NodeHandle::subscribe
Subscriber subscribe(const std::string &topic, uint32_t queue_size, const boost::function< void(C)> &callback, const VoidConstPtr &tracked_object=VoidConstPtr(), const TransportHints &transport_hints=TransportHints())
rm_gimbal_controllers::GimbalConfig::chassis_comp_c_
double chassis_comp_c_
Definition: gimbal_base.h:126
rm_gimbal_controllers::Controller
Definition: gimbal_base.h:162
rm_gimbal_controllers::Controller::pid_pos_
std::unordered_map< int, std::unique_ptr< control_toolbox::Pid > > pid_pos_
Definition: gimbal_base.h:193
rm_gimbal_controllers::Controller::error_pub_
std::shared_ptr< realtime_tools::RealtimePublisher< rm_msgs::GimbalDesError > > error_pub_
Definition: gimbal_base.h:203
rm_gimbal_controllers::Controller::init
bool init(hardware_interface::RobotHW *robot_hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh) override
Definition: gimbal_base.cpp:80
XmlRpc::XmlRpcValue::hasMember
bool hasMember(const std::string &name) const
rm_gimbal_controllers::Controller::TRACK
@ TRACK
Definition: gimbal_base.h:236
rm_gimbal_controllers::Controller::dynamic_reconfig_initialized_
bool dynamic_reconfig_initialized_
Definition: gimbal_base.h:228
rm_gimbal_controllers::Controller::imu_sensor_handle_
hardware_interface::ImuSensorHandle imu_sensor_handle_
Definition: gimbal_base.h:191
transform_datatypes.h
rm_gimbal_controllers::Controller::TRAJ
@ TRAJ
Definition: gimbal_base.h:238
tf2::Quaternion::inverse
Quaternion inverse() const
ros::Time
tf2::doTransform
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
rm_gimbal_controllers::Controller::bullet_solver_
std::shared_ptr< BulletSolver > bullet_solver_
Definition: gimbal_base.h:198
urdf
getParam
T getParam(ros::NodeHandle &pnh, const std::string &param_name, const T &default_val)
rm_gimbal_controllers::Controller::odom2base_
geometry_msgs::TransformStamped odom2base_
Definition: gimbal_base.h:217
angles::two_pi_complement
def two_pi_complement(angle)
rm_gimbal_controllers::Controller::pos_des_in_limit_
std::unordered_map< int, bool > pos_des_in_limit_
Definition: gimbal_base.h:195
ROS_ERROR
#define ROS_ERROR(...)
class_list_macros.hpp
ros_utilities.h
tf2::Quaternion
rm_gimbal_controllers::Controller::feedForward
double feedForward(const ros::Time &time)
Definition: gimbal_base.cpp:545
tf2_geometry_msgs.h
tf2::toMsg
B toMsg(const A &a)
quatToRPY
void quatToRPY(const geometry_msgs::Quaternion &q, double &roll, double &pitch, double &yaw)
rm_gimbal_controllers::Controller::data_track_
rm_msgs::TrackData data_track_
Definition: gimbal_base.h:210
rm_gimbal_controllers::GimbalConfig::accel_pitch_
double accel_pitch_
Definition: gimbal_base.h:127
rm_gimbal_controllers::Controller::commandCB
void commandCB(const rm_msgs::GimbalCmdConstPtr &msg)
Definition: gimbal_base.cpp:617
DurationBase< Duration >::toSec
double toSec() const
rm_gimbal_controllers::Controller::config_
GimbalConfig config_
Definition: gimbal_base.h:229
tf2::TransformException
ROS_INFO
#define ROS_INFO(...)
rm_gimbal_controllers::Controller::chassis_compensation_
double chassis_compensation_
Definition: gimbal_base.h:226
ROS_ASSERT
#define ROS_ASSERT(cond)
rm_gimbal_controllers::Controller::cmd_gimbal_
rm_msgs::GimbalCmd cmd_gimbal_
Definition: gimbal_base.h:209
rm_gimbal_controllers::Controller::pos_state_pub_
std::unordered_map< int, std::unique_ptr< realtime_tools::RealtimePublisher< rm_msgs::GimbalPosState > > > pos_state_pub_
Definition: gimbal_base.h:202
rm_gimbal_controllers::Controller::last_odom2base_
geometry_msgs::TransformStamped last_odom2base_
Definition: gimbal_base.h:217
ros::Duration
rm_gimbal_controllers::Controller::update
void update(const ros::Time &time, const ros::Duration &period) override
Definition: gimbal_base.cpp:196
rm_gimbal_controllers::Controller::setDes
void setDes(const ros::Time &time, double yaw_des, double pitch_des)
Definition: gimbal_base.cpp:235
rm_gimbal_controllers::Controller::getGimbalFrameID
std::string getGimbalFrameID(std::unordered_map< int, urdf::JointConstSharedPtr > joint_urdfs)
Definition: gimbal_base.cpp:587
rm_gimbal_controllers::Controller::direct
void direct(const ros::Time &time)
Definition: gimbal_base.cpp:340
XmlRpc::XmlRpcValue
rm_gimbal_controllers::Controller::gravity_
double gravity_
Definition: gimbal_base.h:221
ros::NodeHandle
angles.h
rm_gimbal_controllers::Controller::state_changed_
bool state_changed_
Definition: gimbal_base.h:213
rm_gimbal_controllers::Controller::reconfigCB
void reconfigCB(rm_gimbal_controllers::GimbalBaseConfig &config, uint32_t)
Definition: gimbal_base.cpp:629
ori_tool.h
rm_gimbal_controllers::GimbalConfig::pitch_k_v_
double pitch_k_v_
Definition: gimbal_base.h:126


rm_gimbal_controllers
Author(s): Qiayuan Liao
autogenerated on Sun May 4 2025 02:57:21