PArduino - An Arduino-based 2WD Robot

I'm pleased to show you PArduino, my first Arduino-based Robot!

It's a 2 wheel drive robot, remotly controlled (Bluetooth) by smartphone: you can use your touchscreen or your voice! And it also support an autopilot mode!

Here is the list of its components (maybe, and I say maybe, one day I'll draw a Fritzing sketch of it!):

  • 1 Arduino Uno R3
  • 1 plexiglass chassis
  • 2 small DC motors with gearboxes and rubber wheels
  • 2 buck-boost adjustable voltage regulators Pololu S7V8A
  • 1 H-bridge motor drive L293DNE
  • 1 Bluetooth module HC-05
  • 1 ultrasound sensor HC-SR04
  • 1 big yellow LED
  • 1 4AA battery holder
  • 1 220 ohm resistor
  • 2 100 uF capacitors
  • 1 piezo buzz
  • 1 small breadboard
  • 1 smaller breadboard
  • many jumpers and cables
  • some other less important things to assemble everything
  • Panoramic
  • Piezo, bluetooth
  • Power supply with buck-boost voltage regulators
  • Panoramic
  • Ultrasound distance sensor
  • Arduino Uno R3

Here it is the "PArduino Remote Control", the Android app I created to control the robot! It's made with the MIT App Inventor online development environment:

  • Main screen
  • Speech recognition
  • MIT App Inventor - Design
  • MIT App Inventor - Blocks

Here you can find the Arduino code: take it "as is", it works, and I know it could work better and be more easy-to-read...Some code is made by me, some code is taken from the web and revisited to my project, so I hope no one will take offence about its publication here: in case, let me know!

#include <SoftwareSerial.h>

// nota:le icone app sono caribbean blue www.iconsdb.com
SoftwareSerial Pasquale(7, 8); // RX, TX

int motor1Pin1 = 4; 
int motor1Pin2 = 2; 
int motor2Pin1 = 6; 
int motor2Pin2 = 5;

int pinluce = 13;
//int pinclacson=3;

int pintrig = 9;
int pinecho = 10;
int distmin=25;
int direzione=1;
unsigned long tlastsceltadir;
unsigned long tlastdir;
long durata;
long distanza;

int comando;
int forzastop=0;
int statoluce=0;
int statoauto=0;

//RTTTL

#define OCTAVE_OFFSET 0
#define TONE_PIN 3

#define NOTE_C4  262
#define NOTE_CS4 277
#define NOTE_D4  294
#define NOTE_DS4 311
#define NOTE_E4  330
#define NOTE_F4  349
#define NOTE_FS4 370
#define NOTE_G4  392
#define NOTE_GS4 415
#define NOTE_A4  440
#define NOTE_AS4 466
#define NOTE_B4  494
#define NOTE_C5  523
#define NOTE_CS5 554
#define NOTE_D5  587
#define NOTE_DS5 622
#define NOTE_E5  659
#define NOTE_F5  698
#define NOTE_FS5 740
#define NOTE_G5  784
#define NOTE_GS5 831
#define NOTE_A5  880
#define NOTE_AS5 932
#define NOTE_B5  988
#define NOTE_C6  1047
#define NOTE_CS6 1109
#define NOTE_D6  1175
#define NOTE_DS6 1245
#define NOTE_E6  1319
#define NOTE_F6  1397
#define NOTE_FS6 1480
#define NOTE_G6  1568
#define NOTE_GS6 1661
#define NOTE_A6  1760
#define NOTE_AS6 1865
#define NOTE_B6  1976
#define NOTE_C7  2093
#define NOTE_CS7 2217
#define NOTE_D7  2349
#define NOTE_DS7 2489
#define NOTE_E7  2637
#define NOTE_F7  2794
#define NOTE_FS7 2960
#define NOTE_G7  3136
#define NOTE_GS7 3322
#define NOTE_A7  3520
#define NOTE_AS7 3729
#define NOTE_B7  3951

int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};

//char *song = "The Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8c6,c6";
//char *song = "Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e,8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6";
char *song1 = "IndianaLITE:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8e,1f";
//char *song = "Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c.6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#,8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6,8a,2d6";
//char *song = "Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6,8d6,8a,8c6,8g,8a#,8a,8f";
//char *song = "Bond:d=4,o=5,b=80:32p,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d#6,16d#6,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d6,16c#6,16c#7,c.7,16g#6,16f#6,g#.6";
//char *song = "StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6";
//char *song = "GoodBad:d=4,o=5,b=56:32p,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,d#,32a#,32d#6,32a#,32d#6,8a#.,16f#.,16g#.,c#6,32a#,32d#6,32a#,32d#6,8a#.,16f#.,32f.,32d#.,c#,32a#,32d#6,32a#,32d#6,8a#.,16g#.,d#";
//char *song = "TopGun:d=4,o=4,b=31:32p,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,16f,d#,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,g#";
//char *song = "Flinstones:d=4,o=5,b=40:32p,16f6,16a#,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,d6,16f6,16a#.,16a#6,32g6,16f6,16a#.,32f6,32f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c6,a#,16a6,16d.6,16a#6,32a6,32a6,32g6,32f#6,32a6,8g6,16g6,16c.6,32a6,32a6,32g6,32g6,32f6,32e6,32g6,8f6,16f6,16a#.,16a#6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,32f6,16a#6,16c7,8a#.6";
//char *song = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
//char *song = "MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g5,2e,d#,8d";
//char *song = "KnightRider:d=4,o=5,b=125:16e,16p,16f,16e,16e,16p,16e,16e,16f,16e,16e,16e,16d#,16e,16e,16e,16e,16p,16f,16e,16e,16p,16f,16e,16f,16e,16e,16e,16d#,16e,16e,16e,16d,16p,16e,16d,16d,16p,16e,16d,16e,16d,16d,16d,16c,16d,16d,16d,16d,16p,16e,16d,16d,16p,16e,16d,16e,16d,16d,16d,16c,16d,16d,16d";
char *song2 = "PoliceP:d=4,o=6,b=140:8e,8c,8e,8c";
char *song = "Metallica:d=4,o=6,b=150:16e,16e,p,8p,8d,8c#,2c,16e5,16e5,16e,16e5,16e5,16e,16e5,16e5,8d,8c#,c,16e5,16e5,16e,16e5,16e5,16e,16e5,16e5,8d,8c#,8c,8b5,16e5,16e5,16e,16e5,16e5,16f,16e5,16e5,16f#,16e5,16e5,16f#,16e5,16e5,8f";

#define isdigit(n) (n >= '0' && n <= '9')

//fine RTTTL

void setup() {
    
    pinMode(pinluce,OUTPUT);
    digitalWrite(pinluce,LOW);
  
    pinMode(motor1Pin1, OUTPUT);
    pinMode(motor1Pin2, OUTPUT);

    pinMode(motor2Pin1, OUTPUT);
    pinMode(motor2Pin2, OUTPUT);
    
    pinMode(pintrig, OUTPUT);
    pinMode(pinecho, INPUT);
   
    digitalWrite(motor1Pin1, LOW); 
    digitalWrite(motor1Pin2, LOW); 
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, LOW);
   
    Pasquale.begin(9600);
}

void loop() {
   
    if(Pasquale.available()){     
      comando = Pasquale.read();   
    } 
    
    if (comando == '0') {
      if(statoauto==0){  
      play_rtttl(song1);
      }
        statoauto=1;
        automatico();
    }
    
    else if (comando == '1') {
       statoauto=0; 
       avanti();
    }
    
    else if (comando == '2') {
        statoauto=0; 
        sinistra();    
    }
    
    else if (comando == '3' || forzastop==1) {
        statoauto=0; 
        fermo();
    }
    else if (comando == '4') {
        statoauto=0; 
        destra();
    }

    else if (comando == '5') {
        statoauto=0; 
        indietro();
    }
    
    else if (comando == '6') {
      statoauto=0; 
      luce();
    }
    
    else if (comando == '7') {
      statoauto=0; 
      clacson();
    }
    
    else if (comando == '8') {
      statoauto=0; 
      avantistop();
    }
    
    else if (comando == '9') {
      statoauto=0; 
      indietrostop();
    }
    
    else if (comando == ':') {
      statoauto=0; 
      destrastop();
    }
    
    else if (comando == ';') {
      statoauto=0; 
      sinistrastop();
    }
    
    delay(100);
}

void avanti(){
        digitalWrite(motor1Pin1, HIGH);
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, HIGH);    
}

void avantistop(){
        digitalWrite(motor1Pin1, HIGH);
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, HIGH);
        
        delay(1000);
        comando=3;
        forzastop=1;    
}

void indietro(){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, HIGH);
        digitalWrite(motor2Pin1, HIGH);
        digitalWrite(motor2Pin2, LOW);
}

void indietrostop(){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, HIGH);
        digitalWrite(motor2Pin1, HIGH);
        digitalWrite(motor2Pin2, LOW);
        
        delay(1000);
        comando=3;
        forzastop=1;
}

void destra(){
        digitalWrite(motor1Pin1, HIGH); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, LOW);
}

void destrastop(){
        digitalWrite(motor1Pin1, HIGH); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, LOW);
        
        delay(350);
        comando=3;
        forzastop=1;
}

void destraauto(int t){
        digitalWrite(motor1Pin1, HIGH); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, LOW);
        
        delay(t);
        fermo();
}

void sinistra(){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, HIGH);
}

void sinistrastop(){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, HIGH);
        
        delay(350);
        comando=3;
        forzastop=1;
}

void sinistraauto(int t){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, HIGH);
        
        delay(t);
        fermo();
}

void fermo(){
        digitalWrite(motor1Pin1, LOW); 
        digitalWrite(motor1Pin2, LOW); 
        digitalWrite(motor2Pin1, LOW);
        digitalWrite(motor2Pin2, LOW);
        forzastop=0;
}

void luce(){
  if (statoluce == 0){    
    digitalWrite(pinluce,HIGH);
    comando=3;
    forzastop=1;
    statoluce=1;
  }
  
  else{
   digitalWrite(pinluce,LOW);
    comando=3;
    forzastop=1;
    statoluce=0;
  }
}

void clacson(){
fermo();
play_rtttl(song);

  comando=3;
  forzastop=1;
}

void automatico(){
  //vuoto = analogRead(A0);
  //if(vuoto>900){
  //  indietro();
  //  delay(1000);
  //  fermo();
  //  delay(1);
  //}
  //else{
 digitalWrite(pintrig, LOW); 
 delayMicroseconds(2); 
 digitalWrite(pintrig, HIGH);
 delayMicroseconds(10); 
 digitalWrite(pintrig, LOW);
 
 durata = pulseIn(pinecho, HIGH);
 distanza = durata/58.2; //cm
 
 if(millis()-tlastsceltadir > 10000){
 direzione=random(1,100);
 tlastsceltadir=millis();
 }
  
 if (distanza >= distmin){
	if (millis()-tlastdir > 10000){
		fermo();
		indietro();
		delay(500);
		fermo();
			if(direzione>50){
				destraauto(200);
			}
			else{
				sinistraauto(200);
			}
		fermo();
		avanti();
		tlastdir=millis();
	}
	else{
		avanti();
	}
 }
 
 else {
    tlastdir=millis();
	fermo();
    play_rtttl(song2);
    delay(100);
    indietro();
    delay(500);
    if(direzione>50){
    fermo();
    destraauto(350);
    }

	else{
    fermo();
    sinistraauto(350);
	} 
 }
 
 delay(50);
//}
}

void play_rtttl(char *p)
{
  // Absolutely no error checking in here

  byte default_dur = 4;
  byte default_oct = 6;
  int bpm = 63;
  int num;
  long wholenote;
  long duration;
  byte note;
  byte scale;

  // format: d=N,o=N,b=NNN:
  // find the start (skip name, etc)

  while(*p != ':') p++;    // ignore name
  p++;                     // skip ':'

  // get default duration
  if(*p == 'd')
  {
    p++; p++;              // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++;                   // skip comma
  }

  // get default octave
  if(*p == 'o')
  {
    p++; p++;              // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++;                   // skip comma
  }

  // get BPM
  if(*p == 'b')
  {
    p++; p++;              // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++;                   // skip colon
  }

  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)

  // now begin note loop
  while(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        break;
      case 'd':
        note = 3;
        break;
      case 'e':
        note = 5;
        break;
      case 'f':
        note = 6;
        break;
      case 'g':
        note = 8;
        break;
      case 'a':
        note = 10;
        break;
      case 'b':
        note = 12;
        break;
      case 'p':
      default:
        note = 0;
    }
    p++;

    // now, get optional '#' sharp
    if(*p == '#')
    {
      note++;
      p++;
    }

    // now, get optional '.' dotted note
    if(*p == '.')
    {
      duration += duration/2;
      p++;
    }
  
    // now, get scale
    if(isdigit(*p))
    {
      scale = *p - '0';
      p++;
    }
    else
    {
      scale = default_oct;
    }

    scale += OCTAVE_OFFSET;

    if(*p == ',')
      p++;       // skip comma for next note (or we may be at the end)

    // now play the note

    if(note)
    {
      tone(TONE_PIN, notes[(scale - 4) * 12 + note]);
      digitalWrite(pinluce,HIGH);
      delay(duration*0.75);
      digitalWrite(pinluce,LOW);
      delay(duration*0.25);
      noTone(TONE_PIN);
    }
    else
    {
      delay(duration);
    }
  }
}


And finally, see it in action! In the first video, you can see how speech recognition works. In the second video, you can see a demo of the autopilot mode. Finally, in the third video an experimental attempt to make PArduino become a tiny rover! Enjoy!

Here you can find the source files: