mbed R2D2 Robot
The R2D2 robot is a Shadow robot chassis test with two motors with PID feedback control. The robot has a Sharp IR sensor mounted to the front for distance sensing, a Class D audio amp breakout board and uLCD display for audiovisual effects. An additional inspiration was the mbed Rover for this project. The robot goes in a straight line, until it encounters an object, then it turns right while playing sound effects.
Layout of components
Motors, Hall sensors, and H bridge
The Shadow robot was assembled with the motors and the Hall sensors following the guide on the Shadow robot site. The left wheel was denoted A and the right wheel was denoted B. Pay attention to this, because swapping anywhere may make the PID controller behave unpredictably.
A Polulu H-bridge breakout board was used for the motor control. AIN1,2 are the forward and reverse control inputs respectively. PWMA is the PWM speed control input. GND is ground, VCC is the 3.3V logic supply, VMOT is the the battery voltage. Electric motors draw a big inrush current at startup, to mitigate this effect a 330 uF capacitor was used on the power line. AO1,2 are the motor leads. Pull the /STBY pin high.
Mbed | H-bridge |
---|---|
p22 | PWMA |
p5 | AIN2 |
p6 | AIN1 |
GND | GND |
The Hall sensors needs to be powered with 3.3V, the (white) signal cable needs a pull-up resistor and was read using GPIO pins. (External pull-up resistors were used, because they are quicker and more robust.) The rotating wheel creates pulses on the signal line, the rising edges were counted using the InterruptIn interface.
IR sensor
Similarly to this IR sensor exercise, the sensor's output voltage was read using the AnalogIn pin. The voltage signal was then transformed to distance reading based on the diagram in the sensor's datasheet.
Audiovisual effects
The Audiovisual effects can easily be replicated following the examples in the uLCD wiki page and the Class D audio amp breakout board section of the speaker wiki page.
Mbed | uLCD |
---|---|
Vu | +5V |
p27 | TX |
p28 | RX |
GND | GND |
p29 | RES |
Code
/** * R2D2 is a mbed robot with the Shadowrobot chassis, two DC motors with feedback control, * IR distance sensor, a speaker and a uLCD */ #include "mbed.h" #include "motordriver.h" #include "PID.h" #include "uLCD_4DGL.h" #include "SongPlayer.h" //one full on this wheel is ~193 counts class Counter { //interrupt driven rotation counter to be used with the feedback control public: Counter(PinName pin) : _interrupt(pin) { // create the InterruptIn on the pin specified to Counter _interrupt.rise(this, &Counter::increment); // attach increment function of this counter instance } void increment() { _count++; } int read() { return _count; } private: InterruptIn _interrupt; volatile int _count; }; int distTransform(float input) { //stepwise transform the IR output voltage to distance if (input>3) return 6; //IR sensor datasheet: www.sharp-world.com/products/device/lineup/data/pdf/datasheet/gp2y0a21yk_e.pdf else if (input>2.5) return 8; else if (input>2) return 10; else if (input>1.5) return 14; else if (input>1.1) return 22; else if (input>0.9) return 27; else if (input>0.75) return 35; else if (input>0.6) return 45; else if (input>0.5) return 60; else if (input>0.4) return 75; else return 99; } Motor leftMotor(p22, p6, p5, 1); // pwm, fwd, rev, can brake Motor rightMotor(p21, p7, p8, 1); // pwm, fwd, rev, can brake Counter leftPulses(p9), rightPulses (p10); //Tuning parameters calculated from step tests; //see http://mbed.org/cookbook/PID for examples. PID leftPid(0.4620, 0.1, 0.0, 0.01); //Kc, Ti, Td PID rightPid(0.4620, 0.1, 0.0, 0.01); //Kc, Ti, Td DigitalOut led(LED1), led2(LED2); //LED feedback AnalogIn ain(p15); //A/D converter for the IR sensor uLCD_4DGL uLCD(p28,p27,p29); // serial tx, serial rx, reset pin for the uLCD float note[18]= {3520, 3135.96, 2637.02, 2093, 2349.32, 3951.07, 2793.83, 4186.01, 3520, 3135.96, 2637.02, 2093, 2349.32, 3951.07, 2793.83, 4186.01}; //R2D2 sound effect float duration[18]= {0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1}; //for a bit of variety, multiple sound samples could be chosen at random int main() { uLCD.printf("\n I am on an\n important\n mission!"); //Initialization //Tune PID controllers, based on mbed Rover: https://developer.mbed.org/cookbook/mbed-Rover leftPid.setInputLimits(0, 3000); leftPid.setOutputLimits(0.0, 0.8); leftPid.setMode(AUTO_MODE); rightPid.setInputLimits(0, 3000); rightPid.setOutputLimits(0.0, 0.8); rightPid.setMode(AUTO_MODE); Serial pc(USBTX, USBRX); SongPlayer mySpeaker(p23); int leftPrevPulses = 0, leftActPulses=0; //pulses from left motor float leftVelocity = 0.0; //The velocity of the left wheel in pulses per second int rightPrevPulses = 0, rightActPulses=0; //pulses from right motor float rightVelocity = 0.0; //The velocity of the right wheel in pulses per second int distance = 0; //Number of pulses to travel. led=0; led2=0; uLCD.baudrate(3000000); //uLCD baud rate for fast display wait(1); //Wait one second before we start moving. uLCD.cls(); uLCD.locate(1,2); uLCD.printf("I must find\n Ben Kenobi!"); //optional motor soft starting to reduce high inrush current /*leftMotor.speed(0.1); rightMotor.speed(0.1); wait(0.1);*/ leftPid.setSetPoint(1000); //set velocity goals for PID rightPid.setSetPoint(1000); while (1) { //start of big while loop if (distTransform(ain)>50) { //if no barrier within 50 cm go in a straight line! leftActPulses=leftPulses.read(); leftVelocity = (leftActPulses - leftPrevPulses) / 0.01; leftPrevPulses = leftActPulses; rightActPulses=rightPulses.read(); rightVelocity = (rightActPulses - rightPrevPulses) / 0.01; rightPrevPulses = rightActPulses; leftPid.setProcessValue(fabs(leftVelocity)); leftMotor.speed(leftPid.compute()); rightPid.setProcessValue(fabs(rightVelocity)); rightMotor.speed(rightPid.compute()); } else { //if there is a barrier within 50 cm, don't go straight, turn! leftMotor.stop(0.1); rightMotor.stop(0.1); led2=1; //turn on LED2 when it is turning uLCD.cls(); mySpeaker.PlaySong(note,duration); //play R2D2 sound effects uLCD.filled_circle(64, 64, 63, RED); //display R2D2 visual effects wait(0.2); uLCD.filled_circle(64, 64, 63, 0x0000FF); //light blue color wait(0.5); uLCD.filled_circle(64, 64, 63, RED); wait(0.3); //wait(0.5); leftActPulses=leftPulses.read(); rightActPulses=rightPulses.read(); distance=leftActPulses+100; while (leftActPulses<distance) { //turn approximately half a revolution leftMotor.speed(-0.5); //rotate to the right rightMotor.speed(0.5); //open loop, because the PID class can't handle negative values leftActPulses=leftPulses.read(); rightActPulses=rightPulses.read(); wait(0.005); }//Turning while end leftMotor.stop(0.1); rightMotor.stop(0.1); wait(0.1); led2=0; uLCD.cls(); uLCD.locate(1,2); uLCD.printf("I must find\n Ben Kenobi!"); leftPid.setSetPoint(1000); //go straight rightPid.setSetPoint(1000); } //Going straight/turning if end //pc.printf("\n%i", distTransform(ain)); //for debugging purposes you can read the distance reading //uLCD.locate(1,1); //uLCD.printf("Distance: %i cm", distTransform(ain)); wait(0.01); led=!led; //blink led1 to follow changes } //end of big while loop }
Project library
Import programR2D2_robot
A robot rover with distance sensing and audiovisual effects
Please log in to post comments.