Lesson 32 – Otto DIY Biped Robot Dances the Smooth Criminal Dance Routine
What is OTTO DIY – Otto is completely open source, Arduino compatible, 3D printable robot which you can put together yourself. This is robotics and opensource at it’s best. The robot was designed by Camilloa Parra as a social impact mission to create an inclusive environment for all kids. Learn more about OTTO DIY and grab a kit at www.ottodiy.com.
Software Required : You will need either Otto Blockly or the Arduino IDE to work on this tutorial. Head over to the following page to learn how to get Otto Blockly or the Arduino IDE installed on your machine – https://learning.kidzcancode.com/lesson/lesson-03-programming-your-otto-robot/ . Once you have the tools installed, launch the relevant application i.e. Otto Blockly or the Arduino IDE and get started using the code shown below.
Uploading code to the Otto DIY Robot : To upload the code to the Arduino Nano (brain of your Otto DIY Biped Robot) you will need to make sure you have the Otto DIY robot connected to your laptop/desktop using the correct cable. Then select the right COM (Communication Port) and type of Arduino board using the drop down menus provided at the top of the screen. Once that’s sorted hit the “tick mark” icon to validate your code and make sure you do not see any errors pop-up. Finally hit the “right arrow” icon to have the code uploaded to the Arduino Nano housed within the Otto DIY robot.
Tutorial : As part of this tutorial you will write code to make your Otto DIY Biped Robot perform the Smooth Criminal Dance routine.
See Otto Blockly code example below –

See Arduino code provided below.
#include <Otto.h> //Requires you to have the Otto libraries installed within the Arduino IDE
Otto Otto;
#include <Servo.h>
#include <Oscillator.h>
#include <EEPROM.h>
#include <PlayRtttl.hpp> // Requires you to have the PlayRtttl Arduino library installed
#define N_SERVOS 4
void goingUp(int tempo);
void drunk (int tempo);
void noGravity(int tempo);
void kickLeft(int tempo);
void kickRight(int tempo);
void run(int steps, int T=500);
void walk(int steps, int T=1000);
void backyard(int steps, int T=3000);
void backyardSlow(int steps, int T=5000);
void turnLeft(int steps, int T=3000);
void turnRight(int steps, int T=3000);
void moonWalkLeft(int steps, int T=1000);
void moonWalkRight(int steps, int T=1000);
void crusaito(int steps, int T=1000);
void swing(int steps, int T=1000);
void upDown(int steps, int T=1000);
void flapping(int steps, int T=1000);
int t=495; // TEMPO: 121 BPM
double pause=0;
#define LeftLeg 2 // left leg pin, servo[0]
#define RightLeg 3 // right leg pin, servo[1]
#define LeftFoot 4 // left foot pin, servo[2]
#define RightFoot 5 // right foot pin, servo[3]
#define Buzzer 13 //buzzer pin
#define N_SERVOS 4
#define PIN_YL 2 // left leg, servo[0]
#define PIN_YR 3 // right leg, servo[1]
#define PIN_RL 4 // left foot, servo[2]
#define PIN_RR 5 // right foot, servo[3]
#define INTERVALTIME 10.0
Oscillator servo[N_SERVOS];
void setup() {
Otto.init(LeftLeg, RightLeg, LeftFoot, RightFoot, true, Buzzer);
Otto.home();
pinMode(8, OUTPUT);
pinMode(9, INPUT);
pinMode(A0, INPUT); // Initializing Touch Sensor Pin
pinMode(A6, INPUT); // Initializing Sound Sensor Pin
Serial.begin(9600);
servo[0].attach(PIN_RR);
servo[1].attach(PIN_RL);
servo[2].attach(PIN_YR);
servo[3].attach(PIN_YL);
for(int i=0;i<4;i++) servo[i].SetPosition(90);
Otto.home();
Otto.sing(S_happy);
playRtttlBlockingPGM(13,(char*)TakeOnMe);
}
void loop() {
Otto.sing(S_OhOoh2);
dance();}
void dance()
{
primera_parte();
segunda_parte();
moonWalkLeft(4,t*2);
moonWalkRight(4,t*2);
moonWalkLeft(4,t*2);
moonWalkRight(4,t*2);
primera_parte();
crusaito(1,t*8);
crusaito(1,t*7);
for (int i=0; i<16; i++){
flapping(1,t/4);
delay(3*t/4); }
moonWalkRight(4,t*2);
moonWalkLeft(4,t*2);
moonWalkRight(4,t*2);
moonWalkLeft(4,t*2);
drunk(t*4);
drunk(t*4);
drunk(t*4);
drunk(t*4);
kickLeft(t);
kickRight(t);
drunk(t*8);
drunk(t*4);
drunk(t/2);
delay(t*4);
drunk(t/2);
delay(t*4);
walk(2,t*2);
backyard(2,t*2);
goingUp(t*2);
goingUp(t*1);
noGravity(t*2);
crusaito(1,t*2);
crusaito(1,t*8);
crusaito(1,t*2);
crusaito(1,t*8);
crusaito(1,t*2);
crusaito(1,t*3);
delay(t);
primera_parte();
for (int i=0; i<32; i++){ flapping(1,t/2); delay(t/2); }
for(int i=0;i<4;i++) servo[i].SetPosition(90);}
void oscillate(int A[N_SERVOS], int O[N_SERVOS], int T, double phase_diff[N_SERVOS]){
for (int i=0; i<4; i++) {
servo[i].SetO(O[i]);
servo[i].SetA(A[i]);
servo[i].SetT(T);
servo[i].SetPh(phase_diff[i]);
}
double ref=millis();
for (double x=ref; x<T+ref; x=millis()) { for (int i=0; i<4; i++){ servo[i].refresh(); }}}
unsigned long final_time; unsigned long interval_time;int oneTime;int iteration;float increment[N_SERVOS]; int oldPosition[]={90,90,90,90};
void moveNServos(int time, int newPosition[]){
for(int i=0;i<N_SERVOS;i++) increment[i] = ((newPosition[i])-oldPosition[i])/(time/INTERVALTIME);
final_time = millis() + time;
iteration = 1;
while(millis() < final_time){ interval_time = millis()+INTERVALTIME;
oneTime=0;
while(millis()<interval_time){
if(oneTime<1){
for(int i=0;i<N_SERVOS;i++){ servo[i].SetPosition(oldPosition[i] + (iteration * increment[i])); }
iteration++;oneTime++; } } }
for(int i=0;i<N_SERVOS;i++){ oldPosition[i] = newPosition[i]; } }
void goingUp(int tempo){
pause=millis();
for(int i=0;i<4;i++) servo[i].SetPosition(90);
delay(tempo);
servo[0].SetPosition(80);
servo[1].SetPosition(100);
delay(tempo);
servo[0].SetPosition(70);
servo[1].SetPosition(110);
delay(tempo);
servo[0].SetPosition(60);
servo[1].SetPosition(120);
delay(tempo);
servo[0].SetPosition(50);
servo[1].SetPosition(130);
delay(tempo);
servo[0].SetPosition(40);
servo[1].SetPosition(140);
delay(tempo);
servo[0].SetPosition(30);
servo[1].SetPosition(150);
delay(tempo);
servo[0].SetPosition(20);
servo[1].SetPosition(160);
delay(tempo);
while(millis()<pause+8*t);
}
void primera_parte(){
int move1[4] = {60,120,90,90};
int move2[4] = {90,90,90,90};
int move3[4] = {40,140,90,90};
for(int x=0; x<3; x++){
for(int i=0; i<3; i++){
lateral_fuerte(1,t/2);
lateral_fuerte(0,t/4);
lateral_fuerte(1,t/4);
delay(t); }
pause=millis();
for(int i=0;i<4;i++) servo[i].SetPosition(90);
moveNServos(t*0.4,move1);
moveNServos(t*0.4,move2);
while(millis()<(pause+t*2)); }
for(int i=0; i<2; i++){
lateral_fuerte(1,t/2);
lateral_fuerte(0,t/4);
lateral_fuerte(1,t/4);
delay(t);
}
pause=millis();
for(int i=0;i<4;i++) servo[i].SetPosition(90);
crusaito(1,t*1.4);
moveNServos(t*1,move3);
for(int i=0;i<4;i++) servo[i].SetPosition(90);
while(millis()<(pause+t*4));
}
void segunda_parte(){
int move1[4] = {90,90,80,100};
int move2[4] = {90,90,100,80};
int move3[4] = {90,90,80,100};
int move4[4] = {90,90,100,80};
int move5[4] = {40,140,80,100};
int move6[4] = {40,140,100,80};
int move7[4] = {90,90,80,100};
int move8[4] = {90,90,100,80};
int move9[4] = {40,140,80,100};
int move10[4] = {40,140,100,80};
int move11[4] = {90,90,80,100};
int move12[4] = {90,90,100,80};
for(int x=0; x<7; x++){ for(int i=0; i<3; i++) {
pause=millis();
moveNServos(t*0.15,move1);
moveNServos(t*0.15,move2);
moveNServos(t*0.15,move3);
moveNServos(t*0.15,move4);
while(millis()<(pause+t)); }
pause=millis();
moveNServos(t*0.15,move5);
moveNServos(t*0.15,move6);
moveNServos(t*0.15,move7);
moveNServos(t*0.15,move8);
while(millis()<(pause+t)); }
for(int i=0; i<3; i++){
pause=millis();
moveNServos(t*0.15,move9);
moveNServos(t*0.15,move10);
moveNServos(t*0.15,move11);
moveNServos(t*0.15,move12);
while(millis()<(pause+t));}
}
void lateral_fuerte(boolean side, int tempo){
for(int i=0;i<4;i++) servo[i].SetPosition(90);
if (side) servo[0].SetPosition(40);
else servo[1].SetPosition(140);
delay(tempo/2);
servo[0].SetPosition(90);
servo[1].SetPosition(90);
delay(tempo/2);
}
void drunk (int tempo){
pause=millis();
int move1[] = {60,70,90,90};
int move2[] = {110,120,90,90};
int move3[] = {60,70,90,90};
int move4[] = {110,120,90,90};
moveNServos(tempo*0.235,move1);
moveNServos(tempo*0.235,move2);
moveNServos(tempo*0.235,move3);
moveNServos(tempo*0.235,move4);
while(millis()<(pause+tempo));
}
void noGravity(int tempo){
int move1[4] = {120,140,90,90};
int move2[4] = {140,140,90,90};
int move3[4] = {120,140,90,90};
int move4[4] = {90,90,90,90};
for(int i=0;i<4;i++) servo[i].SetPosition(90);
for(int i=0;i<N_SERVOS;i++) oldPosition[i]=90;
moveNServos(tempo*2,move1);
moveNServos(tempo*2,move2);
delay(tempo*2);
moveNServos(tempo*2,move3);
moveNServos(tempo*2,move4);
}
void kickLeft(int tempo){
for(int i=0;i<4;i++) servo[i].SetPosition(90);
delay(tempo);
servo[0].SetPosition(50);
servo[1].SetPosition(70);
delay(tempo);
servo[0].SetPosition(80);
servo[1].SetPosition(70);
delay(tempo/4);
servo[0].SetPosition(30);
servo[1].SetPosition(70);
delay(tempo/4);
servo[0].SetPosition(80);
servo[1].SetPosition(70);
delay(tempo/4);
servo[0].SetPosition(30);
servo[1].SetPosition(70);
delay(tempo/4);
servo[0].SetPosition(80);
servo[1].SetPosition(70);
delay(tempo);
}
void kickRight(int tempo){
for(int i=0;i<4;i++) servo[i].SetPosition(90);
delay(tempo);
servo[0].SetPosition(110);
servo[1].SetPosition(130);
delay(tempo);
servo[0].SetPosition(110);
servo[1].SetPosition(100);
delay(tempo/4);
servo[0].SetPosition(110);
servo[1].SetPosition(150);
delay(tempo/4);
servo[0].SetPosition(110);
servo[1].SetPosition(80);
delay(tempo/4);
servo[0].SetPosition(110);
servo[1].SetPosition(150);
delay(tempo/4);
servo[0].SetPosition(110);
servo[1].SetPosition(100);
delay(tempo);}
void walk(int steps, int T){int A[4]= {15, 15, 30, 30};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90)};for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff); }
void run(int steps, int T){int A[4]= {10, 10, 10, 10};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff); }
void backyard(int steps, int T){int A[4]= {15, 15, 30, 30};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(-90), DEG2RAD(-90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void backyardSlow(int steps, int T){int A[4]= {15, 15, 30, 30};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(-90), DEG2RAD(-90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void turnLeft(int steps, int T){int A[4]= {20, 20, 10, 30};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void turnRight(int steps, int T){int A[4]= {20, 20, 30, 10};int O[4] = {0, 0, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void moonWalkRight(int steps, int T){int A[4]= {25, 25, 0, 0};int O[4] = {-15 ,15, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(180 + 120), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void moonWalkLeft(int steps, int T){int A[4]= {25, 25, 0, 0};int O[4] = {-15, 15, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(180 - 120), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void crusaito(int steps, int T){int A[4]= {25, 25, 30, 30};int O[4] = {- 15, 15, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(180 + 120), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void swing(int steps, int T){int A[4]= {25, 25, 0, 0};int O[4] = {-15, 15, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(0), DEG2RAD(90), DEG2RAD(90)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void upDown(int steps, int T){int A[4]= {25, 25, 0, 0};int O[4] = {-15, 15, 0, 0};double phase_diff[4] = {DEG2RAD(180), DEG2RAD(0), DEG2RAD(270), DEG2RAD(270)}; for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void flapping(int steps, int T){int A[4]= {15, 15, 8, 8};int O[4] = {-A[0], A[1], 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(180), DEG2RAD(90), DEG2RAD(-90)};for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);}
void test(int steps, int T){int A[4]= {15, 15, 8, 8};int O[4] = {-A[0] + 10, A[1] - 10, 0, 0};double phase_diff[4] = {DEG2RAD(0), DEG2RAD(180), DEG2RAD(90), DEG2RAD(-90)};for(int i=0;i<steps;i++)oscillate(A,O, T, phase_diff);
Otto.sing(S_cuddly);
}
Purchasing the OTTO DIY Robot : To learn more about the Otto DIY robot or purchase a off the shelf kit please head over to the OTTO DIY website at www.ottodiy.com. By purchasing the kit you will be supporting Camillo Parra and the rest of the OTTO DIY Robot team. At the OTTO DIY website www.ottodiy.com you also have the option to purchase the kit without the 3D printed parts, print the parts yourself using your own 3D printer at home.
For those interested in downloading the 3D models for printing using your own 3D printer, you will find a number of OTTO DIY robot re-mixes (3D print models) along with the original project at the Printables website (hosted by the guys who own Prusa). So head over to the 3D models hosted at Printables.com website to see all the different variants of the OTTO DIY robot listed there. If you are just wanting to download the parts for the basic Otto DIY Biped Robot then check out the following link at the main OTTO DIY Biped Robot page at the Prusa website.
For Makers, Creators & Innovators – If you are a maker, hacker and want to put together your own 3D printed robot using off the shelf components then check out this article at DIYODE – 2 Legged 3D Printed Robot. You can source all the components, parts listed above from Ebay/Amazon. If you do that, you are responsible for identifying and sourcing relevant parts, however if you purchase the kit from the OTTO DIY website www.ottodiy.com you will get quality parts including support from the OTTO DIY team.
Learn more about the OTTO Biped Project and join the OTTO DIY Robot community here – https://wikifactory.com/+OttoDIY/otto-diy and here https://wikifactory.com/+OttoDIY/otto-diy-plus
