There are many tutorials on how to upload the code to an Arduino (Arduino IDE, YouTube, with Arduino kits, etc.) so I will not explain that. However, I will explain some of the highlights of the code. The code is far from perfect and is quite long, so I will not go through all of it. Much of it is based on the PWM/Servo driver example sketch from Adafruit (link), and the IR remote control tutorial from the Dronebot Workshop (link).

The code relies on three libraries as background programming. These are:

  • IRremote.h
  • Wire.h
  • Adafruit_PWMServoDriver.h

The PWMServoDriver can be downloaded from the Adafruit link above. As the name implies, it controls the servo driver which controls the servo motors. The Wire library is a standard library that comes with the Arduino IDE software. The IRremote library can be found in the Library Manager of the Arduino IDE.

One of the variables in the code is “togglePosture” declared near the top of the code. This tracks of the mode the robot: walking, skimming, or gripping. When the robot is about to move, the Nano will check the value of togglePosture to determine what the current mode is. If necessary, it will run the appropriate function to change posture and then update the togglePosture variable to the new mode (skimming=0, or standing=1, or grip/skimming=2, or none of these=3). This allows the user to, for example, activate the “skimForward” function when the robot is standing. Since the robot is not in the skimming mode, the togglePosture does not equal 0. So, the robot will call the “skimPosture” function which will cause the robot to drop down to the casters, and then the value of the togglePosture variable will be updated to equal 0, before the robot skims forward.

Because of the orientation of the motors some are turning clockwise to flex up or go forward, and others turn counter clockwise for the same motion. So, for example, for tib1 and tib3, a value of 100 is fully flexed. However, for tib2 and tib4, a value of 600 is fully flexed.

For walking, the forward and back motions were meant to be smooth coordinated movements with more than one joint moving at a time. It requires a series of motions with the robot shifting its weight to keep the centre of gravity under three legs while the fourth leg is lifted and slowly moved. In order to do this, the forward and back walking functions are split up into several “for” loops in the code (similar to the programming of the “Sweep” example code for the Servo library if you have used it). For example, one of the first motions for walking forward is to shift the weight towards leg4. This has the following code:

for (tib2 = 400; tib2 if (fem2 if (hip3 if (tib4 > 300) tib4 = tib4 — 1;
if (hip1 > 350) hip1 = hip1 — 1;}
pwm.setPWM(0, 0, hip1);
pwm.setPWM(5, 0, fem2);
pwm.setPWM(8, 0, hip3);
pwm.setPWM(14, 0, tib4);
pwm.setPWM(6, 0, tib2);
delay(delayTime);
}

In this section of code, the first line is: for (tib2 = 400; tib2

To explain this line: the variable, tib2, corresponds to the position of the tibia motor on the second leg and starts at 400. This line also specifies that as long as the value of tib2 is below 500, the Nano will loop through the eleven lines of code over and over, but each time it will increment the tib2 value by +1. The next few lines of code are several “if’ statements, where fem1 and hip3 will also increase in position by a value of one each time through the loop as tib2 increases, and tib4 and hip1 will decrease by 1 each time.

The lines with “pwm.setPWM” are the functions that direct the PWM servo driver to advance the motors the new position indicated by the “for” and “if” statements. Because each motor position only changes by 1, the movement is only a small movement. By incrementing these variables one value at a time, the legs will move slowly and smoothly. Furthermore, because tib2, fem1, hip3, tib4 and hip1 are all affected, these five motors will move simultaneously, just like the robot was coordinating several joints at once.

The line, delay(delayTime), causes the Nano to pause before each loop of this code. The variable “delayTime” was defined at the very beginning of the whole code, like the togglePosture variable. However, this variable represents the duration of the pause in milliseconds. It therefore controls how fast the Nano goes through this section of code over-and-over again. The pause must be short enough that it does not appear that the motor stops between each incremented movement, otherwise it would move like the seconds hand on an analog watch. By using this pause between each cycle through the section of code the walking is purposefully slower and smoother.

When tib2 reaches 500, the “for” loop will end and the Nano will go to the next section of code (not shown here), which will orchestrate a different set of movements with different motors.

In contrast to the walking, the code for the skim and grip motions are meant to be much quicker, so the movements are not incremented in “for” loops like the walking. For example, near the beginning of the “skimForward” function is this excerpt of the code:

fem2 = 330, fem3 = 390; // femurs up
pwm.setPWM(5, 0, fem2);
pwm.setPWM(9, 0, fem3);
if (togglePosture == 0) {
fem1 = 375; pwm.setPWM(1, 0, fem1);
fem4 = 300; pwm.setPWM(13, 0, fem4);
}
delay(10);

In this code, the values of fem2 and fem3 are both changed so that those two legs will lift up. The two pwm.setPWM lines execute those two movements to the motors, no incrementing the movement, just one command so it will be sudden and quick. The “if” statement in this code is to check if the robot is in the “skim” mode in which case the next two lines (between the curly brackets {}) are executed which will also bring the front legs, legs 1 and 4, up as well. If the togglePosture variable was NOT zero, then the robot would be in the gripper mode, and so the two front legs are not used to move and so legs 1 and 4 will not be moved here. The delay(10) function delays the robot for 10 milliseconds to give the motors enough time to reach their new positions.

At the end of the full code, the loop() section is very short and quick, and is as follows:

void loop()
{
if (irrecv.decode(&results)) {
if (results.value != 0xFFFFFF) { //0xFFFFFF is the «repeat» command from the remote, so the robot will ignore it
digitalWrite(LED_PIN, LOW); // turn off standby LED
val = results.value;
irrecv.resume();
switch (val) { // Which functions to call when button is pressed, buttons were defined before the setup
case P: Pause (); break;
case Fr: forward(); break;
case B: back(); break;
case L: left(); break;
case R: right(); break;
case St: stand(); break;
case Lu: legsUp(); break;
case Ld: legsDown(); break;
case lt: legsTogether(); break;
case Eq: gripPosture(); break;
case La: legsApart(); break;
case Sf: skimForward(); break;
case Sb: skimBack(); break;
case Sr: skimRight(); break;
case Sl: skimLeft(); break;
case S: skimPosture(); break;
default: break;
}
}
}
digitalWrite(LED_PIN,HIGH); // turn on the standby LED just in case
}

The first line is: if (irrecv.decode(&results)) {

This line will call on the Nano to decode the IR signal from the remote control if one was received by the IR sensor.

In the line, “val=results.value”, the value of IR signal is recorded in the variable called “val”. This variable is then used in the switch function which compares “val” to the different cases, each of which corresponds to one of the movement functions. The Nano will run that movement function, then return in the code to the beginning of the loop section to decode the next IR signal.

You can download the current version of the code here:

Leave a Reply