motor_controller.cpp
Go to the documentation of this file.
1 //=================================================================================================
2 // Copyright (c) 2013, Johannes Meyer, TU Darmstadt
3 // All rights reserved.
4 
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright
10 // notice, this list of conditions and the following disclaimer in the
11 // documentation and/or other materials provided with the distribution.
12 // * Neither the name of the Flight Systems and Automatic Control group,
13 // TU Darmstadt, nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without
15 // specific prior written permission.
16 
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //=================================================================================================
28 
31 
32 #include <geometry_msgs/WrenchStamped.h>
33 #include <std_srvs/Empty.h>
34 
35 #include <ros/subscriber.h>
36 #include <ros/callback_queue.h>
37 
39 
40 using namespace controller_interface;
41 
42 class MotorController : public controller_interface::Controller<QuadrotorInterface>
43 {
44 public:
46  : node_handle_(0)
47  {}
48 
50  {
51  if (node_handle_) {
52  node_handle_->shutdown();
53  delete node_handle_;
54  node_handle_ = 0;
55  }
56  }
57 
58  bool init(QuadrotorInterface *interface, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)
59  {
60  // get interface handles
61  wrench_input_ = interface->addInput<WrenchCommandHandle>("wrench");
62  motor_output_ = interface->addOutput<MotorCommandHandle>("motor");
63 
64  // initialize NodeHandle
65  delete node_handle_;
66  node_handle_ = new ros::NodeHandle(root_nh);
67 
68  // load parameters
69  controller_nh.getParam("force_per_voltage", parameters_.force_per_voltage = 0.559966216);
70  controller_nh.getParam("torque_per_voltage", parameters_.torque_per_voltage = 7.98598e-3);
71  controller_nh.getParam("lever", parameters_.lever = 0.275);
72  root_nh.param<std::string>("base_link_frame", base_link_frame_, "base_link");
73 
74  // TODO: calculate these parameters from the quadrotor_propulsion parameters
75 // quadrotor_propulsion:
76 // k_t: 0.015336864714397
77 // k_m: -7.011631909766668e-5
78 
79 // CT2s: -1.3077e-2
80 // CT1s: -2.5224e-4
81 // CT0s: 1.538190483976698e-5
82 
83  return true;
84  }
85 
86  void reset()
87  {
88  wrench_.wrench.force.x = 0.0;
89  wrench_.wrench.force.y = 0.0;
90  wrench_.wrench.force.z = 0.0;
91  wrench_.wrench.torque.x = 0.0;
92  wrench_.wrench.torque.y = 0.0;
93  wrench_.wrench.torque.z = 0.0;
94 
95  motor_.force.assign(4, 0.0);
96  motor_.torque.assign(4, 0.0);
97  motor_.frequency.clear();
98  motor_.voltage.assign(4, 0.0);
99  }
100 
101  void wrenchCommandCallback(const geometry_msgs::WrenchStampedConstPtr& command)
102  {
103  wrench_ = *command;
104  if (wrench_.header.stamp.isZero()) wrench_.header.stamp = ros::Time::now();
105 
106  // start controller if it not running
107  if (!isRunning()) this->startRequest(wrench_.header.stamp);
108  }
109 
110  void starting(const ros::Time &time)
111  {
112  reset();
113  motor_output_->start();
114  }
115 
116  void stopping(const ros::Time &time)
117  {
118  motor_output_->stop();
119  }
120 
121  void update(const ros::Time& time, const ros::Duration& period)
122  {
123  // Get wrench command input
124  if (wrench_input_->connected() && wrench_input_->enabled()) {
125  wrench_.wrench = wrench_input_->getCommand();
126  }
127 
128  // Update output
129  if (wrench_.wrench.force.z > 0.0) {
130 
131  double nominal_thrust_per_motor = wrench_.wrench.force.z / 4.0;
132  motor_.force[0] = nominal_thrust_per_motor - wrench_.wrench.torque.y / 2.0 / parameters_.lever;
133  motor_.force[1] = nominal_thrust_per_motor - wrench_.wrench.torque.x / 2.0 / parameters_.lever;
134  motor_.force[2] = nominal_thrust_per_motor + wrench_.wrench.torque.y / 2.0 / parameters_.lever;
135  motor_.force[3] = nominal_thrust_per_motor + wrench_.wrench.torque.x / 2.0 / parameters_.lever;
136 
137  double nominal_torque_per_motor = wrench_.wrench.torque.z / 4.0;
138  motor_.voltage[0] = motor_.force[0] / parameters_.force_per_voltage + nominal_torque_per_motor / parameters_.torque_per_voltage;
139  motor_.voltage[1] = motor_.force[1] / parameters_.force_per_voltage - nominal_torque_per_motor / parameters_.torque_per_voltage;
140  motor_.voltage[2] = motor_.force[2] / parameters_.force_per_voltage + nominal_torque_per_motor / parameters_.torque_per_voltage;
141  motor_.voltage[3] = motor_.force[3] / parameters_.force_per_voltage - nominal_torque_per_motor / parameters_.torque_per_voltage;
142 
143  motor_.torque[0] = motor_.voltage[0] * parameters_.torque_per_voltage;
144  motor_.torque[1] = motor_.voltage[1] * parameters_.torque_per_voltage;
145  motor_.torque[2] = motor_.voltage[2] * parameters_.torque_per_voltage;
146  motor_.torque[3] = motor_.voltage[3] * parameters_.torque_per_voltage;
147 
148  if (motor_.voltage[0] < 0.0) motor_.voltage[0] = 0.0;
149  if (motor_.voltage[1] < 0.0) motor_.voltage[1] = 0.0;
150  if (motor_.voltage[2] < 0.0) motor_.voltage[2] = 0.0;
151  if (motor_.voltage[3] < 0.0) motor_.voltage[3] = 0.0;
152 
153  } else {
154  reset();
155  }
156 
157  // set wrench output
158  motor_.header.stamp = time;
159  motor_.header.frame_id = "base_link";
160  motor_output_->setCommand(motor_);
161  }
162 
163 private:
166 
171 
172  geometry_msgs::WrenchStamped wrench_;
173  hector_uav_msgs::MotorCommand motor_;
174  std::string base_link_frame_;
175 
176  struct {
177  double force_per_voltage; // coefficient for linearized volts to force conversion for a single motor [N / V]
178  double torque_per_voltage; // coefficient for linearized volts to force conversion for a single motor [Nm / V]
179  double lever; // the lever arm from origin to the motor axes (symmetry assumption) [m]
180  } parameters_;
181 };
182 
183 } // namespace hector_quadrotor_controller
184 
boost::shared_ptr< HandleType > addOutput(const std::string &name)
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
boost::shared_ptr< HandleType > addInput(const std::string &name)
void wrenchCommandCallback(const geometry_msgs::WrenchStampedConstPtr &command)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
bool getParam(const std::string &key, std::string &s) const
void update(const ros::Time &time, const ros::Duration &period)
static Time now()
bool init(QuadrotorInterface *interface, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)


hector_quadrotor_controller
Author(s): Johannes Meyer
autogenerated on Sun Jul 10 2016 04:30:48