34 #include <geometry_msgs/TwistStamped.h> 35 #include <geometry_msgs/WrenchStamped.h> 36 #include <std_srvs/Empty.h> 41 #include <boost/thread.hpp> 66 node_handle_ = root_nh;
73 engage_service_server_ = node_handle_.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>(
"engage", boost::bind(&
TwistController::engageCallback,
this, _1, _2));
74 shutdown_service_server_ = node_handle_.advertiseService<std_srvs::Empty::Request, std_srvs::Empty::Response>(
"shutdown", boost::bind(&
TwistController::shutdownCallback,
this, _1, _2));
85 controller_nh.
getParam(
"auto_engage", auto_engage_ =
true);
86 controller_nh.
getParam(
"limits/load_factor", load_factor_limit = 1.5);
87 controller_nh.
getParam(
"limits/force/z", limits_.force.z);
88 controller_nh.
getParam(
"limits/torque/xy", limits_.torque.x);
89 controller_nh.
getParam(
"limits/torque/xy", limits_.torque.y);
90 controller_nh.
getParam(
"limits/torque/z", limits_.torque.z);
91 root_nh.
param<std::string>(
"base_link_frame", base_link_frame_,
"base_link");
96 command_given_in_stabilized_frame_ =
false;
103 pid_.linear.x.reset();
104 pid_.linear.y.reset();
105 pid_.linear.z.reset();
106 pid_.angular.x.reset();
107 pid_.angular.y.reset();
108 pid_.angular.z.reset();
110 wrench_.wrench.force.x = 0.0;
111 wrench_.wrench.force.y = 0.0;
112 wrench_.wrench.force.z = 0.0;
113 wrench_.wrench.torque.x = 0.0;
114 wrench_.wrench.torque.y = 0.0;
115 wrench_.wrench.torque.z = 0.0;
117 linear_z_control_error_ = 0.0;
118 motors_running_ =
false;
123 boost::mutex::scoped_lock lock(command_mutex_);
126 if (command_.header.stamp.isZero()) command_.header.stamp =
ros::Time::now();
127 command_given_in_stabilized_frame_ =
false;
130 if (!isRunning()) this->startRequest(command_.header.stamp);
135 boost::mutex::scoped_lock lock(command_mutex_);
137 command_.twist = *command;
139 command_given_in_stabilized_frame_ =
true;
142 if (!isRunning()) this->startRequest(command_.header.stamp);
147 boost::mutex::scoped_lock lock(command_mutex_);
150 motors_running_ =
true;
156 boost::mutex::scoped_lock lock(command_mutex_);
159 motors_running_ =
false;
166 wrench_output_->start();
171 wrench_output_->stop();
176 boost::mutex::scoped_lock lock(command_mutex_);
179 if (twist_input_->connected() && twist_input_->enabled()) {
180 command_.twist = twist_input_->getCommand();
181 command_given_in_stabilized_frame_ =
false;
185 Twist
command = command_.twist;
186 Twist twist = twist_->twist();
188 twist_body.linear = pose_->toBody(twist.linear);
189 twist_body.angular = pose_->toBody(twist.angular);
192 if (command_given_in_stabilized_frame_) {
193 double yaw = pose_->getYaw();
194 Twist transformed = command;
195 transformed.linear.x = cos(yaw) * command.linear.x - sin(yaw) * command.linear.y;
196 transformed.linear.y = sin(yaw) * command.linear.x + cos(yaw) * command.linear.y;
197 transformed.angular.x = cos(yaw) * command.angular.x - sin(yaw) * command.angular.y;
198 transformed.angular.y = sin(yaw) * command.angular.x + cos(yaw) * command.angular.y;
199 command = transformed;
203 const double gravity = 9.8065;
204 double load_factor = 1. / ( pose_->pose().orientation.w * pose_->pose().orientation.w
205 - pose_->pose().orientation.x * pose_->pose().orientation.x
206 - pose_->pose().orientation.y * pose_->pose().orientation.y
207 + pose_->pose().orientation.z * pose_->pose().orientation.z );
209 if (load_factor_limit > 0.0 && !(load_factor < load_factor_limit)) load_factor = load_factor_limit;
213 if (!motors_running_ && command.linear.z > 0.1 && load_factor > 0.0) {
214 motors_running_ =
true;
216 }
else if (motors_running_ && command.linear.z < -0.1 ) {
217 double shutdown_limit = 0.25 * std::min(command.linear.z, -0.5);
218 if (linear_z_control_error_ > 0.0) linear_z_control_error_ = 0.0;
219 if (pid_.linear.z.getFilteredControlError(linear_z_control_error_, 5.0, period) < shutdown_limit) {
220 motors_running_ =
false;
223 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"z control error = " << linear_z_control_error_ <<
" >= " << shutdown_limit);
226 linear_z_control_error_ = 0.0;
230 if (motors_running_ && load_factor < 0.0) {
231 motors_running_ =
false;
232 ROS_WARN_NAMED(
"twist_controller",
"Shutting down motors due to flip over!");
237 if (motors_running_) {
238 Vector3 acceleration_command;
239 acceleration_command.x = pid_.linear.x.update(command.linear.x, twist.linear.x, acceleration_->acceleration().x, period);
240 acceleration_command.y = pid_.linear.y.update(command.linear.y, twist.linear.y, acceleration_->acceleration().y, period);
241 acceleration_command.z = pid_.linear.z.update(command.linear.z, twist.linear.z, acceleration_->acceleration().z, period) + gravity;
242 Vector3 acceleration_command_body = pose_->toBody(acceleration_command);
244 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"twist.linear: [" << twist.linear.x <<
" " << twist.linear.y <<
" " << twist.linear.z <<
"]");
245 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"twist_body.angular: [" << twist_body.angular.x <<
" " << twist_body.angular.y <<
" " << twist_body.angular.z <<
"]");
246 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"twist_command.linear: [" << command.linear.x <<
" " << command.linear.y <<
" " << command.linear.z <<
"]");
247 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"twist_command.angular: [" << command.angular.x <<
" " << command.angular.y <<
" " << command.angular.z <<
"]");
248 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"acceleration: [" << acceleration_->acceleration().x <<
" " << acceleration_->acceleration().y <<
" " << acceleration_->acceleration().z <<
"]");
249 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"acceleration_command_world: [" << acceleration_command.x <<
" " << acceleration_command.y <<
" " << acceleration_command.z <<
"]");
250 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"acceleration_command_body: [" << acceleration_command_body.x <<
" " << acceleration_command_body.y <<
" " << acceleration_command_body.z <<
"]");
252 wrench_.wrench.torque.x = inertia_[0] * pid_.angular.x.update(-acceleration_command_body.y / gravity, 0.0, twist_body.angular.x, period);
253 wrench_.wrench.torque.y = inertia_[1] * pid_.angular.y.update( acceleration_command_body.x / gravity, 0.0, twist_body.angular.y, period);
254 wrench_.wrench.torque.z = inertia_[2] * pid_.angular.z.update( command.angular.z, twist.angular.z, 0.0, period);
255 wrench_.wrench.force.x = 0.0;
256 wrench_.wrench.force.y = 0.0;
257 wrench_.wrench.force.z = mass_ * ((acceleration_command.z - gravity) * load_factor + gravity);
259 if (limits_.force.z > 0.0 && wrench_.wrench.force.z > limits_.force.z) wrench_.wrench.force.z = limits_.force.z;
260 if (wrench_.wrench.force.z <= std::numeric_limits<double>::min()) wrench_.wrench.force.z = std::numeric_limits<double>::min();
261 if (limits_.torque.x > 0.0) {
262 if (wrench_.wrench.torque.x > limits_.torque.x) wrench_.wrench.torque.x = limits_.torque.x;
263 if (wrench_.wrench.torque.x < -limits_.torque.x) wrench_.wrench.torque.x = -limits_.torque.x;
265 if (limits_.torque.y > 0.0) {
266 if (wrench_.wrench.torque.y > limits_.torque.y) wrench_.wrench.torque.y = limits_.torque.y;
267 if (wrench_.wrench.torque.y < -limits_.torque.y) wrench_.wrench.torque.y = -limits_.torque.y;
269 if (limits_.torque.z > 0.0) {
270 if (wrench_.wrench.torque.z > limits_.torque.z) wrench_.wrench.torque.z = limits_.torque.z;
271 if (wrench_.wrench.torque.z < -limits_.torque.z) wrench_.wrench.torque.z = -limits_.torque.z;
274 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"wrench_command.force: [" << wrench_.wrench.force.x <<
" " << wrench_.wrench.force.y <<
" " << wrench_.wrench.force.z <<
"]");
275 ROS_DEBUG_STREAM_NAMED(
"twist_controller",
"wrench_command.torque: [" << wrench_.wrench.torque.x <<
" " << wrench_.wrench.torque.y <<
" " << wrench_.wrench.torque.z <<
"]");
282 wrench_.header.stamp = time;
283 wrench_.header.frame_id = base_link_frame_;
284 wrench_output_->setCommand(wrench_.wrench);
void stopping(const ros::Time &time)
AccelerationHandlePtr acceleration_
virtual bool getMassAndInertia(double &mass, double inertia[3])
boost::shared_ptr< HandleType > addOutput(const std::string &name)
geometry_msgs::TwistStamped command_
#define ROS_INFO_NAMED(name,...)
#define ROS_DEBUG_STREAM_NAMED(name, args)
#define ROS_WARN_NAMED(name,...)
double linear_z_control_error_
std::string base_link_frame_
void update(const ros::Time &time, const ros::Duration &period)
TwistCommandHandlePtr twist_input_
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
ros::NodeHandle node_handle_
boost::shared_ptr< HandleType > addInput(const std::string &name)
void starting(const ros::Time &time)
virtual AccelerationHandlePtr getAcceleration()
bool engageCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
ROSLIB_DECL std::string command(const std::string &cmd)
void twistCommandCallback(const geometry_msgs::TwistStampedConstPtr &command)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
ros::ServiceServer engage_service_server_
ros::Subscriber cmd_vel_subscriber_
ros::ServiceServer shutdown_service_server_
ros::Subscriber twist_subscriber_
geometry_msgs::Wrench limits_
bool getParam(const std::string &key, std::string &s) const
virtual PoseHandlePtr getPose()
void cmd_velCommandCallback(const geometry_msgs::TwistConstPtr &command)
boost::mutex command_mutex_
WrenchCommandHandlePtr wrench_output_
bool command_given_in_stabilized_frame_
geometry_msgs::WrenchStamped wrench_
virtual TwistHandlePtr getTwist()
bool shutdownCallback(std_srvs::Empty::Request &, std_srvs::Empty::Response &)
bool init(QuadrotorInterface *interface, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)