Skip to content

Otto DIY

This article details the hardware parts, software, and useful information needed to assemble and start up the Otto robot.

Components

OttoDIY

OttoDIY+

Assembly

The STLs for the printed parts are in the GitHub repository inside the 3D print directory.

For assembly, follow the PDF included at the root of the GitHub repository (at the time of writing this article it was version 07).

Calibration

Load the following program to find the trim settings needed to square the robot:

//-----------------------------------------------------------------
//-- Easy calibration for Otto DIY
//-- CC BY SA (http://ottodiy.com)
//--  Javier Isabel, 02/06/2015
//-- VERY IMPORTANT only calibrate ONE TIME per board!to avoid damage EEPROM memory
//-----------------------------------------------------------------
#include <Otto.h>
#include <Servo.h>
#include <Oscillator.h>
#include <EEPROM.h>

//-- First step: Configure the pins where the servos are attached
/*
         ---------------
        |     O   O     |
        |---------------|
YR 3==> |               | <== YL 2
         ---------------
            ||     ||
            ||     ||
RR 5==>   -----   ------  <== RL 4
         |-----   ------|
*/

#define PIN_YL 2
#define PIN_YR 3
#define PIN_RL 4
#define PIN_RR 5

#define TRIM_YL 3
#define TRIM_YR 9
#define TRIM_RL -3
#define TRIM_RR 6

Otto Otto;

void setup() {
  Otto.init(PIN_YL, PIN_YR, PIN_RL, PIN_RR, false);
  Otto.setTrims(TRIM_YL, TRIM_YR, TRIM_RL, TRIM_RR); //change Trim "offset values" gradually until Otto is completely straight (90º)
  // Otto.saveTrimsOnEEPROM(); //use only after completely straight(90º), delete this line after for further programming
}

void loop() { //test comparing before & after function
  Otto.home();
}

By trial and error, identify the values of TRIM_RR, TRIM_RL, TRIM_YR, and TRIM_YL that make the four joints perfectly aligned. Once achieved, uncomment the line containing the Otto.saveTrimsOnEEPROM(); command and run it one more time so the values are stored in EEPROM. From then on, all sketches that use the Otto library and initialize that object through the init function with true as the fifth argument will load these calibration values from EEPROM and therefore will start with the robot properly aligned.

There are sketches in the repository that are not based on the Otto library but instead manage the servos directly. In these cases, trim management must also be done directly, since unfortunately the trim positions in EEPROM do not match the ones used by the Otto library, to avoid having to rewrite their values in EEPROM every time we switch from one type of sketch to another. For example, in the Otto_smooth_criminal sketch, which does not use the Otto library, the trims are read from EEPROM in reverse order. Therefore, it is better to disable that reading and write the trim values directly in the code. Like this:

#define EEPROM_TRIM false
// Activate to take callibration data from internal memory
#define TRIM_RR 6
#define TRIM_RL -3
#define TRIM_YR  9
#define TRIM_YL 3

Programming

Among the various example sketches included in the repository, the most practical one to start doing custom programming for Otto is Otto_BASIC. The comments at the beginning describe the basic functions of the Otto library:

/*SOUNDS******************
 * S_connection  S_disconnection  S_buttonPushed S_mode1 S_mode2 S_mode3 S_surprise S_OhOoh  S_OhOoh2  S_cuddly
 * S_sleeping  S_happy S_superHappy S_happy_short S_sad S_confused S_fart1 S_fart2  S_fart3
 */
/*MOVEMENTS LIST**************
 * dir=1---> FORWARD/LEFT
 * dir=-1---> BACKWARD/RIGTH
 * T : amount of movement. HIGHER VALUE SLOWER MOVEMENT usually 1000 (from 600 to 1400)
 * h: height of mov. around 20
     jump(steps=1, int T = 2000);
     walk(steps, T, dir);
     turn(steps, T, dir);
     bend (steps, T, dir); //usually steps =1, T=2000
     shakeLeg (steps, T, dir);
     updown(steps, T, HEIGHT);
     swing(steps, T, HEIGHT);
     tiptoeSwing(steps, T, HEIGHT);
     jitter(steps, T, HEIGHT); (small T)
     ascendingTurn(steps, T, HEIGHT);
     moonwalker(steps, T, HEIGHT,dir);
     crusaito(steps, T, HEIGHT,dir);
     flapping(steps, T, HEIGHT,dir);
/*GESTURES LIST***************
OttoHappy OttoSuperHappy  OttoSad   OttoSleeping  OttoFart  OttoConfused OttoLove  OttoAngry
OttoFretful OttoMagic  OttoWave  OttoVictory  OttoFail*/

In setup, a basic initialization of the Otto library is performed and a sound is emitted through the buzzer. Then in loop, a simple function has been programmed so Otto walks forward until it detects an obstacle at less than 15cm, then takes a few steps backward and turns.

//-- Function to avoid obstacles
void obstacleMode(){
      distance = Otto.getDistance();
      if(distance<15){
          Otto.sing(S_surprise);
               Otto.walk(2,1300,-1);
               Otto.turn(3,1000,-1);
             delay(50);
        }
        else{
          Otto.walk(2,1000,1);
        }
}

It is useful to take advantage of the distance sensor functionality to trigger the Otto behavior we want to program. Otherwise, everything we program inside the loop function will run nonstop. So, for example, imitating the obstacleMode function, an example loop in which we make Otto advance a couple of steps when we place a hand in front of it, do a moonwalk to the right, take a small jump, and stop by executing the victory gesture would be:

void loop() {
  distance = Otto.getDistance();
  if(distance<15){
    Otto.walk(2,1000,1);
    Otto.home();
    Otto.moonwalker(3, 1000, 25, -1);
    Otto.home();
    Otto.jump(1, 1000);
    Otto.home();
    Otto.playGesture(OttoVictory);
    Otto.home();
  } else {
    Otto.home();
  }
}