49 #include <sys/select.h> 60 #include <gsl/gsl_bspline.h> 61 #include <gsl/gsl_multifit.h> 62 #include <gsl/gsl_rng.h> 63 #include <gsl/gsl_randist.h> 64 #include <gsl/gsl_statistics.h> 66 #include "rnr/rnrconfig.h" 104 int fno = fileno(stdin);
106 uint_t usec = (uint_t)nMSec * 1000;
107 struct timeval timeout;
114 timeout.tv_sec = (time_t)(usec / 1000000);
115 timeout.tv_usec = (time_t)(usec % 1000000);
117 if( (rc = select(fno+1, &fdset, NULL, NULL, &timeout)) > 0 )
122 return rc>0?
true:
false;
137 int fno = fileno(stdin);
139 struct timeval timeout;
146 timeout.tv_sec = (time_t)((
int)fSec);
147 timeout.tv_usec = (time_t)(((fSec - (
double)timeout.tv_sec)) * 1000000.0);
149 if( (rc = select(fno+1, &fdset, NULL, NULL, &timeout)) > 0 )
154 return rc>0?
true:
false;
175 m_sCmdHelpBrief =
"Get the current servo PID values.";
176 m_sCmdHelpArgs =
"<servo_id> [servo_id...]\nchain";
177 m_sCmdHelpDesc =
"Get the current PID Kp, Ki, and Kd parameters for the " 179 "If the keyword 'chain' is specified, then the PID " 180 "parameters for all of the servos in the chain are " 182 " <servo_id> Servo id [0-253].";
201 printf(
"Servo %3d: Kp %9.3lf, Ki %9.3lf, Kd %9.3lf\n",
202 pServo->
GetServoId(), pServo->GetSpeedPid().GetKp(),
203 pServo->GetSpeedPid().GetKi(), pServo->GetSpeedPid().GetKd());
224 m_sCmdHelpBrief =
"Set PID constants for the given servo(s).";
225 m_sCmdHelpArgs =
"<servo_id> <Kp> <Ki> <Kd>\nchain <Kp> <Ki> <Kd>";
226 m_sCmdHelpDesc =
"Set the PID Kp, Ki, and Kd parameters for the " 227 "specified servo(s). " 228 "If the keyword 'chain' is specified, then the PID " 229 "parameters for all of the servos in the chain are " 231 " <servo_id> Servo id [0-253].\n" 232 " <Kp> Proportional constant.\n" 233 " <Ki> Integral constant.\n" 234 " <Kd> Derivative constant.";
260 TRY( ChkArgCnt(shell, argc) );
262 TRY( ChkComm(shell) );
263 TRY( ChkChainNotEmpty(shell) );
265 for(i=0; i<argc; ++i)
270 if( !strcmp(argv[i],
"chain") )
276 TRY( ToInt(shell, argv[i], &nServoId) );
277 TRY( ChkChainHasServo(shell, nServoId) );
282 TRY( ToDouble(shell, argv[i], &fKp) );
285 TRY( ToDouble(shell, argv[i], &fKi) );
288 TRY( ToDouble(shell, argv[i], &fKd) );
303 doExec(shell, pServo, fKp, fKi, fKd);
309 doExec(shell, pServo, fKp, fKi, fKd);
332 const char *sContext)
362 snprintf(buf,
sizeof(buf),
"%d", m_nTabServoId);
363 buf[
sizeof(buf)-1] = 0;
367 if( !strncmp(buf, sText, uTextLen) )
373 if( !strncmp(
"chain", sText, uTextLen) )
401 pServo->GetSpeedPid().SetConstants(fKp, fKi, fKd);
421 m_sCmdName =
"recording";
422 m_sCmdHelpBrief =
"Load recording from a file.";
423 m_sCmdHelpArgs =
"<file>";
424 m_sCmdHelpDesc =
"Load a recording from a file. The current recording in " 425 "memory is overwritten.\n" 426 " <file> Recording file name.";
460 TRY( ChkArgCnt(shell, argc) );
462 if( Init(shell, argv[0]) !=
DYNA_OK )
491 const char *sContext)
522 while( (rc ==
DYNA_OK) && GetLine() )
524 m_sField = GetFirstWord();
527 if( m_sField == NULL )
533 else if( *m_sField ==
'#' )
539 else if( !strcmp(m_sField,
"VERSION") )
545 else if( !strcmp(m_sField,
"DATE") )
547 SetDateField(shell, GetEolPhrase());
551 else if( !strcmp(m_sField,
"NUM_SERVOS") )
553 if( ParseIntField(shell, GetNextWord(), &m_nNumServos) !=
DYNA_OK )
557 else if( (m_nNumServos <= 0) || (m_nNumServos >
DYNA_ID_NUMOF) )
559 shell.
Error(
"Line %dc%d: Field %s: Value %d: Out-of-range.",
560 m_nLineNum, m_nColNum, m_sField, m_nNumServos);
566 else if( !strcmp(m_sField,
"SERVOS") )
568 rc = ParseServoList(shell) !=
DYNA_OK;
572 else if( !strcmp(m_sField,
"SAMPLE_PERIOD") )
574 if( ParseIntField(shell, GetNextWord(), &m_nSamplePeriod) !=
DYNA_OK )
578 else if( m_nSamplePeriod <= 0 )
580 shell.
Error(
"Line %dc%d: Field %s: Value %d: Out-of-range.",
581 m_nLineNum, m_nColNum, m_sField, m_nNumServos);
591 else if( !strcmp(m_sField,
"NUM_RECORDS") )
593 if( ParseIntField(shell, GetNextWord(), &m_nNumRecords) !=
DYNA_OK )
597 else if( (m_nNumRecords <= 0) ||
600 shell.
Error(
"Line %dc%d: Field %s: Value %d: Out-of-range.",
601 m_nLineNum, m_nColNum, m_sField, m_nNumServos);
607 else if( !strcmp(m_sField,
"DATA") )
612 if( m_nNumServos == 0 )
614 shell.
Error(
"Field NUM_SERVOS: Not specified in file header.",
622 "Field SERVOS lists %d servos != Field NUM_SERVOS value of %d.",
627 else if( m_nNumRecords == 0 )
629 shell.
Error(
"Field NUM_RECORDS: Not specified in file header.");
633 else if( m_nSamplePeriod == 0 )
635 shell.
Error(
"Field SAMPLE_PERIOD: Not specified in file header.");
641 rc = ParseRecordedData(shell);
649 shell.
Warning(
"Line %d: Field %s: Unknown field - ignoring.",
650 m_nLineNum, m_sField);
659 if( m_sDate == NULL )
661 shell.
Warning(
"Field DATE: Not specified in file header.");
662 SetDateField(shell,
"Unknown File Date");
668 shell.
Response(
"Loaded recording from file %s\n", m_sFileName);
669 shell.
Response(
" Recording date: %s.\n",
671 shell.
Response(
" Number of servos: %d\n",
673 shell.
Response(
" Number of records: %d\n",
675 shell.
Response(
" Sample period: %dms.\n",
694 while( (rc ==
DYNA_OK) && ((sWord = GetNextWord()) != NULL) )
697 if( (rc = ParseIntField(shell, sWord, &nServoId)) ==
DYNA_OK )
699 rc = ParseIntField(shell, GetNextWord(), (
int *)&uModelNum);
708 shell.
Error(
"Line %dc%d: Field %s: Value %d': Out-of-range.",
709 m_nLineNum, m_nColNum, m_sField, nServoId);
719 shell.
Error(
"Line %dc%d: Field %s: Servo %d: Duplicate.",
720 m_nLineNum, m_nColNum, m_sField, nServoId);
747 if( LineHasNoData() )
752 m_sField = (
char *)
"DATA";
759 "Line %d: Field DATA: Exceeded maximum number of %d records.",
764 else if( nRecNum >= m_nNumRecords )
767 "Line %d: Field DATA: Exceeded NUM_RECORDS value of %d records.",
768 m_nLineNum, m_sField, m_nNumRecords);
772 for(sWord = GetFirstWord(), nFldNum=0;
774 sWord = GetNextWord(), ++nFldNum)
776 if( nFldNum >= m_nNumServos )
779 "Line %dc%d: Field %s: Exceeded NUM_SERVOS value of %d servos.",
780 m_nLineNum, m_sField, m_nColNum, m_nNumServos);
785 if( (rc = ParseIntField(shell, sWord, &nPos)) !=
DYNA_OK )
790 if( (rc = ParseIntField(shell, GetNextWord(), &nSpeed)) !=
DYNA_OK )
797 shell.
Error(
"Line %dc%d: Field %s: No registered servo at pos %d.",
798 m_nLineNum, m_nColNum, m_sField, nFldNum);
802 rc = m_pRecording->
AddFieldTuple(nRecNum, nServoId, nPos, nSpeed);
806 shell.
Error(
"Line %dc%d: Field %s: Cannot add any more fields.",
807 m_nLineNum, m_nColNum, m_sField);
812 if( nFldNum < m_nNumServos )
815 "Line %d: Field %s: Only %d (pos,speed) 2-tuples found, expected %d.",
816 m_nLineNum, m_sField, nFldNum, m_nNumServos);
821 if( nRecNum+1 < m_nNumRecords )
823 shell.
Error(
"Line %d: Field %s: Only %d records found, expected %d.",
824 m_nLineNum, m_sField, nRecNum+1, m_nNumRecords);
841 if( m_sDate != NULL )
846 if( (sDate != NULL) && (*sDate != 0) )
849 m_pRecording->
SetDate(m_sDate);
868 shell.
Error(
"Line %dc%d: Field %s: No field value found.",
869 m_nLineNum, m_nColNum, m_sField);
872 else if( sscanf(sWord,
"%i", pFieldVal) != 1 )
874 shell.
Error(
"Line %dc%d: Field %s: Value %s: Not an integer.",
875 m_nLineNum, m_nColNum, m_sField, sWord);
898 return GetNextWord();
914 m_nColNum = (int)(m_sCursor - m_buf) + 1;
916 while( *m_sCursor && isspace((
int)*m_sCursor) )
922 if( *m_sCursor == 0 )
929 while( *m_sCursor && !isspace((
int)*m_sCursor) )
934 if( *m_sCursor != 0 )
959 m_nColNum = (int)(m_sCursor - m_buf) + 1;
961 while( *m_sCursor && isspace((
int)*m_sCursor) )
967 if( *m_sCursor == 0 )
974 while( *m_sCursor && (*m_sCursor !=
'\n') )
979 if( *m_sCursor != 0 )
986 while( (s > sPhrase) && isspace((
int)*s) )
1007 for(s=m_buf; *s; ++s)
1013 else if( !isspace((
int)*s) )
1028 if( getline(&m_buf, &m_sizeBuf, m_fp) != -1 )
1050 if( (m_fp = fopen(sFileName,
"r")) == NULL )
1052 shell.
Error(
"%s: cannot open.", sFileName);
1056 m_sFileName =
newstr(sFileName);
1060 m_buf =
new char[m_sizeBuf];
1065 m_nSamplePeriod = 0;
1084 if( m_sFileName != NULL )
1086 delete[] m_sFileName;
1096 if( m_sDate != NULL )
1103 if( m_pRecording != NULL )
1105 delete m_pRecording;
1106 m_pRecording = NULL;
1115 m_nSamplePeriod = 0;
1135 m_sCmdName =
"recording";
1136 m_sCmdHelpBrief =
"Save the current recording to a file.";
1137 m_sCmdHelpArgs =
"<file>";
1138 m_sCmdHelpDesc =
"Save the current recording to an ASCII file." 1139 "The current recording is the last 'train' or 'load' " 1140 "command executed during this shell's session.\n" 1141 " <file> Recording file name.";
1160 TRY( ChkArgCnt(shell, argc) );
1165 shell.
Error(
"No recording to save.");
1169 if( (fp = fopen(argv[0],
"w")) == NULL )
1171 shell.
Error(
"%s: cannot open.", argv[1]);
1179 shell.
Response(
"Saved recording to file %s\n", argv[0]);
1201 const char *sContext)
1222 fprintf(fp,
"# .DYD v1.0 - Dynamixel Data file format\n");
1223 fprintf(fp,
"VERSION 1.0\n");
1224 fprintf(fp,
"DATE %s\n", pRecording->
GetDate());
1226 fprintf(fp,
"SERVOS");
1230 nFldNum = pRecording->
NextField(0, nFldNum))
1233 fprintf(fp,
" %d 0x%04x",
1241 fprintf(fp,
"DATA ascii\n");
1247 for(nFldNum = pRecording->
FirstField(nRecNum);
1249 nFldNum = pRecording->
NextField(nRecNum, nFldNum))
1251 tupRec = pRecording->
GetField(nRecNum, nFldNum);
1275 m_sCmdName =
"train";
1276 m_sCmdHelpBrief =
"Record a training session.";
1277 m_sCmdHelpArgs =
"<start_delay> <sample_period>";
1278 m_sCmdHelpDesc =
"Record a dynamixel chain training session. " 1279 "The current recording in memory is overwritten.\n" 1280 " <start_delay> Recording start delay (sec).\n" 1281 " <sample_period> Recording sample period (msec).";
1307 TRY( ChkArgCnt(shell, argc) );
1308 TRY( ToInt(shell, argv[0], &nStartDelay) );
1309 TRY( ToInt(shell, argv[1], &nSamplePeriod) );
1314 TRY( ChkComm(shell) );
1315 TRY( ChkChainNotEmpty(shell) );
1331 RecordTraining(shell, nStartDelay, nSamplePeriod);
1353 const char *sContext)
1356 static const char *keywordsLoop[] = {
"close",
"open"};
1378 while( m_nTabIndex < arraysize(keywordsLoop) )
1380 s = keywordsLoop[m_nTabIndex++];
1382 if( !strncmp(s, sText, uTextLen) )
1415 if( nSamplePeriod < 1 )
1420 printf(
"Starting to record in %u seconds.\n", nStartDelay);
1421 printf(
" Recording sample rate: %dms.\n", nSamplePeriod);
1422 printf(
"Press <CR> to stop recording.\n\n");
1426 for(iter=0; iter<nStartDelay; ++iter)
1428 printf(
"%d ", nStartDelay-iter);
1440 printf(
"record[%d]: ", nRecNum);
1452 rc = pServo->ReadCurPos(&nCurPos);
1456 shell.
Error(rc,
"Servo %d: ReadCurPos.", nServoId);
1463 rc = pServo->ReadCurSpeed(&nCurSpeed);
1467 shell.
Error(rc,
"Servo %d: ReadCurSpeed.", nServoId);
1472 pRecording->
AddFieldTuple(nRecNum, nServoId, nCurPos, nCurSpeed);
1474 printf(
"%d %d %d ", nServoId, nCurPos, nCurSpeed);
1504 m_sCmdName =
"play";
1505 m_sCmdHelpBrief =
"Playback the current dynamixel recording.";
1506 m_sCmdHelpArgs =
"<sub_sample> [<speed> [<plot_file>]]";
1507 m_sCmdHelpDesc =
"Playback the current recording. " 1508 "The current recording is the last 'train' or 'load' " 1509 "command executed during this shell's session.\n" 1510 " <sub_sample> Number of control sub-sample points.\n" 1511 " <speed> Playback at % of recorded speed.\n" 1513 " <loop> Do [not] loop recording.\n" 1514 " One of: loop true noloop false.\n" 1515 " Default: noloop.";
1516 " <plot_file> Output plot file in gnuplot format.\n" 1517 " Default: no file";
1519 m_nNumSubSamplePts = 0;
1541 char *sPlotFileName;
1549 TRY( ChkArgCnt(shell, argc) );
1554 shell.
Error(
"No recording to play.");
1559 m_fSpeedPct = 100.0;
1560 sPlotFileName = NULL;
1567 for(i=0; i<argc; ++i)
1573 TRY( ToInt(shell, argv[i], &m_nNumSubSamplePts) );
1575 if( m_nNumSubSamplePts < 1 )
1577 m_nNumSubSamplePts = 1;
1582 TRY( ToDouble(shell, argv[i], &m_fSpeedPct) );
1583 if( m_fSpeedPct < 0.0 )
1585 m_fSpeedPct = 100.0;
1590 sPlotFileName = argv[i];
1593 shell.
Error(
"Huh?");
1606 shell.
Error(
"%d servos in recording != %d master servos in chain.",
1617 if( !pRecording->
HasServo(nServoId) )
1619 shell.
Error(
"Servo %d: Not in recording.");
1627 shell.
Error(
"Servo %d: Recording model number 0x%04x != 0x%04x.",
1637 if( sPlotFileName != NULL )
1639 if( (m_fpPlot = fopen(sPlotFileName,
"w")) == NULL )
1641 shell.
Error(
"%s: cannot open.", sPlotFileName);
1675 const char *sContext)
1693 if( (m_nTabIndex++ == 0) && !strncmp(
"100", sText, uTextLen) )
1700 else if( nArgNum == 2 )
1709 typedef vector< vector<uint_t> > VecCurves;
1735 shell.
Response(
"\nPlaying back recording made on %s.\n",
1737 shell.
Response(
" Number of records: %d\n",
1739 shell.
Response(
" Playback sample period: %.1lfms.\n", m_fSamplePeriod);
1740 shell.
Response(
" Sub-sample period: %.3lfms.\n", dt);
1741 shell.
Response(
"Press <CR> to abort recording.\n\n");
1757 rc = SetRecordGoals(shell, nRecNum);
1767 for(t=0.0; t<m_fSamplePeriod; t+=dt)
1770 rc = ControlToGoals(shell, nRecNum, dt);
1809 printf(
"\n goalpos_%d: ", nRecNum);
1825 rc = PidSetPoint(shell, nServoId, tupRec.
m_nPos, tupRec.
m_nSpeed);
1832 printf(
"%d %d ", nServoId, tupRec.
m_nPos);
1873 printf(
" speed_%d: ", nRecNum);
1887 rc = pServo->ReadCurPos(&nCurPos);
1891 printf(
"Error: Servo %d: ReadCurPos: %s\n", nServoId,
DynaStrError(rc));
1896 rc = pServo->ReadCurSpeed(&nCurSpeed);
1900 printf(
"Error: Servo %d: ReadCurSpeed: %s\n", nServoId,
1906 nGoalSpeed = pServo->GetSpeedPid().Control(nCurSpeed, dt);
1909 tupSpeed[nFldNum].
m_nSpeed = nGoalSpeed;
1911 if( m_fpPlot != NULL )
1913 PlotWriteData(shell, nRecNum, dt, nServoId, nCurPos);
1916 printf(
"%d %d ", nServoId, nGoalSpeed);
1928 printf(
"Error: Servo %d: SyncWriteGoalSpeed: %s\n",
1939 int nNumPidCtlPts = 1;
1943 100.0 / m_fSpeedPct;
1946 if( m_fSamplePeriod < 0.001 )
1948 m_fSamplePeriod = 0.001;
1952 m_fSubSamplePeriod = m_fSamplePeriod / (double)m_nNumSubSamplePts;
1954 if( m_fSubSamplePeriod < 0.001 )
1956 m_fSubSamplePeriod = 0.001;
1960 m_dt = m_fSubSamplePeriod / (double)nNumPidCtlPts;
1968 SmoothRecordingCurves(shell);
1977 void SmoothRecordingCurves(
DynaShell &shell)
1981 void BSplineCurve(
DynaShell &shell,
int nFldNum)
1995 fTLen = (double)uNumRecs * m_fSamplePeriod - m_fSamplePeriod;
2001 uNumBreaks = uNumCoeffs + 2 + uOrder;
2004 gsl_bspline_workspace *pWsBspline = gsl_bspline_alloc(uOrder, uNumBreaks);
2007 gsl_vector *B = gsl_vector_alloc(uNumCoeffs);
2008 gsl_vector *y = gsl_vector_alloc(uNumRecs);
2009 gsl_matrix *X = gsl_matrix_alloc(uNumRecs, uNumCoeffs);
2010 gsl_vector *c = gsl_vector_alloc(uNumCoeffs);
2011 gsl_vector *w = gsl_vector_alloc(uNumRecs);
2012 gsl_matrix *Cov = gsl_matrix_alloc(uNumCoeffs, uNumCoeffs);
2015 gsl_multifit_linear_workspace *pWsMFitLinear =
2016 gsl_multifit_linear_alloc(uNumRecs, uNumCoeffs);
2019 gsl_bspline_knots_uniform(0.0, fTLen, pWsBspline);
2022 for(i=0, xi=0.0; i<uNumRecs; ++i, xi+=m_fSamplePeriod)
2024 gsl_vector_set(y, i, (*pRecording)[i][nFldNum].m_nPos);
2027 gsl_bspline_eval(xi, B, pWsBspline);
2030 for(j=0; j<uNumCoeffs; ++j)
2032 double Bj = gsl_vector_get(B, j);
2033 gsl_matrix_set(X, i, j, Bj);
2038 gsl_multifit_wlinear(X, w, y, c, Cov, &chisq, pWsMFitLinear);
2042 for(xi=0.0; xi<fTLen; xi+=m_fSubSamplePeriod)
2044 gsl_bspline_eval(xi, B, pWsBspline);
2045 gsl_multifit_linear_est(B, c, Cov, &yi, &yerr);
2049 gsl_bspline_free(pWsBspline);
2055 gsl_matrix_free(Cov);
2056 gsl_multifit_linear_free(pWsMFitLinear);
2075 pServo->GetSpeedPid().InitControl();
2104 rc = pServo->ReadCurPos(&nCurPos);
2108 printf(
"Error: Servo %d: ReadCurPos: %s\n", nServoId,
DynaStrError(rc));
2113 pServo->GetSpeedPid().SpecifySetPoint(nOdPos);
2125 if( m_fpPlot != NULL )
2131 m_vecCurves.clear();
2156 if( m_fpPlot != NULL )
2160 fprintf(m_fpPlot,
"#\n");
2161 fprintf(m_fpPlot,
"# Dynamixel Play Back Plot Data\n");
2162 fprintf(m_fpPlot,
"# Recorded: %s\n",
2164 fprintf(m_fpPlot,
"# Number of records: %d\n",
2166 fprintf(m_fpPlot,
"# Recording sample period: %dms\n",
2168 fprintf(m_fpPlot,
"# Playback sample period: %.3f\n",
2170 fprintf(m_fpPlot,
"# Playback delta time step: %.4lfs\n", m_dt);
2171 fprintf(m_fpPlot,
"#\n");
2172 fprintf(m_fpPlot,
"#Fields:\n");
2173 fprintf(m_fpPlot,
"# time servo goal_pos goal_speed cur_pos " 2175 fprintf(m_fpPlot,
"#\n");
2196 if( m_fpPlot != NULL )
2199 fprintf(m_fpPlot,
"%.4f %d %u %d %u\n",
2202 (uint_t)pServo->GetSpeedPid().GetSP(),
2204 (uint_t)pServo->GetSpeedPid().GetOutput());
2227 nMoving = nNumServos;
2229 while( nMoving > 0 )
2239 if( ((rc = pServo->ReadIsMoving(&bIsMoving)) ==
DYNA_OK) && bIsMoving )
RoadNarrows Dynamixel Bus Communications Abstract Base Class Interface.
bool GetLine()
Read the next line of data.
int m_nSamplePeriod
SAMPLE_PERIOD value.
virtual int GetNumOfRecords()
Get the number of records in the recording.
char * newstr(const char *s)
Allocate new duplicated string.
static bool_t waitkey(int nMSec)
Block, waiting for either timeout or user keyboard press.
int ParseRecordedData(DynaShell &shell)
Parse recorded data and save in working recording.
Load recording from file.
Synchronous Write Speed Tuple Structure.
double m_fTAccum
accumulated time
void WaitStop(DynaShell &shell)
Wait until all servos in chain have stopped moving utility function.
virtual int SyncWriteGoalSpeed(DynaSpeedTuple_T tuplesSpeed[], uint_t uCount)
Synchronous write new goal speed for servos.
virtual void Exec(DynaShell &shell, int argc, char *argv[])
Execute save recording.
#define DYNA_OK
not an error, success
int m_nNumServos
NUM_SERVOS value.
virtual int SyncMoveTo(DynaPosTuple_T tuplesPos[], uint_t uCount)
Synchronous move servos to new goal positions in tuple list.
char * GetNextWord()
Get the next word in line buffer.
virtual int Freeze()
Freeze all servos at current position.
Record Field Tuple Structure Type.
int m_nTabIndex
tab completion: keyword index
DynaShellCmdSaveRecording()
Default constructor.
virtual int AddRecord()
Add a new empty record to the recording.
virtual ~DynaShellCmdTrain()
Default destructor.
char * GetFirstWord()
Get the first word in line buffer.
Get the PID values for the given servos.
Dynamixel shell utilities.
virtual void Exec(DynaShell &shell, int argc, char *argv[])
Execute recording.
void RecordingReplace(DynaRecording *pNewRecording)
Replace recording.
The Dynamixel Speed PID Class.
virtual int AddFieldTuple(int nRecNum, int nServoId, int nPos, int nSpeed)
Add new recording field tuple.
void PublishShellTrainCommands(DynaShell &shell)
Publish shell servo commands to shell.
void Save(DynaShell &shell, FILE *fp)
Save recording.
DynaRecording * m_pRecording
working and new recording
virtual uint_t GetNumberOfMastersInChain()
Get the number of servos currently in chain.
RoadNarrows Dynamixel Servo Chain Container Base Class Interface.
double m_dt
playback delta time (seconds)
void SecureArm(DynaShell &shell)
Secure arm in safe postition if posible.
double m_fSpeedPct
playback speed as a % of recorded speed
Record dynamixel chain movements.
int PidSetPoint(DynaShell &shell, int nServoId, int nGoalPos, int nGoalSpeed)
Specify (new) PID goal position setpoint.
static const int FIRST
first state
virtual ~DynaShellCmdPlay()
Default destructor.
size_t m_sizeBuf
size of input buffer
virtual const int GetServoId(int nFldNum)
Get the servo id associated with the given field number.
#define DYNA_ID_MIN
minimum servo id
#define DYNA_DIR_CW
clockwise direction
static char * dupstr(const string &str)
Duplicate string.
Dynamixel shell command abstract base class.
virtual int SetSamplePeriod(int nSamplePeriod)
Set the sample period of the recording.
char * m_sFileName
file name
#define DYNA_ECODE_PARSE
Shell parse error.
virtual int IterStartMaster(int *pIter)
Start iteration master servos over of entire servo chain.
#define DYNA_ID_NUMOF
number of unique servo id's
Miscellaneous collection of useful utilities.
virtual int IterNextMaster(int *pIter)
Next iteration of master servos over of entire servo chain.
virtual uint_t GetNumberInChain() const
Get the number of servos currently in chain.
int Init(DynaShell &shell, char *sFileName)
Initialize data prior to file loading.
DynaRecording * m_pRecording
dynamixel recording
Dynamixel Servo Abstract Base Class.
virtual uint_t GetServoModelNumber(int nServoId)
Get the registered servo model number.
void Cleanup(DynaShell &shell)
Clean up any allocated playback resources.
const char * DynaStrError(int ecode)
Get the error string describing the Dynamixel error code.
void Cleanup(DynaShell &shell)
Clean up data after to file loading parsing.
static const int END
past-the-end mark
char * m_sDate
DATE value.
int m_nTabServoId
tab completion: current servo id
DynaShellCmdPlay()
Default constructor.
#define DYNA_ID_MAX
maximum servo id
virtual int GetSamplePeriod() const
Get the sample period of the recording.
virtual void SetDate(const char *sDate)
static int wc(const string &str)
Count the words in the string.
void Response(const char *sFmt,...)
Print formatted success response.
int m_nLineNum
line number
char * m_sField
current field being parsed
int m_nTabIndex
tab completion: keyword index
bool LineHasNoData()
Test if line is all white space or a comment.
char * m_sCursor
current line parse cursor
virtual const char * GetDate() const
Get the recording data.
FILE * m_fp
open file pointer
#define DYNA_DIR_CCW
counterclockwise direction
void Warning(const char *sFmt,...)
Issue warning.
The Dynamixel Recording Class.
DynaShellCmdLoadRecording()
Default constructor.
virtual void doExec(DynaShell &shell, DynaServo *pServo, double fKp, double fKi, double fKd)
Get servo PID parameters.
int ParseServoList(DynaShell &shell)
Parse servo list and save in working recording.
virtual int IterStart(int *pIter)
Start iteration over of entire servo chain.
#define DYNA_ECODE_BADF
no comm object or not open
virtual DynaServo * GetServo(int nServoId)
char * GetEolPhrase()
Get the end-of-line phrase.
int ParseIntField(DynaShell &shell, const char *sWord, int *pFieldVal)
Parse integer field.
virtual int FirstRecord()
Get the first record number in the recording.
void PlotWriteData(DynaShell &shell, int nRecNum, double dt, int nServoId, int nCurPos)
Write plot data to plot file.
double m_fSamplePeriod
playback sample period (seconds)
VecCurves m_vecCurves
vector of fitted smooth curves
virtual ~DynaShellCmdLoadRecording()
Default destructor.
virtual void doExec(DynaShell &shell, DynaServo *pServo)
Get servo PID parameters.
int m_nColNum
column number in line
void PlotInit(DynaShell &shell)
Initialize plot data output.
int m_nPlotLineCnt
plotted data line count
virtual void Exec(DynaShell &shell, int argc, char *argv[])
Execute load recording.
RoadNarrows Dynamixel Archetype Servo Abstract Base Class.
Dynamixel chain input command abstract base class.
virtual void Exec(DynaShell &shell, int argc, char *argv[])
Execute playback of recording.
Record dynamixel chain movements.
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.
DynaShellCmdTrain()
Default constructor.
#define TRY(boolexpr,...)
Try boolean expression.
Get the PID values for the given servos.
void Exec(DynaShell &shell, int argc, char *argv[])
Execute 'read-like' command on servos.
void PublishCommand(const char *sParent, DynaShellCmd *pNewCmd)
Publish new command to shell.
RoadNarrows Dynamixel Top-Level Package Header File.
virtual uint_t GetModelNumber() const
Get servo model number.
virtual const DynaRecord::FieldTuple_T & GetField(const int nRecNum, const int nFldNum) const
Get the given recorded field tuple.
The dynashell Command Class Interface.
virtual uint_t GetServoId() const
Get servo id.
virtual bool HasServo(int nServoId)
Check if the given servo is in the list of registered servos in the recording header.
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
void RecordTraining(DynaShell &shell, int nStartDelay, int nSamplePeriod)
Record the movements of a dynamixel chain.
#define DYNA_ID_NONE
no servo id
virtual int FirstField(int nRecNum)
Get the first field number in the given record.
virtual int RegisterServoInfo(int nServoId, uint_t uModelNum)
Register servo information in recording header.
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
double m_fSubSamplePeriod
control sub-sample period (seconds)
virtual int IterNext(int *pIter)
Next iteration over of entire servo chain.
DynaChain * m_pDynaChain
dynamixel chain
void Error(int rc, const char *sFmt,...)
Raise error on dynamixel error code.
int ControlToGoals(DynaShell &shell, int nRecNum, double dt)
Control the servos speed to reach the goal positions, hopefully at the end of the sampled period and ...
int m_nNumRecords
NUM_RECORDS value.
static char * FileCompletionGenerator(const char *sText, int nState)
File name tab completion generator.
void SetDateField(DynaShell &shell, const char *sDate)
Set date value.
Position Tuple Structure.
FILE * m_fpPlot
plot data file pointer
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
int m_nTabIter
tab completion: servo id iterator
void PidInit(DynaShell &shell)
Initialize servo PIDs.
void Load(DynaShell &shell)
Load recording.
virtual char * TabCompletion(DynaShell &shell, const char *sText, size_t uTextLen, int nState, const char *sContext)
Command tab completion generator.
void Play(DynaShell &shell)
Play back the previously recorded Dynamixel chain motion sequence.
void RecordingInit(int nSamplePeriod, const char *sDate=NULL)
(Re)Initialize recording.
int SetRecordGoals(DynaShell &shell, int nRecNum)
Set record goals.
The simple dynashell declarations.
int m_nNumSubSamplePts
sub-sample playback control period (msec)
static const int MaxRecords
maximum number of records
virtual ~DynaShellCmdSaveRecording()
Default destructor.