GloveBot: Semi-active Controlled Autonomous Driving Vehicle
Team Members
Animesh Patel
Kevin Chang
Zheyuan Xu
Introduction
The glove bot we are making is an autonomous moving vehicle which can be controlled remotely by a magic glove and pronounce the words upon specific motion command. The vehicle has 2 motors and has a Raspberry Pi 0 powered camera which spins periodically from left to right; it also uses distance sensors to avoid collision, making it a multi-purpose moving platform eligible for various engineering uses.
Hardware Parts
Mbed
ARM LPC1768 has a built-in Cortex M3 processor and can be programmed by Mbed cloud account. In this project, 3 Mbeds are used . The controller, which is the glove terminal, uses Mbed to receive sensor output from the fingers, as well as powering uLCD and Xbee wireless module. The other two are located in the receiver, which is the vehicle. One is used to power the motor, an Emic2 text-to-speech converter, a ToF distance sensor, as well the Xbee wireless module. The other one is used to power the servo which rotates the camera periodically.
Raspberry Pi Zero
The Raspberry Pi Zero is used to power the camera and run the picture taking program when the vehicle is powered. It has a built-in SD card which stores the picture taken for further analysis. Upon power up, it will automatically run the python scripts which can turn on the camera and take pictures at 3 different orientations.
Xbee Modules
The Xbee modules are used for communication between the sender and receiver. They use IEEE 802.15.4 protocol, and can be effective in a circular range of 100 yards. To setup the Xbee module, you need to connect both of them on breakout boards, and connect to PC terminal. You may also need to download XCTU and Teraterm for correct setup and debugging, here is the tutorials: https://www.digi.com/products/xbee-rf-solutions/xctu-software/xctu https://osdn.net/projects/ttssh2/releases/
Emic2 Text-to-Speech Converter
The Emic2 Text-to-speech Converter is used on the vehicle, and is powered by mbed. This modules acts as a driver to control the speaker, and is able to make 9 different voices in 3 different languages.
H-bridge Motor Driver
This module is used to power the motors of the vehicle.
Distance Sensor
We are also using VL53L0x distance sensor to detect any incoming objects. The distance sensor will detect obstacles in front of the vehicle, and it the distance is less than 20cm, the vehicle will start to randomly turn(left or right). When it finds a direction with no obstacles, the vehicle will stop the motion.
Flex Sensors
The flex sensors used in the glove will detect bendings in the user's fingers. After it is bent the resistance value will change, resulting in a different analog input voltage. https://os.mbed.com/components/Flex-Sensor/ The flex sensors are only sensitive enough when connected in series with a 10K ohm resistor. Using a resistor of much lower resistance will greatly reduce the accuracy and introduce a lot of noises.
Heat Sensor
We are using TMP36 analog temperature sensor. The schematics for connecting can be found in the official website.
uLCD screen
The uLCD screen can display and visualize the temperature in the surroundings. The introduction scene will display several lines of text including "ECE 4180"
Functionality
There are two functional parts in our project: Glove and Vehicle
Glove
The glove, which acts as a controller, allows user to directly interfacing with the vehicle, more specifically, the vehicle will receive inputs of 5 commands in our current code, including forward(pinky), backward(ring finger), left(middle finger), right(index finger) and stop(thumb) upon bending or curvature of the fingers, the Mbed will be able to collect the signal and identify the correct finger. Then, upon successful completion of the identification procedure, it will fire a command via Xbee module.
Vehicle
The vehicle receives command from glove, and performs the corresponding action accordingly. It can pronounce "left" or "right" when it's turning after receiving a command, or "stop" if it is commanded to stop from its current motion.
Code Snippet
Glove Code
Import programTransmitter
This code will be implemented on the receiving end of the device, which contains a speaker, an Emic2 text-to-speech converter, as well as a vehicle module that can move or rotate upon request
Code used by glove Mbed
#include "mbed.h" #include "emic2.h" #include "uLCD_4DGL.h" #include<string> using namespace std; //serial RX,TX pins to emic uLCD_4DGL uLCD(p28,p27,p5); // serial tx, serial rx, reset pin; #define length_sprite 20 #define width_sprite 75 #define width_sprite2 47 #define length_sprite2 18 #define Q 0x808000 //OLIVE #define I 0x008000 //GREEN #define S 0xC0C0C0 //SILVER #define R 0xF1C40F //YELLOW #define O 0xF39C12 //ORANGE #define X 0xFFFFFF //WHITE #define B 0x0000FF //BLUE #define G 0xAAB7B8 //GREY #define D 0x797D7F //DARK GREY #define L 0x00FF00 //LIME #define P 0xFF00FF //K #define _ 0x000000 //BLACK #define r 0xFF0000 //RED class TMP36{ public: TMP36(PinName pin); TMP36(); float read(); private: //class sets up the AnalogIn pin AnalogIn _pin; }; TMP36::TMP36(PinName pin) : _pin(pin) {} //This is an initializer list float TMP36::read() { //convert sensor reading to temperature in degrees C return ((_pin.read()*3.3)-0.500)*100.0; //read() function returns a normalized value of the voltage from 0 to 1 as a float } //instantiate new class to set p15 to analog input //to read and convert TMP36 sensor's voltage output } TMP36 myTMP36(p20); // analog in pin for temp sensor // make 3 different sprites // decrease the sprite dimensions to increasing processing speed // for the glove sprite appearing in the beginning int Glove[length_sprite*width_sprite] = { _,_,_,_,R,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,R,_,S,S,S,S,S,S,_,O,_,_,_,_,_,r,r,r,r,r,_,D,D,D,D,D,D,_,I,I,_,_,_,_,_,_,_,I,I,_,R,R,R,R,R,R,_,_,_,_,_,_, _,_,_,_,_,R,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,R,_,_,S,_,_,_,_,_,_,O,_,_,_,_,_,r,_,_,_,_,_,D,_,_,_,_,D,_,I,_,I,_,_,_,_,_,I,_,I,_,R,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,R,_,_,_,_,_,R,R,_,_,_,_,_,_,R,_,_,_,S,_,_,_,_,_,_,O,_,_,_,_,_,r,_,_,_,_,_,D,_,_,_,_,D,_,I,_,_,I,_,_,_,I,_,_,I,_,R,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,R,_,_,_,R,_,_,R,_,_,_,_,R,_,_,_,_,S,S,S,S,_,_,_,O,_,_,_,_,_,r,_,_,_,_,_,D,_,_,_,_,D,_,I,_,_,_,I,_,I,_,_,_,I,_,R,R,R,R,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,R,_,R,_,_,_,_,R,_,_,R,_,_,_,_,_,S,_,_,_,_,_,_,O,_,_,_,_,_,r,_,_,_,_,_,D,_,_,_,_,D,_,I,_,_,_,_,I,_,_,_,_,I,_,R,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,R,_,_,_,_,_,_,R,R,_,_,_,_,_,_,S,_,_,_,_,_,_,O,_,_,_,_,_,r,_,_,_,_,_,D,_,_,_,_,D,_,I,_,_,_,_,_,_,_,_,_,I,_,R,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,S,S,S,S,S,S,_,O,O,O,O,O,_,r,r,r,r,r,_,D,D,D,D,D,D,_,I,_,_,_,_,_,_,_,_,_,I,_,R,R,R,R,R,R,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,G,G,G,G,G,G,G,G,_,_,B,B,B,B,B,B,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,_,_,_,_,_,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,G,_,_,_,_,_,_,B,B,B,B,B,B,B,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, }; int Fourty_One_Eighty[width_sprite2*length_sprite2]= { _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,G,G,G,G,G,G,G,G,_,_,_,B,B,B,B,B,B,B,B,B,_, _,_,_,_,_,_,_,_,_,_,_,L,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,L,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,L,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,L,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,L,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,L,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,L,L,L,L,L,L,L,L,_,_,_,_,O,O,O,_,_,_,_,_,G,G,G,G,G,G,G,G,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,G,G,G,G,G,G,G,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,_,_,_,_,_,_,_,G,_,_,_,B,_,_,_,_,_,_,_,B,_, _,_,_,_,_,_,_,_,_,_,_,_,L,_,_,_,_,O,O,O,_,_,_,_,_,G,G,G,G,G,G,G,G,G,_,_,_,B,B,B,B,B,B,B,B,B,_, _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, }; Serial xbee1(p9,p10); DigitalOut rst1(p11); DigitalOut myled1(LED1); DigitalOut myled2(LED2); DigitalOut myled3(LED3); DigitalOut myled4(LED4); //emic2 myTTS(p13, p14); AnalogIn a1(p15); AnalogIn a2(p16); AnalogIn a3(p17); AnalogIn a4(p18); AnalogIn a5(p19); Serial pc(USBTX, USBRX); float i1; float i2; float i3; float i4; float i5; float ref1; float ref2; float ref3; float ref4; float ref5; float avg1; float avg2; float avg3; float avg4; float avg5; float diff1, diff2, diff3, diff4, diff5; int counter; float sum; int main() { float tempC, tempF; int i = 0; uLCD.BLIT(30,30,width_sprite, length_sprite, Glove); wait(1); uLCD.cls(); uLCD.BLIT(30,30, width_sprite2, length_sprite2, Fourty_One_Eighty); wait(1.0); for (unsigned int j = 0; j <= 128; j+=7){ // DRAW ---- animation of walls uLCD.line(j,127,j+7,0,RED); // horizontal animation uLCD.line(j+1, 127, j+8, 0, RED); uLCD.line(127 - j, 0, 127 - (j+7), 127, BLUE); uLCD.line(127-j-1,0,127 - (j+8), 127, BLUE); // Erase wait(.1); uLCD.line(j,127,j+7,0,BLACK); uLCD.line(j+1, 127, j+8, 0, BLACK); uLCD.line(127 - j, 0, 127 - (j+7), 127, BLACK); // vertical animation uLCD.line(127-j-1,0,127 - (j+8), 127, BLACK); } uLCD.cls(); ref1 = 0; ref2 = 0; ref3 = 0; ref4 = 0; ref5 = 0; counter = 0; rst1 = 0; wait_ms(1); rst1 = 1; wait_ms(1); char o; while(1) { wait(0.5); i1 = a1; i2 = a2; i3 = a3; i4 = a4; i5 = a5; ref1 += i1; ref2 += i2; ref3 += i3; ref4 += i4; ref5 += i5; avg1 = ref1 / counter; avg2 = ref2 / counter; avg3 = ref3 / counter; avg4 = ref4 / counter; avg5 = ref5 / counter; o = 'I'; myled1 = 0; myled2 = 0; myled3 = 0; myled4 = 0; diff1 = i1 - avg1; diff2 = i2 - avg2; diff3 = i3 - avg3; diff4 = i4 - avg4; diff5 = i5 - avg5; if (diff1 > 0.01) { o = 'A'; ref1 -= i1; myled1 = 1; } else if (diff2 > 0.01) { o = 'B'; ref2 -= i2; myled2 = 1; } else if (diff3 > 0.01) { o = 'C'; ref3 -= i3; myled3 = 1; } else if (diff4 > 0.01) { o = 'D'; ref4 -= i4; myled4 = 1; } else if (diff5 > 0.01) { o = 'E'; ref5 -= i5; myled1 = 1; myled2 = 1; } else { counter++; } xbee1.putc(o); pc.printf("%4.2f, %4.2f\r\n", avg4, diff4); uLCD.filled_circle(63,63,63, 0x0000ff); uLCD.baudrate(3000000); //uLCD.set_font_size(3,3); /* uLCD.text_char('B', 9, 8, BLACK); uLCD.text_char('I',10, 8, BLACK); uLCD.text_char('G',11, 8, BLACK); uLCD.text_italic(ON); */ if (i == 0){ uLCD.locate(40,40); uLCD.text_italic(ON); uLCD.text_string("Welcome to 4180", 0, 5, FONT_7X8, WHITE); uLCD.text_italic(ON); wait(0.2); uLCD.cls(); uLCD.text_string("Final", 0, 9, FONT_7X8, WHITE); uLCD.text_string("Project", 0, 11, FONT_7X8, WHITE); i++; uLCD.cls(); uLCD.filled_circle(63,63,63, 0x0000ff); wait(0.2); } tempC = myTMP36.read(); //convert to degrees F tempF = (9.0*tempC)/5.0 + 32.0; //print current temp uLCD.locate(0,0); uLCD.printf("%5.2f C %5.2f F \n\r", tempC, tempF); uLCD.filled_rectangle(40, 127, 50, 127 - 2*tempC , 0xFF0000); // MAX- Celcius 64 for celcius bar uLCD.filled_rectangle(60, 127, 70, 127 - tempF, 0xFFFF00); // MAX- farenheit yellow for farenheit bar wait(0.2); // uLCD.cls(); uLCD.filled_rectangle(0,0,127, 7, 0x000000); uLCD.filled_circle(63,63,63, 0x0000ff); uLCD.filled_rectangle(40, 127, 50, 127 - 2*tempC , 0x000000); // ERASE uLCD.filled_rectangle(60, 127, 70, 127 - tempF, 0x000000); // MAX- farenheit yellow for farenheit bar } }
Vehicle Code
Import programReceiver
receiver code which helps the vehicle to move forward, backward, left and right
Code used by vehicle Mbed powered by Motor and Xbee receiver
#include "Motor.h" #include "mbed.h" #include "emic2.h" #include "XNucleo53L0A1.h" #include <stdio.h> #include "rtos.h" Serial pc(USBTX, USBRX); DigitalOut shdn(p26); AnalogOut led(p18); //I2C sensor pins #define VL53L0_I2C_SDA p28 #define VL53L0_I2C_SCL p27 static XNucleo53L0A1 *board=NULL; emic2 myTTS(p13, p14); Serial xbee1(p9, p10); DigitalOut rst1(p11); Motor B(p23, p6, p5); // pwm, fwd, rev, can brake, right Motor A(p24, p7, p8); // left motor char input; int counter; int direction; int main() { //initialize distance sensor int status; uint32_t distance; DevI2C *device_i2c = new DevI2C(VL53L0_I2C_SDA, VL53L0_I2C_SCL); /* creates the 53L0A1 expansion board singleton obj */ board = XNucleo53L0A1::instance(device_i2c, A2, D8, D2); shdn = 0; //must reset sensor for an mbed reset to work wait(0.1); shdn = 1; wait(0.1); /* init the 53L0A1 board with default values */ status = board->init_board(); while (status) { pc.printf("Failed to init board! \r\n"); status = board->init_board(); } counter = 0; // reset the xbees (at least 200ns) rst1 = 0; wait_ms(1); rst1 = 1; wait_ms(1); input = 'I'; A.speed(0); B.speed(0); wait(2); direction = 1; while(1) { if(xbee1.readable()) { input = xbee1.getc(); wait(0.2); } status = board->sensor_centre->get_distance(&distance); if (status == VL53L0X_ERROR_NONE) { pc.printf("D=%ld mm\r\n", distance); } while (distance < 200) { direction = rand()*100; if (direction > 50) { A.speed(-0.5); B.speed(-0.5); led = 0; wait(0.1); } else { A.speed(0.5); B.speed(0.5); led = 1; wait(0.1); } status = board->sensor_centre->get_distance(&distance); led = 0; A.speed(0); B.speed(0); } if (input == 'A') { //myTTS.speakf("S");//Speak command starts with "S" //myTTS.speakf("forward"); //myTTS.speakf("\r"); //marks end of speak command //myTTS.ready(); A.speed(-0.5); B.speed(0.5); wait(0.2); } else if (input == 'B') { //myTTS.speakf("S");//Speak command starts with "S" //myTTS.speakf("back"); //myTTS.speakf("\r"); //marks end of speak command //myTTS.ready(); A.speed(0.5); B.speed(-0.5); wait(0.2); } else if (input == 'C') { myTTS.speakf("S");//Speak command starts with "S" myTTS.speakf("left"); myTTS.speakf("\r"); //marks end of speak command myTTS.ready(); A.speed(0.5); B.speed(0.5); wait(0.2); } else if (input == 'D') { myTTS.speakf("S");//Speak command starts with "S" myTTS.speakf("right"); myTTS.speakf("\r"); //marks end of speak command myTTS.ready(); A.speed(-0.5); B.speed(-0.5); wait(0.2); } else if (input == 'E') { myTTS.speakf("S");//Speak command starts with "S" myTTS.speakf("stop"); myTTS.speakf("\r"); //marks end of speak command myTTS.ready(); A.speed(0); B.speed(0); wait(0.2); } } }
Camera Code
Left Side Picture
Middle Picture
Right Side Picture
Code used for Raspberry Pi Zero in taking pictures
# Camera Code # Author: Animesh Patel 12/11/2018 import picamera from time import sleep import sys camera = picamera.PiCamera() powerOn = 1 # Servo default position: left side camera_side_current = "left" camera_side_next = "center" counter = 1 while powerOn: if camera_side_current == "left": print("picture from left side\n") camera_side_next = "center" elif camera_side_current == "center": print("picture from center side\n") camera_side_next = "right" elif camera_side_current == "right": print("picture from right side\n") camera_side_next = "left" sleep(.5) camera.start_preview() sleep(.5) camera.stop_preview() if camera_side_current == "left": camera.capture('/home/pi/Desktop/Pictures/Left_Side_%s.jpg' %counter) elif camera_side_current == "center": camera.capture('/home/pi/Desktop/Pictures/Center_Side_%s.jpg' %counter) elif camera_side_current == "right": camera.capture('/home/pi/Desktop/Pictures/Right_Side_%s.jpg' %counter) print('done with ' + camera_side_current + ' side\n') sleep(1.5) camera_side_current = camera_side_next if camera_side_current == "left": counter = counter + 1 sleep(2.5)
Project Schematic
Control Scheme
The glove currently has 5 commands: forward(pinky), backward(ring finger), left(middle finger), right(index finger), and thumb.
By bending the fingers, the flex sensors data will change. The Mbed will detect that change and propagate the signals by Xbee module. The Xbee module on the vehicle side will receive the signal and reports to another Mbed which is connected to the power pack. The Mbed will change the motion of the vehicle accordingly as well as pronouncing the motion with the assistance of the text-to-speech converter.
The vehicle also detects obstacles in front of it by distance sensor, and if the obstacle is in vicinity( < 20cm), the vehicle will stop and try to turn away.
The Raspberry Pi camera is constantly rotating from left to right and taking pictures at 3 positions(left, middle and right). The pictures taken will be stored in a microSD card for acquisition and image processing.
Project Demo
Future Improvements
Packaging
The vehicle consists of a breadboard on top of a Magician Bot chassis. In the future we decide to 3D print a transparent, plastic casing to hide all the ugly wirings. The wirings can be also be replaced with PCBs.
Finishing Imaging Processing Features
We spent a lot of time in setting up camera module on Raspberry Pi Zero, and due to some minor technical issues we are currently unable to import openCV library onto Raspberry Pi. However, we already have the code for edge detection working on our PCs. Once openCV importation issue is fixed, we can add object recognition features.
Below is the Python code with openCV working
Raspberry Pi camera with openCV
import picamera #import cv2 #import numpy as np #from matplotlib import pyplot as plt from time import sleep import sys from skimage import io from skimage import feature camera = picamera.picamera() powerOn = 1 camera_side_current = "left" camera_side_next = "center" counter = 1 while (powerOn and counter < 3): camera.start_preview() if camera_side_current == "left": print("picture from left side\n") camera_side_next = "center" elif camera_side_current == "center": print("picture from center side\n") camera_side_next = "right" elif camera_side_current == "right": print("picture from right side\n") camera_side_next = "left" sleep(.3) camera.stop_preview() #sleep(1.7) if camera_side_current == "left": camera.capture('/home/pi/Desktop/Pictures/Left_Side_%s.jpg' %counter) image = io.imread('/home/pi/Desktop/Pictures/Left_Side_%s.jpg') elif camera_side_current == "center": camera.capture('/home/pi/Desktop/Pictures/Center_Side_%s.jpg' %counter) image = io.imread('/home/pi/Desktop/Pictures/Center_Side_%s.jpg') elif camera_side_current == "right": camera.capture('/home/pi/Desktop/Pictures/Right_Side_%s.jpg' %counter) image = io.imread('/home/pi/Desktop/Pictures/Right_Side_%s.jpg') print('done with ' + camera_side_current + ' side\n') edge = feature.canny(image) io.imshow(edge) io.show() sleep(1.7) camera_side_current = camera_side_next if camera_side_current == "left": counter = counter + 1 sleep(3)
Communication between MCUs
It would be much better if we can make different microcontrollers on the vehicle communicate with each other. For example, the camera which is controlled by Raspberry Pi Zero can provide information for the Mbed connected to the power pack, and alter the vehicle's motion accordingly. We even plan to add more Xbee modules on multiple vehicles and setup a network among them, so each vehicle is able to inform all the others about the obstacles in front of it.
Smart Lighting
Turns on the lights depending on the certain threshold of RGB values from images and turns off for bright enough environment.
Implementing Multi-threading
The vehicle can use Mbed rtos library to implement multi-threading. As a result, the Mbed can utilize its processing power more efficiently.
Incorporating AR/VR, and IMU control
We are planning to add IMU motion sensors to the glove and use sensor fusion to provide more accurate control of the vehicle. We also consider the addition of AR/VR to allow the user to visualize cart movements in a gaming-like environment in addition to sound effects involving cart screeching, accelerating, turning, etc.
Adding PID Control for the motors
We do not have a Hall sensor in our motors, and currently unable to keep the vehicle moving in a straight line. In the future, we plan to mount Halls sensors to and implement PID control system to maintain the vehicle's course.
Github Repository
Please log in to post comments.