Tetrapod Project
pendulum_plugin.cpp
Go to the documentation of this file.
1 /*******************************************************************/
2 /* AUTHOR: Paal Arthur S. Thorseth */
3 /* ORGN: Dept of Eng Cybernetics, NTNU Trondheim */
4 /* FILE: pendulum_plugin.cpp */
5 /* DATE: May 5, 2021 */
6 /* */
7 /* Copyright (C) 2021 Paal Arthur S. Thorseth, */
8 /* Adrian B. Ghansah */
9 /* */
10 /* This program is free software: you can redistribute it */
11 /* and/or modify it under the terms of the GNU General */
12 /* Public License as published by the Free Software Foundation, */
13 /* either version 3 of the License, or (at your option) any */
14 /* later version. */
15 /* */
16 /* This program is distributed in the hope that it will be useful, */
17 /* but WITHOUT ANY WARRANTY; without even the implied warranty */
18 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */
19 /* See the GNU General Public License for more details. */
20 /* */
21 /* You should have received a copy of the GNU General Public */
22 /* License along with this program. If not, see */
23 /* <https://www.gnu.org/licenses/>. */
24 /* */
25 /*******************************************************************/
26 
27 
29 
30 
31 namespace gazebo {
32 
33 // Constructor
35 {
36  this->pos_p_gain = 100;
37  this->pos_i_gain = 0;
38  this->pos_d_gain = 10;
39 
40  this->vel_p_gain = 100;
41  this->vel_i_gain = 0;
42  this->vel_d_gain = 10;
43 }
44 
45 // Destructor
47 {
48  this->rosNode->shutdown();
49 
50  this->rosProcessQueue.clear();
51  this->rosProcessQueue.disable();
52  this->rosProcessQueueThread.join();
53 }
54 
55 // Load Plugin
56 void PendulumPlugin::Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
57 {
58  // Store model pointer
59  this->model = _model;
60 
61  // Store model name
62  this->model_name = _model->GetName();
63 
64  // Store joint
65  this->joint = this->model->GetJoints()[0];
66 
67  // Initialize ROS
68  InitRos();
69 
70  // Setup Joint Controllers
72 
73  // Configure initial joint states
75 
76  // Initialize ROS Queue Threads
78 }
79 
80 // Get joint force
82 {
83  double force = this->joint->GetForce(0);
84 
85  return force;
86 }
87 
88 // Apply force at a single joint
89 void PendulumPlugin::SetJointForce(const double &_force)
90 {
91  if (this->controlMode != 3)
92  {
93  this->model->GetJointController()->Reset();
94 
96  }
97 
98  this->model->GetJointController()->SetForce(
99  this->joint->GetScopedName(),
100  _force
101  );
102 }
103 
104 
105 // Set the a single joints target velocity
106 void PendulumPlugin::SetJointVelocity(const double &_vel)
107 {
108  if (this->controlMode != 2)
109  {
110  this->model->GetJointController()->Reset();
111 
113  }
114 
115  this->model->GetJointController()->SetVelocityTarget(
116  this->joint->GetScopedName(),
117  _vel
118  );
119 }
120 
121 
122 // Set the a single joints target position
123 void PendulumPlugin::SetJointPosition(const double &_pos)
124 {
125  if (this->controlMode != 1)
126  {
127  this->model->GetJointController()->Reset();
128 
130  }
131 
132  this->model->GetJointController()->SetPositionTarget(
133  this->joint->GetScopedName(),
134  _pos
135  );
136 }
137 
138 // Callback for ROS Joint State messages
139 void PendulumPlugin::OnJointStateMsg(const sensor_msgs::JointStateConstPtr &_msg)
140 {
141  if ((!_msg->position.empty()) && (_msg->position.size() == NUMJOINTS))
142  {
143  this->SetJointPosition(_msg->position[0]);
144  }
145 
146  if ((!_msg->velocity.empty()) && (_msg->velocity.size() == NUMJOINTS))
147  {
148  this->SetJointVelocity(_msg->velocity[0]);
149  }
150 
151  if ((!_msg->effort.empty()) && (_msg->effort.size() == NUMJOINTS))
152  {
153  this->SetJointForce(_msg->effort[0]);
154  }
155 }
156 
157 // Setup thread to process messages
159 {
160  static const double timeout = 0.000001;
161  while (this->rosNode->ok())
162  {
163  this->rosProcessQueue.callAvailable(ros::WallDuration(timeout));
164  }
165 }
166 
167 // Setup thread to process messages
169 {
170  ros::Rate loop_rate(10);
171  while (this->rosNode->ok())
172  {
173  std_msgs::Float64 joint_force_msg;
174 
175  joint_force_msg.data = this->GetJointForce();
176 
177  this->jointForcePub.publish(joint_force_msg);
178 
179  loop_rate.sleep();
180  }
181 }
182 // Initialize ROS
184 {
185  if (!ros::isInitialized())
186  {
187  int argc = 0;
188  char **argv = NULL;
189  ros::init(
190  argc,
191  argv,
192  "gazebo_client",
193  ros::init_options::NoSigintHandler
194  );
195  }
196 
197  this->rosNode.reset(new ros::NodeHandle("gazebo_client"));
198 
199  ros::SubscribeOptions joint_state_so =
200  ros::SubscribeOptions::create<sensor_msgs::JointState>(
201  "/" + this->model->GetName() + "/joint_state_cmd",
202  1,
203  boost::bind(&PendulumPlugin::OnJointStateMsg, this, _1),
204  ros::VoidPtr(),
205  &this->rosProcessQueue
206  );
207 
208  ros::AdvertiseOptions joint_force_ao =
209  ros::AdvertiseOptions::create<std_msgs::Float64>(
210  "/" + this->model->GetName() + "/joint_force",
211  1,
212  ros::SubscriberStatusCallback(),
213  ros::SubscriberStatusCallback(),
214  ros::VoidPtr(),
215  &this->rosPublishQueue
216  );
217 
218  this->jointStateSub = this->rosNode->subscribe(joint_state_so);
219 
220  this->jointForcePub = this->rosNode->advertise(joint_force_ao);
221 }
222 
223 // Initialize ROS Publish and Process Queue Threads
225 {
226  this->rosPublishQueueThread = std::thread(
227  std::bind(&PendulumPlugin::PublishQueueThread, this)
228  );
229 
230  this->rosProcessQueueThread = std::thread(
231  std::bind(&PendulumPlugin::ProcessQueueThread, this)
232  );
233 }
234 
235 // Initialize Joint Controllers
237 {
238  this->model->GetJointController()->SetVelocityPID(
239  this->joint->GetScopedName(),
240  common::PID(this->vel_p_gain, this->vel_i_gain, this->vel_d_gain)
241  );
242 
243  this->model->GetJointController()->SetPositionPID(
244  this->joint->GetScopedName(),
245  common::PID(this->pos_p_gain, this->pos_i_gain, this->pos_d_gain)
246  );
247 }
248 
249 // Initialize joint configuration
251 {
252  // Set default position
253  this->model->GetJointController()->SetJointPosition(
254  this->joint->GetScopedName(),
256  );
257 
258  // Set controller position reference
259  this->model->GetJointController()->SetPositionTarget(
260  this->joint->GetScopedName(),
262  );
263 
264 }
265 
266 } // namespace gazebo
virtual void Load(physics::ModelPtr _model, sdf::ElementPtr _sdf)
The Load function is called by Gazebo when the plugin is inserted into simulation.
void SetJointPosition(const double &_pos)
Set the position of the joint.
std::thread rosPublishQueueThread
Thread running the rosPublishQueue.
void OnJointStateMsg(const sensor_msgs::JointStateConstPtr &_msg)
The OnJointStateMsg function handles an incoming joint state message from ROS.
std::string model_name
Model name.
ros::Publisher jointForcePub
ROS Joint Force (Torque) Publisher.
double pos_d_gain
Position D-gain.
void SetJointVelocity(const double &_vel)
Set the velocity of the joint.
PendulumPlugin()
Constructor.
double vel_i_gain
Velocity I-gain.
double vel_d_gain
Velocity D-gain.
double pos_i_gain
Position I-gain.
void InitJointController()
The InitJointControllers function is called to setup joint PID controllers.
physics::ModelPtr model
Pointer to the model.
void SetJointForce(const double &_force)
Apply force at a specific joint.
physics::JointPtr joint
Pointers to the joint.
double pos_p_gain
Position P-gain.
ros::Subscriber jointStateSub
ROS Joint State Subscriber.
double GetJointForce()
Get currently applied force at the joint.
std::unique_ptr< ros::NodeHandle > rosNode
Node used for ROS transport.
std::thread rosProcessQueueThread
Thread running the rosProcessQueue.
void InitRos()
The initRos function is called to initialize ROS.
ControlMode controlMode
Control mode indicator { position = 1, velocity = 2, torque = 3 }.
ros::CallbackQueue rosProcessQueue
ROS callbackque that helps process messages.
void InitRosQueueThreads()
The InitRosQueueThreads function is called to initialize the ROS Publish and Process Queue Threads.
void ProcessQueueThread()
The ProcessQueueThread function is a ROS helper function that processes messages.
void InitJointConfiguration()
The InitJointConfiguration function is called to initialize the desired joint configuration.
double vel_p_gain
Velocity P-gain.
void PublishQueueThread()
The PublishQueueThread function is a ROS helper function that publish state messages.
virtual ~PendulumPlugin()
Destructor.
static constexpr unsigned int NUMJOINTS
Fixed variable for num joints.
double degToRad(const double &_deg)
The degToRad function converts degrees to radians.
Definition: angle_utils.cpp:33