CONCEPT:
For the final project I was inspired to create an assistive device called “Walking Buddy” – a voice-controlled walking guide. Based on voice commands provided by the user, the robot changes direction and continues to move until the next command. If it encounters an obstacle, the robot stops and warns the user by playing a tune through the speaker. All the interaction involved is through voice and sound making the design inclusive for all users.
IMPLEMENTATION:
The communication begins through P5 where speech library has been used to create a code that infers the voice command and sends relevant data to the Arduino. After receiving the data, the Arduino checks the input received from the ultrasonic sensor, if there is no obstacle detected, it implements the direction of motors according to the command. However, in the presence of an obstacle it sends out a tune to warn the user and stop. Further, the ultrasonic sensor has been mounted on a servo motor which allows it to scan the surroundings before turning left or right. An additional feature that I added involves moving an ellipse in the p5 sketch based on the direction of movement of the robot.
ARDUINO CODE:
#include <Servo.h> #include "pitches.h" #define Echo A0 #define Trig A1 #define motor 10 #define Speed 170 #define spoint 103 const int ain1Pin = 3; const int ain2Pin = 4; const int pwmAPin = 5; const int bin1Pin = 8; const int bin2Pin = 7; const int pwmBPin = 6; // notes in the melody: int melody[] = { NOTE_A3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_A3, NOTE_A3, }; // note durations: 4 = quarter note, 8 = eighth note, etc.: int noteDurations[] = { 4, 4, 4, 4, 4, 4, 4, 4 }; char value; int distance; int Left; int Right; int L = 0; int R = 0; Servo servo; void setup() { Serial.begin(9600); pinMode(Trig, OUTPUT); pinMode(Echo, INPUT); servo.attach(motor); pinMode(ain1Pin, OUTPUT); pinMode(ain2Pin, OUTPUT); pinMode(pwmAPin, OUTPUT); pinMode(bin1Pin, OUTPUT); pinMode(bin2Pin, OUTPUT); pinMode(pwmBPin, OUTPUT); while (Serial.available() <= 0) { digitalWrite(LED_BUILTIN, HIGH); // on/blink while waiting for serial data Serial.println("0"); // send a starting message delay(300); // wait 1/3 second digitalWrite(LED_BUILTIN, LOW); delay(50); } } void loop() { VoiceControl(); } void moveBackward() { analogWrite(pwmAPin, Speed); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, Speed); digitalWrite(bin1Pin, HIGH); digitalWrite(bin2Pin, LOW); } void moveForward() { analogWrite(pwmAPin, Speed); digitalWrite(ain1Pin, LOW); digitalWrite(ain2Pin, HIGH); analogWrite(pwmBPin, Speed); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); } void turnRight() { analogWrite(pwmAPin, Speed); digitalWrite(ain1Pin, HIGH); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, Speed); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, HIGH); } void turnLeft() { analogWrite(pwmAPin, Speed); digitalWrite(ain1Pin, LOW); digitalWrite(ain2Pin, HIGH); analogWrite(pwmBPin, Speed); digitalWrite(bin1Pin, HIGH); digitalWrite(bin2Pin, LOW); } void stopMotors() { analogWrite(pwmAPin, Speed); digitalWrite(ain1Pin, LOW); digitalWrite(ain2Pin, LOW); analogWrite(pwmBPin, Speed); digitalWrite(bin1Pin, LOW); digitalWrite(bin2Pin, LOW); } int ultrasonic() { digitalWrite(Trig, LOW); delayMicroseconds(2); digitalWrite(Trig, HIGH); delayMicroseconds(10); digitalWrite(Trig, LOW); long t = pulseIn(Echo, HIGH); long cm = t * 0.034 / 2;; //time convert distance return cm; } int rightsee() { servo.write(20); delay(800); Left = ultrasonic(); return Left; } int leftsee() { servo.write(180); delay(800); Right = ultrasonic(); return Right; } void VoiceControl() { while (Serial.available()) { digitalWrite(LED_BUILTIN,HIGH); int value = Serial.parseInt(); if (Serial.read() == '\n') { Serial.println(value); distance=ultrasonic(); //Serial.println(distance); if (distance <= 12) { stopMotors(); value=0; for (int thisNote = 0; thisNote < 8; thisNote++) { int noteDuration = 1000 / noteDurations[thisNote]; tone(12, melody[thisNote], noteDuration); int pauseBetweenNotes = noteDuration * 1.30; delay(pauseBetweenNotes); // stop the tone playing: noTone(12); } } if (value == 3) { moveForward(); } else if (value == 4) { moveBackward(); } else if (value == 2) { L = leftsee(); servo.write(spoint); if (L >= 10 ) { turnLeft(); } else if (L < 10) { stopMotors(); } } else if (value == 1) { R = rightsee(); servo.write(spoint); if (R >= 10 ) { turnRight(); } else if (R < 10) { stopMotors(); } } else if (value == 0) { stopMotors(); } } } digitalWrite(LED_BUILTIN,LOW); }
P5 SKETCH AND CODE:
let dir = 0; let robotX, robotY; let img1; let title; let speechRec; function preload(){ img1=loadImage("img.png") title=loadImage("title.png") speakImg=loadImage("speak.png") } function setup() { createCanvas(600, 400); robotX = 460; robotY = 195; let lang = navigator.language || "en-US"; speechRec = new p5.SpeechRec(lang, gotSpeech); let speech = new p5.Speech(); //Checks for the end of text-to-speech conversion speech.onEnd = () => { isSpeaking = false; let continuous = true; let interim = false; speechRec.start(continuous, interim); }; isSpeaking = true; speech.speak('Hi there!,This is your walking buddy. Join me to explore the world on foot. Use the commands Right, Left, Forward, Backward and Stop to navigate the directions. Finally, remember to stop when you hear the siren.') function gotSpeech() { console,log("Speech") if (speechRec.resultValue) { createP(speechRec.resultString); //Conditions to detect the direction command if (speechRec.resultString.toLowerCase().includes("right")) { dir = 1; } else if (speechRec.resultString.toLowerCase().includes("left")) { dir = 2; } else if (speechRec.resultString.toLowerCase().includes("forward")) { dir = 3; } else if (speechRec.resultString.toLowerCase().includes("backward")) { dir = 4; } else if (speechRec.resultString.toLowerCase().includes("stop")) { dir = 0; } } } } function draw() { stroke(0); background("rgb(244,227,68)"); image(img1,30,140,170,260) image(title,30,20,300,180) fill(146,196,248) rect(340,40,240,310) fill(0); ellipse(robotX, robotY, 20, 20); fill(255); textSize(15); if (!serialActive) { text("Press Space Bar to select Serial Port", 340, 380); } else { text("Connected", 3400, 380); } if (dir == 1) { stroke(255, 0, 0); // Red stroke for right } else if (dir == 2) { stroke(0, 255, 0); // Green stroke for left } else if (dir == 3) { stroke(0, 0, 255); // Blue stroke for forward } else if (dir == 4) { stroke(255, 255, 0); // Yellow stroke for backward } else { noStroke(); // No stroke for stop } noFill() strokeWeight(2) ellipse(robotX, robotY, 30, 30); if (dir==1 && robotX < width - 40){ robotX+=0.5 } else if (dir==2 && robotX > 360){ robotX-=0.5 } else if (dir==3 && robotY > 60){ robotY-=0.5 } else if (dir==4 && robotY < height-70 ){ robotY+=0.5 } if (isSpeaking) { image(speakImg, 180, 210, 100, 70); } } function keyPressed() { if (key == " ") { setUpSerial(); } } function readSerial(data) { //////////////////////////////////// //READ FROM ARDUINO HERE //////////////////////////////////// if (data != null) { // make sure there is actually a message // split the message let fromArduino = split(trim(data), ","); // // if the right length, then proceed if (fromArduino.length == 1) { console.log(fromArduino[0]); } ////////////////////////////////// //SEND TO ARDUINO HERE (handshake) ////////////////////////////////// console.log(dir); let sendToArduino= dir + "\n"; writeSerial(sendToArduino); } }
The part of this project that I am proud of is achieving the voice control feature. I used ‘The Coding Train’ youtube tutorials to explore the p5 speech library and implemented both text-to-speech as well as speech-to-text conversions.
Coding Train Tutorial: https://youtu.be/q_bXBcmfTJM
CHALLENGES FACED:
Understanding the direction of movement of the motors was difficult initially but after a few trials I figured out the right code for each direction. Apart from this sending the text obtained from the commands of the user to the arduino did not always work as expected which made it challenging to understand what was wrong.
PROJECT TESTING VIDEOS:
The below videos include the robot following voice commands, detecting an obstacle and p5 screen.
https://drive.google.com/drive/folders/17U0GwIh4A0-HnNlQ5Dn-SARxTF9sP-2-?usp=drive_link
IM SHOW:
The showcase was a wonderful experience to see the creative work of others which also served as a sorce of inspiration for future projects. The concept of my project seemed interesting to people. However, I was encountered with an unanticipated situation where the robot was unable to work due to the detection of multiple sounds.
FURTHER IMPROVEMENT:
Some areas of future improvement would be to design a more efficient communication system with a precise description of the surrounding being conveyed to the user.
After the IM show, I felt that for such a robotic assistive device to be practical it would be necessary to have stronger sound selection to allow it to work even in crowded environments where multiple sounds can be detected.