Dynamixel  2.9.5
RoadNarrows Robotics Dynamixel Package
dynashell_recording.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: Dynamixel
4 //
5 // Program: dynashell
6 //
7 // File: dynashell_recording.h
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2015-01-12 10:56:06 -0700 (Mon, 12 Jan 2015) $
12  * $Rev: 3845 $
13  *
14  * \brief The Dynamixel Recording Class.
15  *
16  * \note May promote this class to libDynamixel library.
17  *
18  * \author Robin Knight (robin.knight@roadnarrows.com)
19  *
20  * \copyright
21  * \h_copy 2011-2017. RoadNarrows LLC.\n
22  * http://www.roadnarrows.com\n
23  * All Rights Reserved
24  */
25 /*
26  * @EulaBegin@
27  *
28  * Unless otherwise stated explicitly, all materials contained are copyrighted
29  * and may not be used without RoadNarrows LLC's written consent,
30  * except as provided in these terms and conditions or in the copyright
31  * notice (documents and software) or other proprietary notice provided with
32  * the relevant materials.
33  *
34  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY
35  * MEMBERS/EMPLOYEES/CONTRACTORS OF ROADNARROWS OR DISTRIBUTORS OF THIS SOFTWARE
36  * BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
37  * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
38  * DOCUMENTATION, EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN
39  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * THE AUTHORS AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
42  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
43  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
44  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
45  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
46  *
47  * @EulaEnd@
48  */
49 ////////////////////////////////////////////////////////////////////////////////
50 
51 #ifndef _DYNASHELL_RECORDING_H
52 #define _DYNASHELL_RECORDING_H
53 
54 #include <cstring>
55 #include <iostream>
56 #include <fstream>
57 #include <vector>
58 #include <map>
59 
60 #include "rnr/rnrconfig.h"
61 #include "rnr/log.h"
62 
63 #include "Dynamixel/Dynamixel.h"
64 #include "Dynamixel/DynaComm.h"
65 #include "Dynamixel/DynaChain.h"
66 
67 #include "dynashell_util.h"
68 
69 using namespace std;
70 
71 
72 // -----------------------------------------------------------------------------
73 // ServoInfo_T Structure
74 // -----------------------------------------------------------------------------
75 
76 /*!
77  * \brief Key Recorded Servo Information Structure Type.
78  */
79 typedef struct
80 {
81  int m_nServoId; ///< servo id
82  uint_t m_uModelNum; ///< servo model number
83 } ServoInfo_T;
84 
85 
86 // -----------------------------------------------------------------------------
87 // DynaRecord Class
88 // -----------------------------------------------------------------------------
89 
90 /*!
91  * Dynamixel record.
92  */
94 {
95 public:
96  static const int END = -1; ///< past-the-end mark
97 
98  /*!
99  * \brief Record Field Tuple Structure Type.
100  */
101  typedef struct
102  {
103  int m_nPos; ///< servo position
104  int m_nSpeed; ///< servo speed
105  } FieldTuple_T;
106 
107  /*! 'Not a Field' field. */
108  static const FieldTuple_T NoField;
109 
110  /*!
111  * \brief Default constructor.
112  */
114  {
115  m_nFieldCnt = 0;
116  }
117 
118  /*!
119  * \brief Default destructor.
120  */
121  virtual ~DynaRecord() { }
122 
123  /*!
124  * \brief Get the current number of field tuples in record.
125  *
126  * \return Field tuple count.
127  */
128  int GetFieldCount() const
129  {
130  return m_nFieldCnt;
131  }
132 
133  /*!
134  * \brief Reset the field count to zero.
135  */
137  {
138  m_nFieldCnt = 0;
139  }
140 
141  virtual int AddField(int nPos, int nSpeed);
142 
143  /*!
144  * \brief Test if field is 'Not a Field'.
145  *
146  * \param field Field tuple to test.
147  *
148  * \return Returns true or false.
149  */
150  static const bool NaF(FieldTuple_T &field)
151  {
152  return (field.m_nPos == DynaRecord::NoField.m_nPos) &&
154  }
155 
156  DynaRecord &operator=(const DynaRecord &rhs);
157 
158  /*!
159  * \brief Subscript operator.
160  *
161  * \param nFldNum Field number subscript.
162  *
163  * \return Field tuple.
164  */
165  FieldTuple_T const &operator[](const int nFldNum) const
166  {
167  return nFldNum < m_nFieldCnt? m_field[nFldNum]: NoField;
168  }
169 
170 protected:
171  int m_nFieldCnt; ///< number of field tuples
172  FieldTuple_T m_field[DYNA_ID_NUMOF]; ///< one record of field data
173 
174  friend class DynaRecording;
175 };
176 
177 
178 // -----------------------------------------------------------------------------
179 // DynaRecording Class
180 // -----------------------------------------------------------------------------
181 
182 /*!
183  * Dynamixel recording. The recording is usually made by a training session,
184  * but does not have to be.
185  */
187 {
188 public:
189  static const int MaxRecords = 5000; ///< maximum number of records
190  static const int END = -1; ///< past-the-end mark
191 
192  /*!
193  * \brief Default constructor.
194  */
196  {
197  m_sDate = NULL;
198  m_nRecordCnt = 0;
199  }
200 
201  /*!
202  * \brief Default destructor.
203  */
204  virtual ~DynaRecording()
205  {
206  m_vecServoInfo.clear();
207  m_mapIIdx.clear();
208  DELOBJ(m_sDate);
209  }
210 
211  virtual void Init(int nSamplePeriod, const char *sDate = NULL);
212 
213  /*!
214  * \brief Get the first record number in the recording.
215  *
216  * \return
217  * If a recording is present, returns the first record number (0).\n
218  * Otherwise \ref END is returned.
219  */
220  virtual int FirstRecord()
221  {
222  return m_nRecordCnt > 0? 0: END;
223  }
224 
225  /*!
226  * \brief Get the next record number in the recording after the given record
227  * number.
228  *
229  * \param nRecNum Record number.
230  *
231  * \return
232  * If there is a next record present in the recording, returns the next
233  * record number.\n
234  * Otherwise \ref END is returned.
235  */
236  virtual int NextRecord(int nRecNum)
237  {
238  if( nRecNum == END )
239  {
240  return END;
241  }
242  ++nRecNum;
243  return nRecNum < m_nRecordCnt? nRecNum: END;
244  }
245 
246  virtual int AddRecord();
247 
248  /*!
249  * \brief Copy source record to destination record.
250  *
251  * \param nRecNumDst Destination record number.
252  * \param nRecNumSrc Source record number.
253  *
254  * \copydoc doc_return_std
255  */
256  virtual int CopyRecord(int nRecNumDst, int nRecNumSrc)
257  {
258  if( (nRecNumDst == END) || (nRecNumDst >= m_nRecordCnt) ||
259  (nRecNumSrc == END) || (nRecNumSrc >= m_nRecordCnt) )
260  {
261  return -DYNA_ECODE_BAD_VAL;
262  }
263 
264  m_record[nRecNumDst] = m_record[nRecNumSrc];
265 
266  return DYNA_OK;
267  }
268 
269  /*!
270  * \brief Get the first field number in the given record.
271  *
272  * \param nRecNum Record number.
273  *
274  * \return
275  * If a field is present, returns the first field number (0).\n
276  * Otherwise \ref END is returned.
277  */
278  virtual int FirstField(int nRecNum)
279  {
280  if( (nRecNum < m_nRecordCnt) && (m_record[nRecNum].GetFieldCount() > 0) )
281  {
282  return 0;
283  }
284  else
285  {
286  return END;
287  }
288  }
289 
290  /*!
291  * \brief Get the next field number in the record after the given field
292  * number.
293  *
294  * \param nRecNum Record number.
295  * \param nFldNum Field number.
296  *
297  * \return
298  * If there is a next field present in the record, returns the next
299  * field number.\n
300  * Otherwise \ref END is returned.
301  */
302  virtual int NextField(int nRecNum, int nFldNum)
303  {
304  if( (nFldNum == END) || (nRecNum >= m_nRecordCnt) )
305  {
306  return END;
307  }
308 
309  ++nFldNum;
310 
311  return nFldNum < m_record[nRecNum].GetFieldCount()? nFldNum: END;
312  }
313 
314  virtual int AddFieldTuple(int nRecNum, int nServoId, int nPos, int nSpeed);
315 
316  /*!
317  * \brief Get the given recorded field tuple.
318  *
319  * \param nRecNum Record number.
320  * \param nFldNum Field number.
321  *
322  * \return
323  * On success, returns the specified field tuple.\n
324  * On failure, returns \ref DynaRecord::NoField.
325  * (use \ref DynaRecord::NaF() to test);
326  */
327  virtual const DynaRecord::FieldTuple_T &GetField(const int nRecNum,
328  const int nFldNum) const
329  {
330  if( (nRecNum < m_nRecordCnt) &&
331  (nFldNum < m_record[nRecNum].GetFieldCount()) )
332  {
333  return m_record[nRecNum][nFldNum];
334  }
335  else
336  {
338  }
339  }
340 
341  /*!
342  * \brief Get the number of records in the recording.
343  *
344  * \reuturn Number of records.
345  */
346  virtual int GetNumOfRecords()
347  {
348  return m_nRecordCnt;
349  }
350 
351  /*!
352  * \brief Get the number of servos in the recording.
353  *
354  * The number of servos is the count of registered servos in the recording
355  * header.
356  *
357  * \return Number of servos.
358  */
360  {
361  return (int)m_vecServoInfo.size();
362  }
363 
364  virtual int RegisterServoInfo(int nServoId, uint_t uModelNum);
365 
366  /*!
367  * \brief Get the servo id associated with the given field number.
368  *
369  * \return
370  * On success, returns the servo id. Otherwise \ref DYNA_ID_NONE is returned.
371  */
372  virtual const int GetServoId(int nFldNum)
373  {
374  return (nFldNum < (int)m_vecServoInfo.size())?
375  m_vecServoInfo[nFldNum].m_nServoId: DYNA_ID_NONE;
376  }
377 
378  /*!
379  * \brief Check if the given servo is associated with the given field number,
380  * as per the ordering of the registered servos in the recording header.
381  *
382  * \param nFldNum Field number.
383  * \param nServoid Servo Id.
384  *
385  * \return Returns true or false.
386  */
387  virtual bool HasServoAt(int nFldNum, int nServoId) const
388  {
389  return (nFldNum < (int)m_vecServoInfo.size()) &&
390  (m_vecServoInfo[nFldNum].m_nServoId == nServoId);
391  }
392 
393  /*!
394  * \brief Check if the given servo is in the list of registered servos in the
395  * recording header.
396  *
397  * \param nServoid Servo Id.
398  *
399  * \return Returns true or false.
400  */
401  virtual bool HasServo(int nServoId)
402  {
403  return m_mapIIdx.find(nServoId) != m_mapIIdx.end();
404  }
405 
406  /*!
407  * \brief Get the registered servo model number.
408  *
409  * \param nServoid Servo Id.
410  *
411  * \return Returns the model number. If no servo is found returns
412  * \ref DYNA_MODEL_NUM_GENERIC.
413  */
414  virtual uint_t GetServoModelNumber(int nServoId)
415  {
416  MapIIdx::iterator iter;
417 
418  if( (iter = m_mapIIdx.find(nServoId)) != m_mapIIdx.end() )
419  {
420  return m_vecServoInfo[m_mapIIdx[nServoId]].m_uModelNum;
421  }
422  else
423  {
424  return DYNA_MODEL_NUM_GENERIC;
425  }
426  }
427 
428  /*!
429  * \brief Get the sample period of the recording.
430  *
431  * \return Returns the sample period in milliseconds.
432  */
433  virtual int GetSamplePeriod() const
434  {
435  return m_nSamplePeriod;
436  }
437 
438  /*!
439  * \brief Set the sample period of the recording.
440  *
441  * \param nSamplePeriod Sample period in milliseconds.
442  */
443  virtual int SetSamplePeriod(int nSamplePeriod)
444  {
445  if( nSamplePeriod < 1 )
446  {
447  nSamplePeriod = 1;
448  }
449  m_nSamplePeriod = nSamplePeriod;
450  }
451 
452  /*!
453  * \brief Get the recording data.
454  *
455  * \return Returns date string.
456  */
457  virtual const char *GetDate() const
458  {
459  return m_sDate;
460  }
461 
462  virtual void SetDate(const char *sDate);
463 
464  /*!
465  * \brief Subscript operator.
466  *
467  * \param nRecNum Record number subscript.
468  *
469  * \return DynaRecord.
470  */
471  DynaRecord const &operator[](const int nRecNum) const
472  {
473  // TODO return nRecNum < m_nFieldCnt? m_record[nRecNum]: NoRecord;
474  return m_record[nRecNum];
475  }
476 
477 protected:
478 
479  /*!
480  * \brief Map of record servos ids and model numbers indexed by field number.
481  */
482  typedef vector<ServoInfo_T> VecServoInfo;
483 
484  /*!
485  * \brief Indirect indexing by servo id of servo info map.
486  */
487  typedef map<int,int> MapIIdx;
488 
489  char *m_sDate; ///< recording date
490  VecServoInfo m_vecServoInfo; ///< vector of recorded servo information
491  MapIIdx m_mapIIdx; ///< indirect index map
492  int m_nSamplePeriod; ///< recording sample period (ms)
493  int m_nRecordCnt; ///< number of records recorded
494  DynaRecord m_record[MaxRecords]; ///< the recording data
495 };
496 
497 
498 #endif // _DYNASHELL_RECORDING_H
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
virtual int GetNumOfRecords()
Get the number of records in the recording.
char * m_sDate
recording date
#define DYNA_OK
not an error, success
Definition: Dynamixel.h:78
#define DYNA_MODEL_NUM_GENERIC
generic, base model
Definition: Dynamixel.h:119
Record Field Tuple Structure Type.
Dynamixel shell utilities.
virtual ~DynaRecording()
Default destructor.
DynaRecord()
Default constructor.
DynaRecord const & operator[](const int nRecNum) const
Subscript operator.
FieldTuple_T const & operator[](const int nFldNum) const
Subscript operator.
#define DELOBJ(p)
Delete an allocated object convenience macro.
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
Key Recorded Servo Information Structure Type.
virtual const int GetServoId(int nFldNum)
Get the servo id associated with the given field number.
virtual int SetSamplePeriod(int nSamplePeriod)
Set the sample period of the recording.
#define DYNA_ID_NUMOF
number of unique servo id&#39;s
Definition: Dynamixel.h:148
virtual uint_t GetServoModelNumber(int nServoId)
Get the registered servo model number.
int m_nServoId
servo id
virtual int GetSamplePeriod() const
Get the sample period of the recording.
VecServoInfo m_vecServoInfo
vector of recorded servo information
static const FieldTuple_T NoField
virtual const char * GetDate() const
Get the recording data.
virtual bool HasServoAt(int nFldNum, int nServoId) const
Check if the given servo is associated with the given field number, as per the ordering of the regist...
int m_nRecordCnt
number of records recorded
MapIIdx m_mapIIdx
indirect index map
virtual int FirstRecord()
Get the first record number in the recording.
DynaRecording()
Default constructor.
map< int, int > MapIIdx
Indirect indexing by servo id of servo info map.
virtual int NextField(int nRecNum, int nFldNum)
Get the next field number in the record after the given field number.
virtual int GetNumOfServosInRecording()
Get the number of servos in the recording.
virtual int NextRecord(int nRecNum)
Get the next record number in the recording after the given record number.
RoadNarrows Dynamixel Top-Level Package Header File.
virtual const DynaRecord::FieldTuple_T & GetField(const int nRecNum, const int nFldNum) const
Get the given recorded field tuple.
virtual bool HasServo(int nServoId)
Check if the given servo is in the list of registered servos in the recording header.
int m_nSamplePeriod
recording sample period (ms)
#define DYNA_ID_NONE
no servo id
Definition: Dynamixel.h:145
uint_t m_uModelNum
servo model number
virtual int FirstField(int nRecNum)
Get the first field number in the given record.
#define DYNA_ECODE_BAD_VAL
bad value
Definition: Dynamixel.h:85
virtual int CopyRecord(int nRecNumDst, int nRecNumSrc)
Copy source record to destination record.
virtual ~DynaRecord()
Default destructor.
int m_nFieldCnt
number of field tuples
vector< ServoInfo_T > VecServoInfo
Map of record servos ids and model numbers indexed by field number.
void ResetFieldCount()
Reset the field count to zero.
int GetFieldCount() const
Get the current number of field tuples in record.
static const bool NaF(FieldTuple_T &field)
Test if field is &#39;Not a Field&#39;.