Katana300.cpp
Go to the documentation of this file.
1 /*
2  * UOS-ROS packages - Robot Operating System code by the University of Osnabrück
3  * Copyright (C) 2011 University of Osnabrück
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * Katana300.cpp
20  *
21  * Created on: Dec 13, 2011
22  * Authors:
23  * Hannes Raudies <h.raudies@hs-mannheim.de>
24  * Martin Günther <mguenthe@uos.de>
25  * Benjamin Reiner <reinerbe@hs-weingarten.de>
26  */
27 
28 #include <katana/Katana300.h>
29 
30 namespace katana
31 {
32 
34  Katana()
35 {
37  setLimits();
38 }
39 
41 {
42 }
43 
45 {
46  // TODO: constants
47 
48  // TODO: setting the limits this low shouldn't be necessary; the limits should
49  // be set to 2 (acc.) and 180 (vel.) and tested on real Katana 300
50  //fast: acc. 2 and vel. 150 (tested on real Katana 300)
51  //slow: acc. 1 and vel. 30
52 
53 
54  kni->setMotorAccelerationLimit(0, 2);
55  kni->setMotorVelocityLimit(0, 60); // set to 90 to protect our old Katana
56 
57  for (size_t i = 1; i < NUM_MOTORS; i++)
58  {
59  // These two settings probably only influence KNI functions like moveRobotToEnc(),
60  // openGripper() and so on, and not the spline trajectories. We still set them
61  // just to be sure.
62  kni->setMotorAccelerationLimit(i, 2);
63  kni->setMotorVelocityLimit(i, 60);
64  }
65 
66 }
67 
73 {
74  boost::recursive_mutex::scoped_lock lock(kni_mutex);
75  kni->freezeRobot();
76 }
77 
81 bool Katana300::moveJoint(int jointIndex, double turningAngle)
82 {
83 
84  desired_angles_[jointIndex] = turningAngle;
85 
86  return Katana::moveJoint(jointIndex, turningAngle);
87 }
88 
94 {
97 }
98 
104 {
105  std::vector<double> motor_angles = getMotorAngles();
106 
107  for (size_t i = 0; i < NUM_JOINTS; i++)
108  {
109  if (motor_status_[i] == MSF_MOTCRASHED)
110  return false;
111  if (fabs(desired_angles_[i] - motor_angles[i]) > JOINTS_STOPPED_POS_TOLERANCE)
112  return false;
114  return false;
115  }
116 
117  return true;
118 }
119 
125 {
126  std::vector<double> motor_angles = getMotorAngles();
127 
128  for (size_t i = 0; i < NUM_MOTORS; i++)
129  {
130  if (motor_status_[i] == MSF_MOTCRASHED)
131  return false;
132 
134  return false;
135  }
136 
137  return true;
138 }
139 
141 {
142  ros::Rate idleWait(5);
143  std::vector<double> pos1_angles(NUM_MOTORS);
144  std::vector<double> pos2_angles(NUM_MOTORS);
145 
146  // these are safe values, i.e., no self-collision is possible
147  // values on robot Kate
148  pos1_angles[0] = 2.75;
149  pos2_angles[0] = -1.5;
150 
151  pos1_angles[1] = 0.5;
152  pos2_angles[1] = 2.1;
153 
154  pos1_angles[2] = 1.40;
155  pos2_angles[2] = 0.3;
156 
157  pos1_angles[3] = 0.50;
158  pos2_angles[3] = -2.00;
159 
160  pos1_angles[4] = 2.8;
161  pos2_angles[4] = -2.75;
162 
163  pos1_angles[5] = -0.44;
164  pos2_angles[5] = 0.30;
165 
166  for (size_t i = 0; i < NUM_MOTORS; i++)
167  {
168  int pos1_encoders = (int)converter->angle_rad2enc(i, pos1_angles[i]);
169  int pos2_encoders = (int)converter->angle_rad2enc(i, pos2_angles[i]);
170 
171  int accel = kni->getMotorAccelerationLimit(i);
172  int max_vel = kni->getMotorVelocityLimit(i);
173 
174  ROS_INFO("Motor %zu - acceleration: %d (= %f), max speed: %d (=%f)", i, accel, 2.0 * converter->acc_enc2rad(i, accel), max_vel, converter->vel_enc2rad(i, max_vel));
175  ROS_INFO("KNI encoders: %d, %d", kni->GetBase()->GetMOT()->arr[i].GetEncoderMinPos(), kni->GetBase()->GetMOT()->arr[i].GetEncoderMaxPos());
176  ROS_INFO("moving to encoders: %d, %d", pos1_encoders, pos2_encoders);
177  ROS_INFO("current encoders: %d", kni->getMotorEncoders(i, true));
178 
179  ROS_INFO("Moving to min");
180  {
181  boost::recursive_mutex::scoped_lock lock(kni_mutex);
182  kni->moveMotorToEnc(i, pos1_encoders, true, 50, 60000);
183  }
184 
185 // do
186 // {
187 // idleWait.sleep();
188 // refreshMotorStatus();
189 //
190 // } while (!allMotorsReady());
191 
192  ROS_INFO("Moving to max");
193  {
194  boost::recursive_mutex::scoped_lock lock(kni_mutex);
195  kni->moveMotorToEnc(i, pos2_encoders, true, 50, 60000);
196  }
197 
198 // do
199 // {
200 // idleWait.sleep();
201 // refreshMotorStatus();
202 // } while (!allMotorsReady());
203  }
204 
205  // Result:
206  // Motor 0 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932)
207  // Motor 1 - acceleration: 2 (= -2.646220), max speed: 180 (=-1.190799)
208  // Motor 2 - acceleration: 2 (= 5.292440), max speed: 180 (=2.381598)
209  // --> wrong! the measured values are more like 2.6, 1.2
210  //
211  // Motor 3 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932)
212  // Motor 4 - acceleration: 2 (= -4.908739), max speed: 180 (=-2.208932)
213  // Motor 5 - acceleration: 2 (= 1.597410), max speed: 180 (=0.718834)
214  // (TODO: the gripper duration can be calculated from this)
215 }
216 
224  boost::function<bool()> isPreemptRequested)
225 {
226  ROS_DEBUG("Entered executeTrajectory. Spline size: %d, trajectory size: %d, number of motors: %d",
227  (int )traj->at(0).splines.size(), (int )traj->size(), kni->getNumberOfMotors());
228  try
229  {
230  // ------- wait until all motors idle
231  ros::Rate idleWait(10);
232  while (!allMotorsReady())
233  {
235  ROS_DEBUG("Motor status: %d, %d, %d, %d, %d, %d", motor_status_[0], motor_status_[1], motor_status_[2],
237 
238  // ------- check if motors are blocked
239  // it is important to do this inside the allMotorsReady() loop, otherwise we
240  // could get stuck in a deadlock if the motors crash while we wait for them to
241  // become ready
242  if (someMotorCrashed())
243  {
244  ROS_WARN("Motors are crashed before executing trajectory! Unblocking...");
245 
246  boost::recursive_mutex::scoped_lock lock(kni_mutex);
247  kni->unBlock();
248  }
249 
250  idleWait.sleep();
251  }
252 
253  // ------- wait until start time
254  ros::Time start_time = ros::Time(traj->at(0).start_time);
255  double time_until_start = (start_time - ros::Time::now()).toSec();
256 
257  if (time_until_start < -0.01)
258  {
259  ROS_WARN("Trajectory started %f s too late! Scheduled: %f, started: %f", -time_until_start, start_time.toSec(),
260  ros::Time::now().toSec());
261  }
262  else if (time_until_start > 0.0)
263  {
264  ROS_DEBUG("Sleeping %f seconds until scheduled start of trajectory", time_until_start);
265  ros::Time::sleepUntil(start_time);
266  }
267 
268  // ------- start trajectory
269  boost::recursive_mutex::scoped_lock lock(kni_mutex);
270 
271  // fix start times: set the trajectory start time to now(); since traj is a shared pointer,
272  // this fixes the current_trajectory_ in joint_trajectory_action_controller, which synchronizes
273  // the "state" publishing to the actual start time (more or less)
274  double delay = ros::Time::now().toSec() - traj->at(0).start_time;
275  for (size_t i = 0; i < traj->size(); i++)
276  {
277  traj->at(i).start_time += delay;
278  }
279 
280  // enable splines with gripper
281  bool isPresent;
282  int openEncoder, closeEncoder;
283  kni->getGripperParameters(isPresent, openEncoder, closeEncoder);
284  kni->setGripperParameters(false, openEncoder, closeEncoder);
285 
286  // iterate over all trajectory steps
287  for (size_t step = 0; step < traj->size(); step++)
288  {
289  ROS_DEBUG("Executing step %d", (int )step);
290 
291  if (isPreemptRequested())
292  {
293  ROS_INFO("Preempt requested. Aborting the trajectory!");
294  return true;
295  }
296 
297  Segment seg = traj->at(step);
298 
299  // + 1 to be flexible enough to perform trajectories that include the gripper
300  if (seg.splines.size() != joint_names_.size() && seg.splines.size() != (joint_names_.size() + 1))
301  {
302  ROS_ERROR("Wrong number of joints in specified trajectory (was: %zu, expected: %zu)!", seg.splines.size(),
303  joint_names_.size());
304  }
305 
307  if (someMotorCrashed())
308  {
309  ROS_ERROR("A motor crashed! Aborting to not destroy anything.");
310  return false;
311  }
312 
313  if (!ros::ok())
314  {
315  ROS_INFO("Stop trajectory because ROS node is stopped.");
316  return true;
317  }
318 
319  // time in 10 ms units, seg.duration is in seconds
320  short duration = static_cast<short>(seg.duration * 100);
321  // copy joint values and calculate to encoder values
322  for (size_t jointNo = 0; jointNo < seg.splines.size(); jointNo++)
323  {
324  short encoder = static_cast<short>(converter->angle_rad2enc(jointNo, seg.splines[jointNo].target_position));
325  desired_angles_[jointNo] = seg.splines[jointNo].target_position;
326  // the actual position
327  short p1 = ::round(converter->angle_rad2enc(jointNo, seg.splines[jointNo].coef[0]));
328  short p2 = ::round(64 * converter->vel_rad2enc(jointNo, seg.splines[jointNo].coef[1]));
329  short p3 = ::round(1024 * converter->acc_rad2enc(jointNo, seg.splines[jointNo].coef[2]));
330  short p4 = ::round(32768 * converter->jerk_rad2enc(jointNo, seg.splines[jointNo].coef[3]));
331 
332  kni->sendSplineToMotor(jointNo, encoder, duration, p1, p2, p3, p4);
333  }
334 
335  lock.unlock();
336  ros::spinOnce();
338 
339  while (seg.start_time > ros::Time::now().toSec())
340  {
341  if (isPreemptRequested())
342  {
343  ROS_INFO("Preempt requested. Aborting the trajectory!");
344  lock.lock();
345  kni->freezeRobot();
346  return true;
347  }
348  ros::spinOnce();
349  ros::Duration(0.001).sleep();
350  }
351  lock.lock();
352  kni->startSplineMovement(false);
353  }
354 
355  //kni->moveRobotToEnc(encoders, true); // to ensure that the goal position is reached
356  return true;
357  }
358  catch (const WrongCRCException &e)
359  {
360  ROS_ERROR(
361  "WrongCRCException: Two threads tried to access the KNI at once. This means that the locking in the Katana node is broken. (exception in executeTrajectory(): %s)",
362  e.message().c_str());
363  }
364  catch (const ReadNotCompleteException &e)
365  {
366  ROS_ERROR(
367  "ReadNotCompleteException: Another program accessed the KNI. Please stop it and restart the Katana node. (exception in executeTrajectory(): %s)",
368  e.message().c_str());
369  }
370  catch (const FirmwareException &e)
371  {
372  // TODO: find out what the real cause of this is when it happens again
373  // the message returned by the Katana is:
374  // FirmwareException : 'StopperThread: collision on axis: 1 (axis N)'
375  ROS_ERROR(
376  "FirmwareException: Motor collision? Perhaps we tried to send a trajectory that the arm couldn't follow. (exception in executeTrajectory(): %s)",
377  e.message().c_str());
378  }
379  catch (const MotorTimeoutException &e)
380  {
381  ROS_ERROR("MotorTimeoutException (exception in executeTrajectory(): %s)", e.what());
382  }
383  catch (const Exception &e)
384  {
385  ROS_ERROR("Unhandled exception in executeTrajectory(): %s", e.message().c_str());
386  }
387  catch (...)
388  {
389  ROS_ERROR("Unhandled exception in executeTrajectory()");
390  }
391 
392  return false;
393 }
394 
395 }
double vel_enc2rad(int index, short encoders)
KNIConverter * converter
Definition: Katana.h:75
const double JOINTS_STOPPED_POS_TOLERANCE
Definition: Katana300.h:64
virtual void testSpeed()
Definition: Katana300.cpp:140
const double JOINTS_STOPPED_VEL_TOLERANCE
Definition: Katana300.h:65
boost::recursive_mutex kni_mutex
Definition: Katana.h:72
virtual void refreshMotorStatus()
Definition: Katana.cpp:228
double acc_rad2enc(int index, double acc)
std::string message() const
virtual void freezeRobot()
Definition: Katana300.cpp:72
virtual ~Katana300()
Definition: Katana300.cpp:40
MSF_MOTCRASHED
void refreshEncoders()
Definition: Katana.cpp:155
std::vector< TMotStsFlg > motor_status_
Definition: Katana.h:73
static bool sleepUntil(const Time &end)
bool sleep() const
const size_t NUM_MOTORS
The number of motors in the katana (= all 5 "real" joints + the gripper)
virtual void setLimits()
Definition: Katana300.cpp:44
std::vector< double > motor_velocities_
#define ROS_WARN(...)
virtual bool moveJoint(int jointIndex, double turningAngle)
Definition: Katana300.cpp:81
std::vector< std::string > joint_names_
virtual void refreshMotorStatus()
Definition: Katana300.cpp:93
double angle_rad2enc(int index, double angle)
#define ROS_INFO(...)
virtual std::vector< double > getMotorAngles()
ROSCPP_DECL bool ok()
virtual bool allMotorsReady()
Definition: Katana300.cpp:124
boost::shared_ptr< CLMBase > kni
Definition: Katana.h:71
bool sleep()
virtual bool moveJoint(int jointIndex, double turningAngle)
Definition: Katana.cpp:461
unsigned int step
double vel_rad2enc(int index, double vel)
const char * what() const
Wrapper class around the KNI (Katana Native Library).
Definition: Katana.h:48
static Time now()
const size_t NUM_JOINTS
The number of joints in the katana (= only the 5 "real" joints)
virtual bool allJointsReady()
Definition: Katana300.cpp:103
virtual bool someMotorCrashed()
Definition: Katana.cpp:494
std::vector< Spline > splines
ROSCPP_DECL void spinOnce()
double acc_enc2rad(int index, short encoders)
#define ROS_ERROR(...)
short round(const double x)
Definition: Katana.cpp:532
std::vector< double > desired_angles_
Definition: Katana300.h:68
double jerk_rad2enc(int index, double jerk)
virtual bool executeTrajectory(boost::shared_ptr< SpecifiedTrajectory > traj, boost::function< bool()> isPreemptRequested)
Definition: Katana300.cpp:223
#define ROS_DEBUG(...)


katana
Author(s): Martin Günther
autogenerated on Fri Jun 7 2019 22:06:58