Balancing robot for dummies

@kas
@osmaneralp
@Ro-Bot-X
@GuzZzt

I would like to have a page on the projects homepage with some example robots that has used this project to be able to build a balancing robot or something else...

If you feel that this project had helped you with your bot could you send me a link to a homepage or a build blog there you describe your bots and what components you have used. With some images and videos etc.

Otherwise send some text and the images and links to videos and I can make a page on my web server for the bot..

I got my hands on a free L298N H-Bridge: http://www.st.com/stonline/books/pdf/docs/1773.pdf
Unfortunately it only can handle spikes of 3 A (repetitive 2.5 A). Did you ever get an idea of what currents are used? I plan on making the bot relatively small...

I would take the motor stall current as the H-bridge amp requirement

Also, have you ever run into speed problems from the microcontroller? Is 16 MHz fast enough?

16 MHz is fast enough

My understanding was that the sensors act as the feedback to tell the motors direction and speed, so a motor encoder is not necessary. I see you made the same statement in your initial post.

You will get "basic" balance w/o encoders, but the bot will drift forward/backward

I have now gotten my BlueSmirf and the other parts I was missing to be able to complete my bot.
...
I will post some images and a video on the interface and robot in the end of the week hopefully..

Congratulation Patrik
I will also post my XBee version this week end :wink: :wink:

Ok, I ordered the 6DOF IMU. It has I2C interface, not SPI. Standard speed is 100k/s, faster speed is 400k/s. To poll the sensor we need the Wire library, I have experience working with I2C sensors and I have 4 Arduinos on a robot linked through I2C interface. So, I hope it will work fine. The only thing I have a problem with is the 3.3V interface. I'll see what I can do. I think I need to use 4.7k pull up resistors tied to 3.3V instead of 5V. Also, the sensor needs 3.3V that I will get from the Arduino board directly (I still need to check the current requirements).

I will create a blog page with my attempt, although it did not work because of the design I tried just to see if it works. New version coming as soon as I will get the new IMU.

08:16 14/01/2011
@Osmaneram
Nice bot :slight_smile:
I played with a MPC3208 ADC which is the 8 input version
As far as I remember, those are 12 bit ADC's with 4096 units (not 8096) :o
Please clarify

Your IMU board may have a different noise pattern that may require specific Kalman filter tuning.
The ADC should not inpact Kalman tuning (it didn't on my setup)

@Ro-Bot-X
I am also tempted to go digital for several reasons

  • analogic is noisy by nature
  • additional features
  • this is the future...

I2C frequency is in the 100KHz range, don't be affraid
Please try it and let us know the outcome, we all need guinea pigs :wink: :wink:

I played with a MPC3208 ADC which is the 8 input version
As far as I remember, those are 12 bit ADC's with 4096 units (not 8096)
Please clarify

@kas Good catch. I'm actually using a 3302, which is a four channel 13-bit differential input a2d. The extra bit compared to the 32xx parts is a sign bit. To take advantage of the sign bit, the a2d input voltage must swing above and below the a2d vref. If the vref of your arduino is tied to 3.3v, you the input voltage from the gyro will never go above vref, and so you only get 12 bits.

To get the full 13 bits, take the vref from the gyro, which on my gyro is 1.241v, and connect it to the vref on the a2d and channel 1 on the a2d. Take the vout from the gyro and connect it to channel 0 on the a2d. Configure the a2d to run in differential mode. This means that the a2d will compare channel 0 to channel 1. If the voltage on channel 0 is greater than the voltage on channel 1, the output of the a2d is positive and the sign bit is 0, otherwise the sign bit is 1 which indicates a negative value. In addition to the sign bit, there are 12 more bits of resolution. This means that you get 12 bits from 0 to vref, and another 12 bits from vref to 2 x vref. That's 13 bits effective resolution.

Whether or not all 13 bits will be useful is not yet clear! :-/

--Osman

Hi Kas,

compliments for your great job and info.

I have terminated a self balancing robot very similar to your (same IMU), except for motors.

I used 6V HITEC HS-325HB hacked to run continuosly, but this motors are not enough for he job they have to do.

I tried to make the robot less high but it became too instable..

anyway I order the same Your Pololu equipment...waiting for shipment.

Two questions:

(1) in the setup, with the function calibrateSensors(); you have to put the robot (each time you switch it on) exactly in the static equilibrium position in order to evaluate zero values (exept for z).

is this a little bit boring and could produce errors (if it is not perfectly perpendicular)?

If during the calibrateSensors() i'll give a tilt, the Robot will work to keep the tilt!

maybe there is something that I cannot understand?

(2) what do You use to recharge the 12V batteries?

thanks,

bye,

Prof

Hi prof_jazz, welcome :slight_smile:
please let us have a photo of your new pet

I used 6V HITEC HS-325HB hacked to run continuosly, but this motors are not enough for he job they have to do

I also waste one year following this track :wink:

(1) in the setup, with the function calibrateSensors(); you have to put the robot (each time you switch it on) exactly in the static equilibrium position in order to evaluate zero values (exept for z).
is this a little bit boring and could produce errors (if it is not perfectly perpendicular)?
If during the calibrateSensors() i'll give a tilt, the Robot will work to keep the tilt!

No No...
If you tilt the bot forward before calibrateSensors(), it will move forward and find a vertical equilibrium
This will happen only with encoder(s) implementation, look here

(2) what do You use to recharge the 12V batteries?

I ordered the battery charger shown here

** Balancing robot for dummies **

Part seven: Xbee wireless control, KasBot V 3.0

The objective is to obtain basic motion control (Forward/Backward, Stop Right/Left)
Xbee modules act as a serial line replacement, a USB cable without the cable :slight_smile:
See post #82 for more info

1) controller side:

Shopping list at post #77
Transmitter with Nunchuck joystick controller is shown on post #107
The additional micro joystick and the 3 LED's will be used for advanced features wich are beyong the scope of this basic KasControl V1.0

Nunchuk_kas.h does take care of the I2C communication with the joystick

// Nunchuck_kas.h        joystick functions ----------------------------------------------------------------

#include "Wprogram.h"
#include <Wire.h>

static uint8_t nunchuck_buf[6];                             // array to store nunchuck data,

void nunchuck_init()  { 
  Wire.begin();                                                  // join i2c bus as master
  Wire.beginTransmission(0x52);                                  // transmit to device 0x52
  Wire.send(0x40);                                        // sends memory address
  Wire.send(0x00);                                        // sends a zero.  
  Wire.endTransmission();                                  // stop transmitting
}

void nunchuck_send_request()  {                             // Send a request for data to nunchuck
  Wire.beginTransmission(0x52);                                  // transmit to device 0x52
  Wire.send(0x00);                                        // sends one byte
  Wire.endTransmission();                                  // stop transmitting
}
 
char nunchuk_decode_byte (char x)  {                         // Encode data to format that most wiimote drivers 
  x = (x ^ 0x17) + 0x17;                                     // except only needed if you use one of the regular
  return x;                                                  // wiimote drivers
}

int nunchuck_get_data()  {                                   // Receive data back from the nunchuck
  int cnt=0;
  Wire.requestFrom (0x52, 6);                                  // request data from nunchuck
  while (Wire.available ()) {                               // receive byte as an integer
    nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());
    cnt++;
  }
  nunchuck_send_request();                                  // send request for next data payload
  if (cnt >= 5)     return 1;                               // If we recieved the 6 bytes, then go print them
  return 0;                                                 // failure
}                                                           // returns 1 on success read, returns 0 on failure

int nunchuck_joyx()  {                                     // returns value of x-axis joystick
  return nunchuck_buf[0]; 
}

int nunchuck_joyy()  {                                     // returns value of y-axis joystick
  return nunchuck_buf[1];
}

This is a strip down version of the code that can be found in the Arduino Playground section.
We only use the joystick data, (we have enough accelerometers in this project ;))
More info on wiring and code here

The main code uses a communication protocol based on 3 Bytes:
controlByte = 'd' (just says "hey, I am coming with new joystick data !!")
dataByte_1 = value of y-axis joystick
dataByte_2 = value of x-axis joystick

To reduce traffic, data is only sent when joystick is moved

// ** Kas Control V10     Balancing bot RC with nunchuk **  

// Yellow: Clock SCL (AI5)  Red: 3.3V  Green: Data SDA(AI4)  Write: Ground
// serial data format:   <controlByte> <dataByte_1> <dataByte_2> <CR>
// V1.0 basic control

#include <Wire.h>
#include "Nunchuck_kas.h"

int refreshTime = 100;                                    // time in millisecs between Nunchuck poolings
long lastPulse = 0;
char controlByte = 0;
char dataByte_1 = 0;                                      // joystick data
char dataByte_2 = 0;

void setup()  {
  Serial.begin(19200);
  nunchuck_init();                                         // send the initilization handshake
  delay(100);
  nunchuck_joyx();
  nunchuck_joyy();
}

void loop()  {
  if (millis() - lastPulse >= refreshTime) {                // x ms have passed
    checkNunchuck();
    lastPulse = millis();                                   // save the time of last pulse
  }
} 

void checkNunchuck()  {
  static int Byte1_ant, Byte2_ant;
  nunchuck_get_data();
  controlByte = 'd';
  dataByte_1 = map(nunchuck_joyy(), 27, 218, 0, 40);        // nunchuck joystick North/South                    
  dataByte_2 = map(nunchuck_joyx(), 27, 218, 0, 40);        // nunchuck joystick East/West
  dataByte_1 = constrain(dataByte_1, 0, 40);                                 
  dataByte_2 = constrain(dataByte_2, 0, 40);
  if((dataByte_1!=Byte1_ant)||(dataByte_2!=Byte2_ant))  {
    updateBot();
    Byte1_ant = dataByte_1;
    Byte2_ant = dataByte_2;
  }
}

void updateBot()    {                                       // send data stream
    Serial.print(controlByte);        
    Serial.print(dataByte_1);    
    Serial.print(dataByte_2);
    Serial.print("\n");
}

...........

.......... continued

** Balancing robot for dummies **

Part seven: Xbee wireless control, KasBot V 3.0

2) Robot side:

On the bot side, the Xbee module is set as per post #107

The datastream is decoded within getMotion()

void getMotion() {
  if(!Serial.available())      return;
  delay(5);                  
  int controlByte = Serial.read();              // get control byte
  if(!Serial.available())      return;
  int dataByte_1 = Serial.read();               // get data byte 1
  if(!Serial.available())      return;
  int dataByte_2 = Serial.read();               // get data byte 2
  Serial.flush();                                 
 
  if(controlByte == 'd')   {                    // Nunchuk joystick data
    setPoint = -(dataByte_1 - 20)/2;          // get forward/backward motion byte
    if(abs(setPoint) > 2)  {
      count = 0;
      last_count = 0;
    }
    turn = (dataByte_2 - 20);                   // get right/left motion byte
  }  else    bip(bipPin, 10, 1);                  // wrong header
}

setPoint is used to bias updatePid() and slithly move the bot from vertical, thus initiating the move

void loop() {
// ********************* Get Xbee data *******************************
  getMotion();

// ********************* Sensor aquisition & filtering ***************
.....

// *********************** Angle Control and motor drive *************
  drive = updatePid(setPoint, actAngle);                                // PID algorithm

  if(abs(actAngle) < 100)    {
    Drive_Motor(drive); 
  }  else {  
    Drive_Motor(0);                                                    // stop motors if situation is hopeless
    setZeroIntegal();                                                  // reset PID Integral accumulaor
  }
// ********************* print Debug info ****************************
.....

// *********************** loop timing control ***********************
.....

}

turn becomes a new parameter in Drive_Motor(), to allow right and left motor to run at their own speed

int Drive_Motor(int torque)  {
  if (torque + turn >= 0)  {                                          // drive motors forward
    digitalWrite(InA_R, LOW);                        
    digitalWrite(InB_R, HIGH);
    torque_R = torque + turn;
    if (torque - turn >= 0)  {                                        // drive motors forward 
      digitalWrite(InA_L, LOW);                     
      digitalWrite(InB_L, HIGH);
      torque_L = torque - turn;
    }  else  {
      digitalWrite(InA_L, HIGH);                      
      digitalWrite(InB_L, LOW);
      torque_L = abs(torque - turn);
    }
  }  else {                                                           // drive motors backward
    digitalWrite(InA_R, HIGH);                       
    digitalWrite(InB_R, LOW);
    torque_R = abs(torque + turn);
     if (torque - turn >= 0)  {                                       // drive motors forward
      digitalWrite(InA_L, LOW);                     
      digitalWrite(InB_L, HIGH);
      torque_L = torque - turn;
    }  else  {
      digitalWrite(InA_L, HIGH);                      
      digitalWrite(InB_L, LOW);
      torque_L = abs(torque - turn);
    }
 }
  torque_R = map(torque_R,0,255,K_map,255);
  torque_L = map(torque_L,0,255,K_map,255);
  torque_R = constrain(torque_R, 0, 255);
  torque_L = constrain(torque_L * motor_Offset, 0, 255);
  analogWrite(PWM_R,torque_R);
  analogWrite(PWM_L,torque_L * motor_Offset);                      // motors are not built equal...
}

OK guys, this is probably my last significant contribution to this thread :-/
I suddently realize that I have a real life and... some other projects to explore ::slight_smile: ::slight_smile:

I am sure this thread will keep on, with new bright ideas coming on
What about non linear control ??
What about one wheeled bot as shown by Big Oil ??

"...Two wheeled balancing robots are an area of research that may well provide the future locomotion for everyday robots..."

I really enjoyed all these discussions we had on this common project
Thanks again to everybody for reading and contributing :slight_smile: :slight_smile: :slight_smile:

wow kas!

any video of this new child?

bye

I am better at photo than video :wink:

@osmaneralp

I have ordered my Chumby from Costco, it should arrive in 7-10 days at my friend in Florida then he will send it to me in Canada. So I expect about 3-4 weeks until I'll actually have it in my hands. Until then, I'll work on the chassis and the rest of the project. I would really like to take a look at your bot's build page, especially the way you used the Chumby as a robot controller. I have found some info on the net, but a more in depth info would be great.

Thanks!

@Patrick

here is a link to my attempt: Balancing Octobot | Ro-Bot-X's Weblog

@Ro-Bot-X

One of the guys in the robotics club I belong to (The Silicon Valley HomeBrew Robotics Club) wrote an article on using the Chumby as a robot controller. You can find it on his web site: http://www.demandperipherals.com/docs.html#howto. He said you can contact him if you have any questions. I also have a fair bit experience using the Chumby as the brains of my robots. Feel free to PM me.

I don't want to hijack this thread with posts about the Chumby, so let's start a new topic or exchange PMs.

--Osman

Hi,

the 1 x Dual VNH2SP30 Motor Driver Carrier MD03A (49,95$) on Pololu is out of stock till March...

Could You suggest a valid backup solution ?

The "Pololu Qik 2s12v10 Dual Serial Motor
Controller" (74,95$) Pololu Qik 2s12v10 Dual Serial Motor Controller uses the same VNH2SP30 chip.

I have to drive the same Kas motors (Pololu Metal Gearmotor 37Dx52L mm with 64 CPR Encoder), Could You give me a feedback and more information?
I'll be happy to add 25$ if the "Pololu Qik 2s12v10 Dual Serial Motor Controller" will drive the above motors with no difference.

will be the arduino code the same?

Thanks

I'm wondering how well a Brushed Motor ESC could work with the balancing bot? They take a servo signal between 1000-2000us and convert it to linear throttle curve, forward, backward and programmable break (jumper ON=break, Off=coast). Here is a link for such a device: http://www.hobbyking.com/hobbyking/store/uh_viewItem.asp?idProduct=9090 It's just $5 for 20A! Of course, we need 2 of them, but they are cheaper than a 5 A dual motor driver...

I think the problem with brush less motors is that they don't like low speeds where they will consume a lot amps..

I think the problem with brush less motors is that they don't like low speeds where they will consume a lot amps..

I was talking about Brushed motor ESC, not brush less...