Laelaps  2.3.5
RoadNarrows Robotics Small Outdoor Mobile Robot Project
laePlatform.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Laelaps
4 //
5 // Library: liblaelaps
6 //
7 // File: laePlatform.cxx
8 //
9 /*! \file
10  *
11  * \brief Laelaps robotic platform control and dynamics state implementation.
12  *
13  * \author Robin Knight (robin.knight@roadnarrows.com)
14  *
15  * \par Copyright
16  * \h_copy 2015-2017. RoadNarrows LLC.\n
17  * http://www.roadnarrows.com\n
18  * All Rights Reserved
19  */
20 /*
21  * @EulaBegin@
22  *
23  * Unless otherwise stated explicitly, all materials contained are copyrighted
24  * and may not be used without RoadNarrows LLC's written consent,
25  * except as provided in these terms and conditions or in the copyright
26  * notice (documents and software) or other proprietary notice provided with
27  * the relevant materials.
28  *
29  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
30  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
31  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
32  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
33  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
34  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41  *
42  * @EulaEnd@
43  */
44 ////////////////////////////////////////////////////////////////////////////////
45 
46 #include <math.h>
47 
48 #include <string>
49 #include <vector>
50 
51 #include "rnr/rnrconfig.h"
52 
53 #include "Laelaps/RoboClaw.h"
54 
55 #include "Laelaps/laelaps.h"
56 #include "Laelaps/laeDesc.h"
57 #include "Laelaps/laeTune.h"
58 #include "Laelaps/laeMotor.h"
59 #include "Laelaps/laeUtils.h"
60 #include "Laelaps/laeDb.h"
61 #include "Laelaps/laeTraj.h"
62 #include "Laelaps/laePowertrain.h"
63 #include "Laelaps/laePlatform.h"
64 
65 
66 using namespace std;
67 using namespace laelaps;
68 using namespace motor::roboclaw;
69 
70 
71 // -----------------------------------------------------------------------------
72 // Class LaeMotorCtlrState
73 // -----------------------------------------------------------------------------
74 
75 void LaeMotorCtlrState::clear()
76 {
77  m_fMainVolts = 0.0;
78  m_fBoardTemp = 0.0;
79  m_uStatus = ParamStatusNormal;
80 }
81 
82 LaeMotorCtlrState::LaeMotorCtlrState(const LaeMotorCtlrState &src)
83 {
84  m_strName = src.m_strName;
85  m_fMainVolts = src.m_fMainVolts;
86  m_fBoardTemp = src.m_fBoardTemp;
87  m_uStatus = src.m_uStatus;
88 }
89 
90 LaeMotorCtlrState LaeMotorCtlrState::operator=(const LaeMotorCtlrState &rhs)
91 {
92  m_strName = rhs.m_strName;
93  m_fMainVolts = rhs.m_fMainVolts;
94  m_fBoardTemp = rhs.m_fBoardTemp;
95  m_uStatus = rhs.m_uStatus;
96 
97  return *this;
98 }
99 
100 
101 // -----------------------------------------------------------------------------
102 // Class LaePlatform
103 // -----------------------------------------------------------------------------
104 
105 LaePlatform::LaePlatform() : m_strName("plaform")
106 {
107  clear();
108 
111 }
112 
114 {
115  int nCtlr;
116  int i;
117 
118  m_strName = src.m_strName;
119 
120  m_dimRobot = src.m_dimRobot;
121  m_dimBody = src.m_dimBody;
122 
125 
126  for(i = 0; i < LaeMotorsNumOf; ++i)
127  {
128  m_fPosLast[i] = src.m_fPosLast[i];
129  }
130 
131  for(i = 0; i < HistSize; ++i)
132  {
133  m_pose[i] = src.m_pose[i];
134  }
135 
136  m_fOdometer = src.m_fOdometer;
137  m_fVelocity = src.m_fVelocity;
138 
140  m_fVoltsAvg = src.m_fVoltsAvg;
141  m_fTempAvg = src.m_fTempAvg;
142 
143  for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
144  {
145  m_ctlr[nCtlr] = src.m_ctlr[nCtlr];
146  }
147 }
148 
150 {
151  int nCtlr;
152  int i;
153 
154  m_strName = rhs.m_strName;
155 
156  m_dimRobot = rhs.m_dimRobot;
157  m_dimBody = rhs.m_dimBody;
158 
161 
162  for(i = 0; i < LaeMotorsNumOf; ++i)
163  {
164  m_fPosLast[i] = rhs.m_fPosLast[i];
165  }
166 
167  for(i = 0; i < HistSize; ++i)
168  {
169  m_pose[i] = rhs.m_pose[i];
170  }
171 
172  m_fOdometer = rhs.m_fOdometer;
173  m_fVelocity = rhs.m_fVelocity;
174 
176  m_fVoltsAvg = rhs.m_fVoltsAvg;
177  m_fTempAvg = rhs.m_fTempAvg;
178 
179  for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
180  {
181  m_ctlr[nCtlr] = rhs.m_ctlr[nCtlr];
182  }
183 
184  return *this;
185 }
186 
188 {
189  int i;
190 
191  m_dimRobot.clear();
192  m_dimBody.clear();
193 
194  m_fWheelbase = 0.0;
195  m_fWheeltrack = 0.0;
196 
197  for(i = 0; i < LaeMotorsNumOf; ++i)
198  {
199  m_fPosLast[i] = 0.0;
200  }
201 
202  for(i = 0; i < HistSize; ++i)
203  {
204  m_pose[i].clear();
205  }
206 
207  m_fOdometer = 0.0;
208  m_fVelocity = 0.0;
209 
210  m_fAmpsMotors = 0.0;
211  m_fVoltsAvg = 0.0;
212  m_fTempAvg = 0.0;
213 
216 }
217 
219 {
220  // base kinematics
221  m_dimBody = desc.m_dimBody;
222  m_dimRobot = desc.m_dimRobot;
223  m_fWheelbase = desc.m_fWheelbase;
225 }
226 
228 {
229  LaeDescBase desc;
230  double fTuneTireRadius, fTuneTireWidth; // tire dimensions
231 
232  // assumes all tires are the same dimensions
233  tunes.getTireDimParams(LaeKeyLeftFront, fTuneTireRadius, fTuneTireWidth);
234 
235  desc.calcDimensions(fTuneTireRadius, fTuneTireWidth);
236 
237  m_dimBody = desc.m_dimBody;
238  m_dimRobot = desc.m_dimRobot;
239  m_fWheelbase = desc.m_fWheelbase;
241 
242  return LAE_OK;
243 }
244 
245 int LaePlatform::reload(const LaeTunes &tunes)
246 {
247  return configure(tunes);
248 }
249 
251 {
252  int i;
253 
254  clearPoses();
255 
256  for(i = 0; i < LaeMotorsNumOf; ++i)
257  {
258  m_fPosLast[i] = 0.0;
259  }
260 
261  m_fOdometer = 0.0;
262 }
263 
265 {
266  static double ReallyZero = 1e-4;
267 
268  LaeMapPowertrain::const_iterator iter;
269 
270  int nMotorId; // motor id
271  double fDeltaPos; // delta position last position (radians)
272  double fDeltaDist[LaeMotorsNumOf]; // delta wheel distances (meters)
273  double fDeltaOd; // delta odometer (meters)
274  double fDistL, fDistR; // left and right average delta distance
275  double s; // delta arc length
276  double r; // radius of curvature
277  double c; // central angle
278  double dx, dy, da; // delta pose (m, m, radians)
279  LaePose pose; // new pose
280 
281  // zero current velocity, delta odometer
282  m_fVelocity = 0.0;
283  fDeltaOd = 0.0;
284 
285  //
286  // Process powertrain kinodynamics to arrive at platform dynamics.
287  //
288  for(iter = mapPowertrains.begin(); iter != mapPowertrains.end(); ++iter)
289  {
290  const LaePowertrain &train = iter->second;
291 
292  nMotorId = train.m_attr.m_nMotorId;
293 
294  // delta position (radians) and delta distance (meters)
295  fDeltaPos = train.m_state.m_fPosition - m_fPosLast[nMotorId];
296  m_fPosLast[nMotorId] = train.m_state.m_fPosition;
297  fDeltaDist[nMotorId] = fDeltaPos * train.m_attr.m_fMetersPerRadian;
298 
299  // sum delta odometer distances
300  fDeltaOd += fDeltaDist[nMotorId];
301 
302  // sum wheel velocity (radians/s) to linear velocity (meters/s)
304  }
305 
306  //
307  // Average the odometer delta sum value and accumulate to attain meters
308  // traveled at the platform center of rotation. Note that this odometer is
309  // the absolute distance traveled.
310  //
311  fDeltaOd = fabs(fDeltaOd / (double)LaeMotorsNumOf);
312  m_fOdometer += fDeltaOd;
313 
314  //
315  // Average the velocity sum. The velocity is calculated from the platform
316  // center of rotation. Note that this velocity is the absolute value.
317  //
318  m_fVelocity = fabs(m_fVelocity / (double)LaeMotorsNumOf);
319 
320  //
321  // Average the left and right side delta distances traveled.
322  //
323  fDistL = (fDeltaDist[LaeMotorIdLF] + fDeltaDist[LaeMotorIdLR]) / 2.0;
324  fDistR = (fDeltaDist[LaeMotorIdRF] + fDeltaDist[LaeMotorIdRR]) / 2.0;
325 
326  //
327  // Calculate the new absolute orientation.
328  //
329  // The new theta can be calculated directly from current odometry.
330  //
331  // Eq. s = r * c, where
332  //
333  // s = arc length (meters)
334  // r = radius of curvature (meters) == wheel base
335  // c = central angle (radians)
336  //
337  s = (fDistR + fDistL) / 2.0;
338  c = (fDistR - fDistL) / m_fWheelbase;
339 
340  //
341  // No linear component (i.e. spin or stopped).
342  //
343  if( fabs(s) <= ReallyZero )
344  {
345  dx = 0.0;
346  dy = 0.0;
347  da = c;
348  }
349 
350  //
351  // Degenerate curve: straight path.
352  //
353  // The arc length is a straigt line.
354  //
355  else if( fabs(c) <= ReallyZero )
356  {
357  dx = s;
358  dy = 0.0;
359  da = 0.0;
360  }
361 
362  //
363  // Circular arc path.
364  //
365  // Note: The following comments are nice, but the calculations simplify when
366  // delta distances are used.
367  //
368  // The center of rotation is a pi/2 rotation from the robot frame of
369  // reference. Rotating 90 degrees and translating the center to 0,0, we
370  // can calculate the delta position. From the deltas, the current absolute
371  // position is determined.
372  //
373  // Using trig identities:
374  // sin(-u) = -sin(u)
375  // cos(-u) = cos(u)
376  // sin(u) = cos(theta)
377  // cos(u) = sin(theta)
378  //
379  // Let u = pi/2 - theta
380  // -u = theta - pi/2
381  // Then:
382  // dx = r * (m.cos(theta[cur]-m.pi/2) - m.cos(theta[prev]-m.pi/2))
383  // dy = r * (m.sin(theta[cur]-m.pi/2) - m.sin(theta[prev]-m.pi/2))
384  //
385  else
386  {
387  r = s / c;
388  dx = r * sin(c);
389  dy = r * -cos(c);
390  da = c;
391  }
392 
393  //
394  // New current pose.
395  //
396  pose.m_x = m_pose[IdxPrev].m_x + dx;
397  pose.m_y = m_pose[IdxPrev].m_y + dy;
398  pose.m_theta = fmod(m_pose[IdxPrev].m_theta + da, M_TAU);
399 
400  pushNewPose(pose);
401 
402  //
403  // Save to real-time DB.
404  //
410 
411  return LAE_OK;
412 }
413 
415  double fVolts,
416  double fTemp,
417  uint_t uStatus)
418 {
419  if( (nCtlr < 0) || (nCtlr >= LaeNumMotorCtlrs) )
420  {
421  LOGERROR("Motor controller id %d: Out-of-range.", nCtlr);
422  return -LAE_ECODE_BAD_VAL;
423  }
424 
425  m_ctlr[nCtlr].m_fMainVolts = fVolts;
426  m_ctlr[nCtlr].m_fBoardTemp = fTemp;
427  m_ctlr[nCtlr].m_uStatus = uStatus;
428 
429  return LAE_OK;
430 }
431 
432 int LaePlatform::updateHealth(const LaeMapPowertrain &mapPowertrains)
433 {
434  LaeMapPowertrain::const_iterator iter;
435 
436  int n;
437 
438  m_fAmpsMotors = 0.0;
439  m_fVoltsAvg = 0.0;
440  m_fTempAvg = 0.0;
441 
442  n = 0;
443 
444  for(iter = mapPowertrains.begin(); iter != mapPowertrains.end(); ++iter)
445  {
446  const LaePowertrain &train = iter->second;
447 
448  m_fAmpsMotors += train.m_state.m_fAmps;
449  m_fVoltsAvg += train.m_state.m_fVolts;
450  m_fTempAvg += train.m_state.m_fTemp;
451 
452  ++n;
453  }
454 
455  m_fVoltsAvg /= (double)n;
456  m_fTempAvg /= (double)n;
457 
459 
460  return LAE_OK;
461 }
462 
464 {
465  for(int i = 0; i < HistSize; ++i)
466  {
467  m_pose[i].clear();
468  }
469 }
470 
472 {
473  // save pose
475 
476  // clear new pose
477  m_pose[IdxCur] = pose;
478 }
static const int LaeMotorIdRR
right rear
Definition: laeMotor.h:106
double m_fWheeltrack
wheeltrack (m)
Definition: laePlatform.h:146
double m_fVelocity
robot velocity (meters/second)
Definition: laePlatform.h:153
virtual int updateStateDynamics(const LaeMapPowertrain &mapPowertrains)
Update robot platform state dynamics.
double m_fAmpsMotors
total draw from all motors (A)
Definition: laePlatform.h:156
std::string m_strName
robot platform name
Definition: laePlatform.h:140
double m_fAmps
motor draw (A)
std::string m_strName
motor controller name
Definition: laePlatform.h:78
double m_fWheelbase
wheelbase(m)
Definition: laeDesc.h:119
static const int LaeMotorCtlrIdRear
rear motor controller
Definition: laeMotor.h:114
Laelaps tuning data class.
Definition: laeTune.h:566
Trajectory classes interfaces.
virtual int configure(const LaeDescBase &desc)
Configure robot platform from product description.
double m_fTemp
motor temperature (C)
LaeDbKin m_kin
kinodynamics
Definition: laeDb.h:236
LaeDbRobotStatus m_robotstatus
robot status data
Definition: laeDb.h:229
static const int LaeMotorsNumOf
number of motors
Definition: laeMotor.h:107
double m_y
robot absolute y position (meters)
Definition: laeTraj.h:174
double m_theta
robot orientation (radians)
Definition: laeTraj.h:175
double m_fVelocity
robot velocity (meters/second)
Definition: laeDb.h:181
RoboClaw motor controller class interface.
static const char *const LaeKeyRear
rear
Definition: laeMotor.h:93
LaeDbKinRobot m_robot
robot kinodynmics
Definition: laeDb.h:191
LaePlatform operator=(const LaePlatform &rhs)
Assignment operator.
static const char *const LaeKeyFront
front
Definition: laeMotor.h:92
double m_fOdometer
robot odometer (meters)
Definition: laeDb.h:180
LaeDb RtDb
The real-time database.
Definition: laeDb.h:244
double m_fBoardTemp
average sensed interior tempature (C)
Definition: laePlatform.h:80
virtual int reload(const LaeTunes &tunes)
Reload tuning parameters and re-configure.
double m_x
robot absolute x position (meters)
Definition: laeTraj.h:173
static const int LaeMotorIdRF
right front
Definition: laeMotor.h:104
static const int LaeMotorIdLR
left rear
Definition: laeMotor.h:105
double m_y
robot absolute y position (meters)
Definition: laeDb.h:178
LaePowertrainAttr m_attr
semi-fixed attribute data
LaePlatform()
Default constructor.
double m_theta
robot orientation (radians)
Definition: laeDb.h:179
Dim m_dimBody
dimensions of robot body
Definition: laePlatform.h:144
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
Definition: laeAlarms.h:64
Dim m_dimRobot
total dimensions of robot (TODO)
Definition: laePlatform.h:143
Laelaps robotic base mobile platform description class interface.
LaePose m_pose[HistSize]
robot pose (meters, meters, radians)
Definition: laePlatform.h:151
double m_fPosLast[LaeMotorsNumOf]
last sensed wheel positions (radians)
Definition: laePlatform.h:149
virtual int updateHealth(const LaeMapPowertrain &mapPowertrains)
Update robot platform health state.
Laelaps common utilities.
double m_fVolts
input motor voltage (V)
virtual int resetOdometer()
Reset odometry to zero.
double m_x
robot absolute x position (meters)
Definition: laeDb.h:177
Laelaps powertrain class interfaces.
std::map< std::string, LaePowertrain > LaeMapPowertrain
Map of powertrain kinodynamics.
Laelaps tuning.
index of current state
Definition: laePlatform.h:136
Robot base motor controller board state.
Definition: laePlatform.h:75
Dim m_dimBody
body dimensions(m)
Definition: laeDesc.h:118
double m_fMainVolts
average sensed battery voltage (V)
Definition: laePlatform.h:79
static const int LaeMotorIdLF
left front
Definition: laeMotor.h:103
double m_fVoltsAvg
average sensed battery voltage (V)
Definition: laePlatform.h:157
virtual void clearPoses()
Clear pose history.
double m_fMetersPerRadian
tire meters per radian
Laelaps robotic platform control and dynamics state interface.
uint_t m_uStatus
board status
Definition: laePlatform.h:81
Robotic base platform description.
Definition: laeDesc.h:113
Laelaps motors, encoder, and controllers hardware abstraction interfaces.
virtual int updateCtlrHealth(int nCtlr, double fVolts, double fTemp, uint_t uStatus)
Update robot platform motor controller health state.
Dim m_dimRobot
robot full dimensions(m)
Definition: laeDesc.h:117
void clear()
Clear data sans name.
Definition: laePlatform.cxx:75
static const int LAE_ECODE_BAD_VAL
bad value general error
Definition: laelaps.h:76
double m_fWheelbase
wheelbase (m)
Definition: laePlatform.h:145
static const int LaeNumMotorCtlrs
number of motor controllers
Definition: laeMotor.h:115
Laelaps 2D pose class.
Definition: laeTraj.h:170
virtual void pushNewPose(const LaePose &pose)
Push a new pose on the pose history.
LaePowertrainState m_state
dynamic state data
static const int LaeMotorCtlrIdFront
front motor controller
Definition: laeMotor.h:113
index of previous history
Definition: laePlatform.h:135
double m_fVelocity
wheel angular velocity (radians/second)
double m_fTempAvg
average interior temperature
Definition: laeDb.h:113
void clear()
Clear data sans name.
double m_fWheeltrack
wheeltrack(m)
Definition: laeDesc.h:120
LaeMotorCtlrState m_ctlr[LaeNumMotorCtlrs]
motor controllers&#39; state
Definition: laePlatform.h:161
#define M_TAU
tau = 2 * pi
Definition: laeUtils.h:66
double m_fTempAvg
average sensed interior tempature (C)
Definition: laePlatform.h:158
double m_fPosition
wheel angular position (radians)
void getTireDimParams(const std::string &strName, double &fTireRadius, double &fTireWidth) const
Get tire dimensions tune parameters.
Definition: laeTune.cxx:382
Powertrain data class.
Laelaps real-time "database".
static const char *const LaeKeyLeftFront
left front
Definition: laeMotor.h:94
void calcDimensions(double fTireRadius, double fTireWidth)
Calculate robot dimensions.
Definition: laeDesc.cxx:140
double m_fOdometer
robot odometer (meters)
Definition: laePlatform.h:152
Top-level package include file.
static const int LAE_OK
not an error, success
Definition: laelaps.h:71
Robot platform control and state data class.
Definition: laePlatform.h:127