µBotino - 2"sq board for robotics, Arduino compatible

Bot4Julia.pde (9511Bytes)
Speaker.zip (1395Bytes)

After playing with the Robot Builder's Shield, I've decided to make a small robot board that has the same features as the shield. I wanted it to be 2"x2" (5x5cm) so it can be fabricated cheap and to be appealing to many robot builders that still build small robots.

I present the µBotino robot controller. Features: 

 

 

  • 6 analog sensor connectors
  • 5 servo connectors
  • SN754410 H-bridge, digital pins 5-8
  • 6 digital sensor connectors
  • 3 pin hardware serial connector
  • Arduino FTDI cable connector for programming
  • 6 pin ISP connector
  • reset button
  • jumper J1 to select power (5V or Vin) to the servo connectors
  • jumper J2 to enable/disable power to the motors (you don't want the robot to run all over when programming)
  • jumper J3 to enable/disable the LED on pin Digital 13 (don't use the LED when using a servo)
  • 16 MHz ceramic resonator
  • power LED
  • power switch
  • 5V LDO voltage regulator (1A or more)
  • small form factor, 2" square

Using Fusion PCB 2layer 5x5cm service from SeeedStudio, 10 boards will cost $20 to make. That means $2 a piece! I think all parts plus the board can fit a $20 bill.

Here is a picture of the PCB:

ubotino.jpg

 

Update 04.03.2010: Order placed at SeeedStudio. Can’t wait to work with them! Perfect for a Start Here robot!

Here is the schematic (click to get a bigger image):

 

Update Sept. 23rd 2010.

I got the boards in the mail! Here’s how they look like:

I can sell the µBotino PCB for $4 USD. I will get back soon for a complete kit.

Part list from SparkFun:

2x https://www.sparkfun.com/commerce/product_info.php?products_id=116 pin headers
4x http://www.sparkfun.com/commerce/product_info.php?products_id=8375 cap 0.1uF
1x http://www.sparkfun.com/commerce/product_info.php?products_id=315  SN754410
1x http://www.sparkfun.com/commerce/product_info.php?products_id=9650 LED green
1x http://www.sparkfun.com/commerce/product_info.php?products_id=533 LED red
1x http://www.sparkfun.com/commerce/product_info.php?products_id=102 power switch
1x http://www.sparkfun.com/commerce/product_info.php?products_id=8229 reset button (this one is SMD, should be TH)
2x http://www.sparkfun.com/commerce/product_info.php?products_id=96 cap 100uF
3x http://www.sparkfun.com/commerce/product_info.php?products_id=523 cap 10uF
1x http://www.sparkfun.com/commerce/product_info.php?products_id=8374 resistor 10k
2x http://www.sparkfun.com/commerce/product_info.php?products_id=8980 resistor 1k
1x http://www.sparkfun.com/commerce/product_info.php?products_id=9061 ATmega328
1x http://www.sparkfun.com/commerce/product_info.php?products_id=9420 resonator 16MHz
1x http://www.sparkfun.com/commerce/product_info.php?products_id=7942 28 pin socket
1x https://www.sparkfun.com/commerce/product_info.php?products_id=7938 16 pin socket
3x http://www.sparkfun.com/commerce/product_info.php?products_id=9044 jumper
1x http://www.sparkfun.com/commerce/product_info.php?products_id=107 5V v-reg, (this one is regular, should be LDO)
1x http://www.sparkfun.com/commerce/product_info.php?products_id=8233 power connector header
1x http://www.sparkfun.com/commerce/product_info.php?products_id=8100 crimp pins for power connector
1x http://www.sparkfun.com/commerce/product_info.php?products_id=8095 power connector housing

Total price: $27.7 USD with 2 items that are not what they should be. I hope I can get better prices than this!

 

Update, Sept. 24th 2010:

I have populated the first board and uploaded the code using the xBees. I had to set up the baud to 19200 because I used a mega168, but it worked flawlessly. Now all I have to do is mount the board on a robot and take a video...

Pictures:

dsc00651.jpg

 

dsc00655.jpg

dsc00653.jpg

 

dsc00654.jpg

More to come...

Update Sept 25th 2010:

Installed the µBotino on my daughter's robot and took a video. Enjoy!

 

Update Nov. 12th, 2010:

New boards are in stock and ready for sale here: 

http://robotxdesigns.ca/2010/11/08/the-ubotino-v2-pcb/

and kits:

http://robotxdesigns.ca/2010/11/08/the-ubotino-v2-kit/

 

Update April 16th, 2011:

I am getting low on the boards in stock (only 4 left) and I am looking to make some inprovements to the design. So, I am getting at version 3:

- replaced the SPDT sliding switch with a DPDT toggle switch - taller, easier to work with; the switch (in the Off position) separates the voltage regulator from the servo and motor power bus so there is no power leakage during programming with the FTDI cable

- moved the power connector between the voltage regulator and the power switch

- removing jumper J2 removes power to the servos and the motors at the same time (useful in case of debuging code)

- removing jumper J1 removes the power only for the servos

- added an extra 2 pin unkeyed connector in case one needs separate motor and servo power, remove J1 if used

- moved the D0-D4 pin names on the silk screen closer to the pins, for a better understanding

 

Here is the new schematic:

uBotinoSchV3.jpg

Here is the new PCB layout:

Let me know what you think.

 

Update May 21st, 2011:

I have received the new boards today and I am glad the custom part I designed in Eagle for the DPDT power switch fits perfectly. Can't wait to test them out, but I have another package on the way with male header pins and the Arduino long leads female headers for the shield. As soon as I can test the boards I'll add them to the store so you can get them. The new improvements make them easier to use and a better product.

Here are some pics:

new_006_resize.jpg

new_009_resize.jpg

new_010_resize.jpg

I hope you'll like them!

https://www.youtube.com/watch?v=jtR88ssGZP8?hl=en

I uploaded the code through

I uploaded the code through a wireless xBee link on the uBotino! Cool! No more pick up the robot and put it on the table for programming. Yay!

Here is the code for this robot:

// Bot4Julia, a simple Start Here style robot, made with 2 CDs,
// 2 GM17 motors and wheels, one servo, one SeeedStudio US sensor,
// one battery box, one uBotino board
//
// uBotino board pinout:
//
// uBotino Funct Arduino  ATmega168      Arduino Funct uBotino
//                       ±----/----+
//          Reset       1| PC6   PC5 |28  D19 A5  SCL  RightBumper
//          Rx    D0    2| PD0   PC4 |27  D18 A4  SDA  LeftBumper
//          Tx    D1    3| PD1   PC3 |26  D17 A3        
//          Int0  D2    4| PD2   PC2 |25  D16 A2        
//          Int1  D3    5| PD3   PC1 |24  D15 A1        IR sensor
//      Spk       D4    6| PD4   PC0 |23  D14 A0        Ping
//                      7| VCC   GND |22  
//                      8| GND  AREF |21  
//          Xtal        9| PB6  AVCC |20  
//          Xtal       10| PB7   PB5 |19  D13      SCK  LED      
//      M1A OC0B  D5   11| PD5   PB4 |18  D12      MISO 
//      M2A OC0A  D6   12| PD6   PB3 |17  D11 OC2A MOSI       
//      M2B       D7   13| PD7   PB2 |16  D10 OC1B      
//      M1B       D8   14| PB0   PB1 |15  D 9 OC1A      Pan servo
//                       ±----------+
//
#include <Servo.h>
#include <Speaker.h>
//Inputs/outputs
//#define Encoder_1_ChA  2 // digital pin 2    // Right Encoder
//#define Encoder_2_ChA  3 // digital pin 3    // Left Encoder
#define Motor_1_PWM   5 // digital pin 5    // Right Motor
#define Motor_1_Dir   8 // digital pin 8
#define Motor_2_PWM   6 // digital pin 6   // Left Motor
#define Motor_2_Dir   7 // digital pin 7
#define PingPin  14     // digital pin 14 (analog pin 0)
#define IR_Pin  15 // digital pin 15 (analog pin 1)
#define LeftBumper 18
#define RightBumper 19
#define PanPin    9     
#define SpeakerPin 4
#define LedPin 13
#define center 90
// Remote control buttons
#define btnPower   149
#define btnMute    148
#define btnPrevCh  187
#define btnDown    145
#define btnUp      144
#define btnLeft    147
#define btnRight   146
#define btnPlay    1434
#define btnStop    1432
#define btnRecord  1437
#define btnPause   1433
#define btnRew     1435
#define btnFwd     1436
#define btnInfo    186
#define btnSleep   182
#define btnInput   165
#define btnEnter   139
#define btn0       137
#define btn1       128
#define btn2       129
#define btn3       130
#define btn4       131
#define btn5       132
#define btn6       133
#define btn7       134
#define btn8       135
#define btn9       136
//Variables
byte dir=0;
byte speed1=230;
byte speed2=255;
int turn90=400;
int turn45=200;
int stopTime=200;
int USdistance=0;
int treshold=20; //20cm min distance
// remote control variables
#define start_bit  2200 // Start bit threshold (Microseconds)
#define bin_1  1000        // Binary 1 threshold (Microseconds)
#define bin_0  400              // Binary 0 threshold (Microseconds)
Servo Pan; 
Speaker speaker = Speaker(SpeakerPin); 
//-----------------------------------------------------------------------------
void setup() { 
   
  // set motor pins as output and LOW so the motors are breaked
  pinMode(Motor_1_PWM, OUTPUT);
  pinMode(Motor_1_Dir, OUTPUT);
  pinMode(Motor_2_PWM, OUTPUT);
  pinMode(Motor_2_Dir, OUTPUT);
  Stop();
  pinMode(IR_Pin, INPUT); // uses an analog pin so it has to be declared as digital in
  pinMode(PingPin, OUTPUT); 
  digitalWrite(PingPin, LOW);
  
  pinMode(LeftBumper, INPUT); 
  digitalWrite(LeftBumper, HIGH); //turn on pull ups
  pinMode(RightBumper, INPUT); 
  digitalWrite(RightBumper, HIGH); //turn on pull ups
  Pan.attach(PanPin);
  Pan.write(center); //90
  StepDelay();
  pinMode(SpeakerPin, OUTPUT); 
  speaker.Beep();
  pinMode(LedPin, OUTPUT);      
  digitalWrite(LedPin, LOW);  
  Serial.begin (19200);
  Serial.println(“start”);
  Forward();
void loop(){
  Drive();
  Get_IR_Command();
  //square();
}
void Get_IR_Command() {
  int key = getIRKey();    //Fetch the key
  Serial.print("Key ");
  Serial.println(key);
  switch (key) {    
    case btnLeft:
      Left();
      delay(turn45);
      Stop();
      break;
      
    case btnRight:    
      Right();
      delay(turn45);
      Stop();
      break;
      
    case btnUp:
      Forward();
      break;  
      
    case btnDown:
      Reverse();
      break;
    case btnStop:
      Stop();
      break;
    case btnMute:
      speaker.PlayMelody();
      break;
  }  
  //StepDelay();
  return;
}
//--------------------------
int getIRKey() {
  int data[12];
  int newdata=pulseIn(IR_Pin, LOW, 100000);
  while(newdata>0 && newdata<start_bit) { //Wait for a start bit
    newdata=pulseIn(IR_Pin, LOW, 100000);
  }
  if (newdata==0) return 0;
  for(int i=0;i<11;i++){
    data[i] = pulseIn(IR_Pin, LOW, 100000);   //Start measuring bits, we only want low pulses
  }
  speaker.Beep();
  for(int i=0;i<11;i++) {      //Parse them
    if(data[i] > bin_1) {      //is it a 1?
data[i] = 1;
    }  else {
if(data[i] > bin_0) {      //is it a 0?
 data[i] = 0;
} else {
data[i] = 2;      //Flag the data as invalid; I don’t know what it is!
}
    }
  }
   for(int i=0;i<11;i++) {      //Pre-check data for errors
    if(data[i] > 1) {
return -1;              //Return -1 on invalid data
    }
  }
  int result = 0;
  int seed = 1;
  for(int i=0;i<11;i++) {      //Convert bits to integer
    if(data[i] == 1) {
result += seed;
    }
    seed = seed * 2;
  }
  return result;      //Return key number
}
void square(){
  Forward();
  delay(2000);
  Stop();
  delay(stopTime);
  Right();
  delay(turn90);
  Stop();
  delay(stopTime);
  Forward();
  delay(2000);
  Stop();
  delay(stopTime);
  Right();
  delay(turn90);
  Stop();
  delay(stopTime);
  Forward();
  delay(2000);
  Stop();
  delay(stopTime);
  Right();
  delay(turn90);
  Stop();
  delay(stopTime);
  Forward();
  delay(2000);
  Stop();
  delay(stopTime);
  Right();
  delay(turn90);
  Stop();
  delay(stopTime);
}
void Drive(){
  if (digitalRead(LeftBumper)==LOW){
  digitalWrite(LedPin, HIGH);  
    Stop();
    speaker.Beep();
    StepDelay();
  digitalWrite(LedPin, LOW);  
    Reverse();
    StepDelay();
    Stop();
    StepDelay();
    Right();
    delay(turn45); //turn45
    Stop();
    StepDelay();
    Forward();
  }
  if (digitalRead(RightBumper)==LOW){
  digitalWrite(LedPin, HIGH);  
    Stop();
    speaker.Beep();
    StepDelay();
  digitalWrite(LedPin, LOW);  
    Reverse();
    StepDelay();
    Stop();
    StepDelay();
    Left();
    delay(turn45); //turn45
    Stop();
    StepDelay();
    Forward();
  }
  USdistance=Read_Ping_Sensor();
  Serial.print("USdistance ");
  Serial.println(USdistance);
  if (USdistance<10){
    Stop();
    speaker.Beep();
    StepDelay();
    TurnAround();
  }
  if (USdistance<treshold){
    Stop();
    speaker.Beep();
    StepDelay();
    Avoid();
    Forward();
  }
  delay(50);
}
void TurnAround(){
    Reverse();
    Pan.write(center);
    StepDelay();
    Stop();
    Left();
    delay(turn90);
    delay(turn90);
    Stop();
    StepDelay();
    Forward();
}
void Avoid(){
  int prev=0;
  dir=2;
  for (byte i=0; i<5; i++){
    Pan.write(i*45);
    StepDelay();
    StepDelay();
    USdistance=Read_Ping_Sensor();
    if (USdistance>prev){
      dir=i;
      prev=USdistance;
    }
  }
  Pan.write(center);
  StepDelay();
  switch (dir){
    case 0:
      Right();
      delay(turn90);
      Stop();
      speaker.Beep();
      StepDelay();
      break;
    case 1:
      Right();
      delay(turn90); //turn45
      Stop();
      speaker.Beep();
      StepDelay();
      break;
    case 2:
      Forward();
      break;
    case 3:
      Left();
      delay(turn90); //turn45
      Stop();
      speaker.Beep();
      StepDelay();
      break;
    case 4:
      Left();
      delay(turn90);
      Stop();
      speaker.Beep();
      StepDelay();
      break;
  }
  delay(500);
}  
// Read Sensors
int Read_Ping_Sensor(){
  //digitalWrite(LedPin, HIGH);  
  int cm=0;
  //trigger the sensor
  unsigned long value = 0;
  pinMode(PingPin, OUTPUT);
  digitalWrite(PingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(PingPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(PingPin, LOW);
  //receive the echo
  pinMode(PingPin, INPUT);
  digitalWrite(PingPin, HIGH); // turn on pull up resistor
  value = pulseIn(PingPin, HIGH);
  value=value/58;
  cm=int(value);
  //digitalWrite(LedPin, LOW);  
  return cm;
}
void StepDelay() {
    for (byte t=0; t<10; t++){
      //SoftwareServo::refresh();
      delay(20);
    }
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void Forward(){
  digitalWrite(Motor_1_Dir, LOW); // forward
  digitalWrite(Motor_2_Dir, LOW); // forward
  analogWrite(Motor_1_PWM, speed1); // 
  analogWrite(Motor_2_PWM, speed2); //
  return;
}
void Reverse(){
  digitalWrite(Motor_1_Dir, HIGH); // reverse
  digitalWrite(Motor_2_Dir, HIGH); // reverse
  analogWrite(Motor_1_PWM, 255-speed1); // 
  analogWrite(Motor_2_PWM, 255-speed2); //
  return;
}
void Right(){
  digitalWrite(Motor_1_Dir, HIGH); // reverse
  digitalWrite(Motor_2_Dir, LOW); // forward
  analogWrite(Motor_1_PWM, 255-speed1); // 
  analogWrite(Motor_2_PWM, speed2); //
  return;
}
void Left(){
  digitalWrite(Motor_1_Dir, LOW); // forward
  digitalWrite(Motor_2_Dir, HIGH); // reverse
  analogWrite(Motor_1_PWM, speed1); // 
  analogWrite(Motor_2_PWM, 255-speed2); //
  return;
}
void Stop()
{
  digitalWrite(Motor_1_PWM, LOW);
  digitalWrite(Motor_1_Dir, LOW);
  digitalWrite(Motor_2_PWM, LOW);
  digitalWrite(Motor_2_Dir, LOW);
  return;
}