qb_move_interactive_interface.h
Go to the documentation of this file.
1 /***
2  * Software License Agreement: BSD 3-Clause License
3  *
4  * Copyright (c) 2016-2018, qbrobotics®
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
8  * following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this list of conditions and the
11  * following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
14  * following disclaimer in the documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
17  * products derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
25  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef QB_MOVE_INTERACTIVE_INTERFACE_H
29 #define QB_MOVE_INTERACTIVE_INTERFACE_H
30 
31 // ROS libraries
33 #include <tf2/utils.h>
34 #include <trajectory_msgs/JointTrajectory.h>
35 
44  public:
50  : spinner_(1) {
51  spinner_.start();
52  }
53 
57  virtual ~qbMoveInteractive() {
58  spinner_.stop();
59  }
60 
70  void initMarkers(ros::NodeHandle &root_nh, const std::string &device_name, const std::vector<std::string> &joint_names) {
71  device_name_ = device_name;
72  joint_names_ = joint_names;
73  interactive_commands_server_ = std::make_unique<interactive_markers::InteractiveMarkerServer>(device_name + "_interactive_commands");
74 
75  cylinder_.header.frame_id = device_name + "_shaft_link";
76  cylinder_.name = device_name + "_position_reference_cylinder";
77  cylinder_.description = "motor position reference cylinder.";
78  cylinder_.scale = 0.05;
79  controls_.pose.position.y = 0.02; // others are 0
81 
82  controls_.header.frame_id = device_name + "_shaft_link";
83  controls_.name = device_name + "_position_reference_controls";
84  controls_.description = "motor position reference controls.";
85  controls_.scale = 0.05;
86  controls_.pose.position.y = 0.02; // others are 0
88 
90  interactive_commands_server_->insert(controls_, std::bind(&qbMoveInteractive::interactiveMarkerCallback, this, std::placeholders::_1));
91  interactive_commands_server_->applyChanges();
92 
93  // set initial pose to avoid NaN in computation
94  controls_position_orig_.orientation.w = 1; // others are 0
95  controls_position_orig_.position.y = 0.02; // others are 0
97 
98  joint_command_pub_ = root_nh.advertise<trajectory_msgs::JointTrajectory>("control/" + device_name + "_position_and_preset_trajectory_controller/command", 1);
99  }
100 
105  void setMarkerState(const std::vector<double> &joint_positions) {
106  joint_positions_ = joint_positions;
108  }
109 
110  protected:
113  trajectory_msgs::JointTrajectory joint_command_trajectories_;
114  std::vector<std::string> joint_names_;
115  std::vector<double> joint_positions_;
116  std::string device_name_;
117 
118  std::unique_ptr<interactive_markers::InteractiveMarkerServer> interactive_commands_server_;
119  visualization_msgs::InteractiveMarker cylinder_;
120  visualization_msgs::InteractiveMarker controls_;
121  geometry_msgs::Pose controls_position_old_;
122  geometry_msgs::Pose controls_position_orig_;
123 
128  void buildCylinder(visualization_msgs::InteractiveMarker &interactive_marker) {
129  visualization_msgs::Marker marker;
130  marker.type = visualization_msgs::Marker::CYLINDER;
131  marker.pose.position.y = 0.02; // others are 0
132  marker.pose.orientation.w = 1;
133  marker.pose.orientation.x = 1;
134  marker.pose.orientation.y = 0;
135  marker.pose.orientation.z = 0;
136  marker.scale.x = interactive_marker.scale * 0.4;
137  marker.scale.y = interactive_marker.scale * 0.4;
138  marker.scale.z = interactive_marker.scale * 0.4;
139  marker.color.r = 0.35;
140  marker.color.g = 0.35;
141  marker.color.b = 0.35;
142  marker.color.a = 0.75;
143 
144  visualization_msgs::InteractiveMarkerControl control;
145  control.always_visible = static_cast<unsigned char>(true);
146  control.markers.push_back(marker);
147  control.orientation_mode = visualization_msgs::InteractiveMarkerControl::FIXED;
148  interactive_marker.controls.push_back(control);
149  }
150 
158  void buildMotorControl(visualization_msgs::InteractiveMarker &interactive_marker) {
159  visualization_msgs::InteractiveMarkerControl control;
160  control.orientation.w = 1;
161  control.orientation.x = 0;
162  control.orientation.y = 0;
163  control.orientation.z = 1;
164  control.name = "position";
165  control.interaction_mode = visualization_msgs::InteractiveMarkerControl::ROTATE_AXIS;
166  control.orientation_mode = visualization_msgs::InteractiveMarkerControl::FIXED;
167  interactive_marker.controls.push_back(control);
168  control.name = "stiffness";
169  control.interaction_mode = visualization_msgs::InteractiveMarkerControl::MOVE_AXIS;
170  control.orientation_mode = visualization_msgs::InteractiveMarkerControl::FIXED;
171  interactive_marker.controls.push_back(control);
172  }
173 
180  double computeAngularDistance(const geometry_msgs::Quaternion &to_pose, const geometry_msgs::Quaternion &from_pose) {
181  tf2::Quaternion to_q, from_q;
182  tf2::fromMsg(to_pose, to_q);
183 // tf2::fromMsg(from_pose, from_q);
184  double to_roll = 0.0;
185 // double from_roll = 0.0;
186  double not_used_1, not_used_2;
187  tf2::Matrix3x3(to_q).getRPY(not_used_1, to_roll, not_used_2);
188 // tf2::Matrix3x3(from_q).getRPY(not_used_1, from_roll, not_used_2);
189  return to_roll; // actually this works better than the difference in orientation
190  }
191 
198  double computeLinearDistance(const geometry_msgs::Point &to_pose, const geometry_msgs::Point &from_pose) {
199  return to_pose.y - from_pose.y; // the marker can only move in the y direction
200  }
201 
208  trajectory_msgs::JointTrajectory computeJointTrajectories(const double &displacement_position, const double &displacement_stiffness) {
209  trajectory_msgs::JointTrajectoryPoint point;
210  point.positions = {joint_positions_.at(0) + displacement_position, getStiffnessFromScale()};
211  point.velocities.resize(2);
212  point.accelerations.resize(2);
213  point.time_from_start = ros::Duration(1.0); //TODO: add a parameter to set the trajectory velocity
214 
215  trajectory_msgs::JointTrajectory trajectory;
216  trajectory.header.stamp = ros::Time::now();
217  trajectory.header.frame_id = device_name_ + "_interactive";
218  trajectory.joint_names.push_back(joint_names_.at(0));
219  trajectory.joint_names.push_back(joint_names_.at(1));
220  trajectory.points.push_back(point);
221  return trajectory;
222  }
223 
229  return cylinder_.controls.at(0).markers.at(0).scale.x/0.05 - 0.2;
230  }
231 
238  void interactiveMarkerCallback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback) {
239  if (feedback->event_type == feedback->POSE_UPDATE) {
240  // auto clamp = [](auto &val, const auto &min, const auto &max) { val = std::min(std::max(val, min), max); };
241  double clamped_scale = std::min(std::max(cylinder_.controls.at(0).markers.at(0).scale.x + 2*(feedback->pose.position.y - controls_position_old_.position.y), 0.01), 0.05);
242  cylinder_.controls.at(0).markers.at(0).scale.x = clamped_scale;
243  cylinder_.controls.at(0).markers.at(0).scale.y = clamped_scale;
244  interactive_commands_server_->insert(cylinder_);
245  interactive_commands_server_->applyChanges();
246 
247  double displacement_position = computeAngularDistance(feedback->pose.orientation, controls_position_old_.orientation);
248  //TODO: find a better workaround to avoid discontinuities
249  if (std::abs(displacement_position) > 1.5) {
250  interactive_commands_server_->erase(controls_.name);
251  interactive_commands_server_->applyChanges();
252  interactive_commands_server_->insert(controls_, std::bind(&qbMoveInteractive::interactiveMarkerCallback, this, std::placeholders::_1));
253  interactive_commands_server_->applyChanges();
254  }
255 
256  double displacement_stiffness = computeLinearDistance(feedback->pose.position, controls_position_old_.position);
257  joint_command_trajectories_ = computeJointTrajectories(displacement_position, displacement_stiffness);
258  joint_command_pub_.publish(joint_command_trajectories_);
259 
260  controls_position_old_ = feedback->pose;
261  return;
262  }
263 
264  if (feedback->event_type == feedback->MOUSE_UP) {
265  interactive_commands_server_->setPose(controls_.name, controls_position_orig_);
266  interactive_commands_server_->applyChanges();
267  controls_position_old_ = controls_position_orig_;
268  return;
269  }
270  }
271 
277  void setScaleFromStiffness(const double &stiffness_value) {
278  double scaled_stiffness_value = 0.01 + stiffness_value*0.05;
279  cylinder_.controls.at(0).markers.at(0).scale.x = scaled_stiffness_value;
280  cylinder_.controls.at(0).markers.at(0).scale.y = scaled_stiffness_value;
281  interactive_commands_server_->insert(cylinder_);
282  interactive_commands_server_->applyChanges();
283  }
284 };
285 } // namespace qb_move_interactive_interface
286 
287 #endif // QB_MOVE_INTERACTIVE_INTERFACE_H
void getRPY(tf2Scalar &roll, tf2Scalar &pitch, tf2Scalar &yaw, unsigned int solution_number=1) const
void publish(const boost::shared_ptr< M > &message) const
void setScaleFromStiffness(const double &stiffness_value)
Set the diameter scale of the marker from the given stiffness value.
void interactiveMarkerCallback(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &feedback)
This is the core method of the class, where commands are computed w.r.t.
void initMarkers(ros::NodeHandle &root_nh, const std::string &device_name, const std::vector< std::string > &joint_names)
Initialize the interactive_markers::InteractiveMarkerServer and the marker displayed in rviz to contr...
void setMarkerState(const std::vector< double > &joint_positions)
Update the stored joint positions with the given values.
A simple interface that adds an interactive marker (to be used in rviz) with two controls to change r...
std::unique_ptr< interactive_markers::InteractiveMarkerServer > interactive_commands_server_
double computeAngularDistance(const geometry_msgs::Quaternion &to_pose, const geometry_msgs::Quaternion &from_pose)
Compute the angular distance between current and last orientations.
void fromMsg(const A &, B &b)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
double computeLinearDistance(const geometry_msgs::Point &to_pose, const geometry_msgs::Point &from_pose)
Compute the distance along the marker axis between current and last positions.
static Time now()
void buildMotorControl(visualization_msgs::InteractiveMarker &interactive_marker)
Add two interactive controls to the given interactive marker.
qbMoveInteractive()
Start the async spinner and do nothing else.
trajectory_msgs::JointTrajectory computeJointTrajectories(const double &displacement_position, const double &displacement_stiffness)
Compute a simple joint trajectory from the given displacements in position and orientation.
void buildCylinder(visualization_msgs::InteractiveMarker &interactive_marker)
Create a cylinder marker representing the qbmove shaft axis and attach it to the given interactive ma...


qb_move_hardware_interface
Author(s): qbrobotics®
autogenerated on Thu Oct 10 2019 03:30:57