Problem:
There is erratic behavior from the following sequence using the serial monitor:
1. Use the skill token, 'k' to give a gait skill command, say walk, " kwk".
o Nybble executes the gait skill command properly.
2. Use a non-skill token, say 'd'.
o Nybble processes the token properly.
3. Use the skill token, 'k' to give the SAME gait skill command as above (again, "kwk").
o Nybble now executes the SAME gait skill command incorrectly giving erratic behavior.
Video:
Nybble in the new training safety harness (link). Kitten goes from 'd' to kbalance then follows above sequence [kwk, d, kwk] via the serial monitor to show the erratic behavior. Final token of 'd' used to calm Nybble down!
Note: The standard unmodified Nybble.ino was used.
Diagnosis:
In the loop() function of Nybble.ino, there is a "motion block" section of code that is responsible for looping a gait skill to provide continuous motion. All token 'k' gait skill commands use this "motion block" but other token's do not. In that motion block is this code:
int dutyIdx = timer * WALKING_DOF + jointIdx - firstMotionJoint;
calibratedPWM(jointIdx, motion.dutyAngles[dutyIdx] ...
This code uses the "timer" variable to step through the frames in the gait skill ("timer" = 0 to motion.period) and access the correct angles for each joint index. All is well until the above problem sequence is used. The first step in the problem sequence starts the gait skill and the second step interrupts the gait skill, leaving "timer" at a some value (last used) from 0 to motion.period. The third step in the sequence attempts to do the same gait skill again but the code does not either reset "timer" back to zero (restart) or synchronize the traverse of the gait skill frames with the last value of "timer" (resume). The result is erratic behavior as the frame angles are matched to the wrong joint indices because "timer" is now out of sync.
Solution:
One easy solution is a quick code modification to do an explicit restart (reset "timer" to zero). Line 643 of Nybble.ino has the following code which controls access to resetting "timer":
if (strcmp(newCmd, "") && strcmp(newCmd, lastCmd) ) {
During step 3 of the problem sequence, the first part of this line, "strcmp(newCmd, "")" evaluates to true because newCmd has the gait skill name (e.g. "wk") so that's good. However, the second part, "strcmp(newCmd, lastCmd)" evaluates to false since newCmd and lastCmd have the same gait skill name (e.g. "wk") and timer can't be reset.
So, changing line 643 to the following allows the timer to be reset:
if (strcmp(newCmd, "") ) {
Result is a happy kitten! 😸
I had noticed a similar problem when I got Nybble back in August. Too bad I hadn't learned to check these posts. It took a few days to come up with a very similar fix...
I noticed some abnormal behaviors previously, that the cat occasionally ignoressome repetitive skill commands unless a new skill is assigned. Maybe your solution is the fix. I'll study it after I return from the business trip. Thank you!