Voice Controlled Car

1,262

18

3

Posted in TechnologyRobots

Introduction: Voice Controlled Car

About: I like to learn, like to make, like to share.

In this instructable, I am going to show and explain the recipe of my voice controlled robot car. I used Amazon Alexa for voice command. I developed a custom skill for the robot. When you say, "Alexa, drive the car forward" or "turn right" Alexa trigger the AWS Lambda and Lambda function sends a command to an MQTT server. For making the car I used Arduino Uno and Raspberry Pi. Raspberry Pi receives the MQTT message from the server and sends it to Arduino using the USB port. Arduino controls the motor according to the received command. In the next few steps, I will show all the involved task step by step. So, keep reading. Before going the next step please enjoy the video.

Demo Video

Voice Activated Challenge

Runner Up in the
Voice Activated Challenge

Step 1: Bill of Materials

1. Arduino Uno (seeedstudio.com) or Seeeduino only $6.9( seeedstudio.com)

2. Raspberry Pi (any version) ( Seeedstudio.com)

3. Arduino Motor Shield ( seeedstudio.com)

4. 2WD Robot Chassis (any model) ( pololu.com)

5. 2000mAh Li-ion Battery and Boost Converter Module ( pololu.com)

6. Amazon Echo or Echo Dot (amazon.com)

Tools

1. Soldering Iron

2. Multimeter

3. Screwdriver

Step 2: Build Your Chassis

If you bought a readymade chassis you can escape this step. Here, I added some picture how I made the chassis from an ebonite board. I used one ball caster and two small sizes DC gear motor for the chassis. DC geared motors are fixed to the bottom plate using supper glow.

Why Ball Caster?
The wheel is the most common moving element among other possibilities including legs, flying, swimming and rolling. A wheel provides at least speed, accuracy, and stability for a robot, three characteristics very important in designing and building robots. Finding inspiration in everything, the researchers design many types of wheels including standard, orientable, ball, and omnidirectional wheels. Depending on the design and requirements, standard wheels are used especially for classical methods of driving and steering while orientable and ball wheels are included in the same category and user for balancing a robot. A ball caster is a type of 'wheel' that allows smooth movement in all directions. Ball caster works as omnidirectional wheels and are very good for driving and steering and are used when the robot should have the ability to move in all directions. The ball can be built from metal or plastic and is positioned on the frame with a holder.

Why DC Geared Motor?

The speed of the motor is counted in terms of rotations of the shaft per minute and is termed as RPM. Another important parameter of a motor is torque. Torque is a force for which rotor or shaft rotates. The more the torque, the shaft can rotate with more load. Generally, a DC motor run with a high speed and low torque which is not perfect for robotics applications. Most robots required high torque with a low speed. The gear assembly helps in increasing the torque and reducing the speed. Using the correct combination of gears in a gear motor, its speed can be reduced to any desirable figure. This concept where gears reduce the speed of the vehicle but increase its torque is known as gear reduction.

To know more please visit my previous Instructables about robot car.

Step 3: Creating Custom Alexa Skill (Part 1)

For controlling your robot using Alexa you will be required a custom Alexa Skill and the big hope is that building your own Alexa Skill is very easy. For building a custom skill you need to register Amazon Developer Site. After registering log into the account and select Alexa Skills Kit. Follow the pictures attached to the step.

For the Intent Schema use the following JSON code:

{
  "intents": [
    {
      "slots": [
        {
          "name": "Direction",
          "type": "LIST_OF_DIRECTIONS"
        },
        {
          "name": "Turn",
          "type": "LIST_OF_TURNS"
        },
        {
          "name": "Speed",
          "type": "AMAZON.NUMBER"
        }
      ],
      "intent": "CarIntent"
    },
    {
      "slots": [
        {
          "name": "Color",
          "type": "LIST_OF_COLORS"
        }
      ],
      "intent": "LightIntent"
    },
    {
      "slots": [
        {
          "name": "stop",
          "type": "STOP"
        }
      ],
      "intent": "StopIntent"
    },
    {
      "intent": "SupportedDirectionsIntent"
    },
    {
      "intent": "SupportedTurnsIntent"
    },
    {
      "intent": "SupportedColorsIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}

From the custom slot types section add 4 slots named as LIST_OF_DIRECTIONS, LIST_OF_TURNS, LIST_OF_COLORS, STOP and set the values accordingly. For example, for the LIST_OF_DIRECTIONS you can add straight | forward | backward | reverse | back etc.

For Sample Utterances, you can use following sample code and some from your own mind.

CarIntent go {Direction}
CarIntent move the car {Direction}
CarIntent drive the car {Direction}
CarIntent make the car go {Direction}
CarIntent turn {Turn}
CarIntent turn car {Turn}
CarIntent turn the car {Turn}
CarIntent set speed {Speed} percent
CarIntent adjust speed {Speed} percent
CarIntent fix speed {Speed} percent
LightIntent change light color to {Color}
LightIntent change the car's lights to {Color}
LightIntent make the car's lights {Color}
LightIntent change lights to {Color}
LightIntent turn the lights to {Color}
StopIntent {stop} car
StopIntent {stop} car now
StopIntent make car {stop}
StopIntent make car {stop} now
StopIntent {stop} the car
StopIntent {stop} the car now
StopIntent make the car {stop}
StopIntent make the car {stop} now
SupportedDirectionsIntent supported directions
SupportedDirectionsIntent what are the supported directions
SupportedDirectionsIntent what are all the supported directions
SupportedDirectionsIntent what are all supported directions
SupportedDirectionsIntent tell me all the supported directions
SupportedDirectionsIntent tell me all supported directions
SupportedDirectionsIntent tell me the supported directions
SupportedDirectionsIntent list supported directions
SupportedDirectionsIntent list all supported directions
SupportedDirectionsIntent list me the supported directions
SupportedDirectionsIntent list me all supported directions
SupportedDirectionsIntent list me all the supported directions
SupportedDirectionsIntent list to me the supported directions
SupportedDirectionsIntent list to me all supported directions
SupportedDirectionsIntent list to me all the supported directions
SupportedDirectionsIntent give supported directions
SupportedDirectionsIntent give all supported directions
SupportedDirectionsIntent give me the supported directions
SupportedDirectionsIntent give me all supported directions
SupportedDirectionsIntent give me all the supported directions
SupportedDirectionsIntent give to me the supported directions
SupportedDirectionsIntent give to me all supported directions
SupportedDirectionsIntent give to me all the supported directions
SupportedTurnsIntent supported turns
SupportedTurnsIntent what are the supported turns
SupportedTurnsIntent what are all the supported turns
SupportedTurnsIntent what are all supported turns
SupportedTurnsIntent tell me all the supported turns
SupportedTurnsIntent tell me all supported turns
SupportedTurnsIntent tell me the supported turns
SupportedTurnsIntent list supported turns
SupportedTurnsIntent list all supported turns
SupportedTurnsIntent list me the supported turns
SupportedTurnsIntent list me all supported turns
SupportedTurnsIntent list me all the supported turns
SupportedTurnsIntent list to me the supported turns
SupportedTurnsIntent list to me all supported turns
SupportedTurnsIntent list to me all the supported turns
SupportedTurnsIntent give supported turns
SupportedTurnsIntent give all supported turns
SupportedTurnsIntent give me the supported turns
SupportedTurnsIntent give me all supported turns
SupportedTurnsIntent give me all the supported turns
SupportedTurnsIntent give to me the supported turns
SupportedTurnsIntent give to me all supported turns
SupportedTurnsIntent give to me all the supported turns
SupportedColorsIntent supported colors
SupportedColorsIntent what are the supported colors
SupportedColorsIntent what are all the supported colors
SupportedColorsIntent what are all supported colors
SupportedColorsIntent tell me all the supported colors
SupportedColorsIntent tell me all supported colors
SupportedColorsIntent tell me the supported colors
SupportedColorsIntent list supported colors
SupportedColorsIntent list all supported colors
SupportedColorsIntent list me the supported colors
SupportedColorsIntent list me all supported colors
SupportedColorsIntent list me all the supported colors
SupportedColorsIntent list to me the supported colors
SupportedColorsIntent list to me all supported colors
SupportedColorsIntent list to me all the supported colors
SupportedColorsIntent give supported colors
SupportedColorsIntent give all supported colors
SupportedColorsIntent give me the supported colors
SupportedColorsIntent give me all supported colors
SupportedColorsIntent give me all the supported colors
SupportedColorsIntent give to me the supported colors
SupportedColorsIntent give to me all supported colors
SupportedColorsIntent give to me all the supported colors

Then click on save and then next to go to next step. In this stage, you will be required an Endpoint and for this field, we will use AWS Lambda ARN (Amazon Resource Name). To get the ARN you will need to create a Lambda function. To create a Lambda function follow the next step and come back to here after getting ARN.

Step 4: Creating Custom Alexa Skill (Part 2)

For creating a Lambda function you need to log in console.aws.amazon.com. After log in to aws console in from the services tab select Lambda under compute tab. Then follow the images to create a Lambda function. Carefully note the red mark in the images. After getting the ARN go back to Alexa Skil section and paste the ARN to the Default Endpoint box and come back here.

Welcome back, now you need to upload the code for Lambda function. For the Lambda you need some modification. We will upload code in lambda for communication with MQTT server. You should put MQTT username and password in the appropriate place in Lambda function. You should also place your Alexa app id. You can change these parameters in two ways. First, upload the vBotLambda.zip to the aws Lambda and then change the index.js from the edit code inline option. You can also change the code before uploading. To do it, unzip the file and make appropriate change in the index.js file. Then add the modified file to a zip archive and upload it to AWS Lambda.

/**
 * Alexa voice home automation
 * Developed by Md. Khairul Alam
 * Date: 25 August, 2016
 * Updated on 5 May, 2017
 */
var mqtt    = require('mqtt');
var client = mqtt.createClient(15708,"m12.cloudmqtt.com", //you may require to change port#
    {
        username: "your mqtt user name from CloudMQTT",
        password: "your mqtt password from CloudMQTT"<br>    });
    
var app_id = "place the ID from Alexa Skill Kit here" //id from your alexa skill

var ctx = null;

// Route the incoming request based on type (LaunchRequest, IntentRequest, etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
    try {
        console.log("event.session.application.applicationId=" + event.session.application.applicationId);
        ctx = context;

        if (event.session.application.applicationId !== app_id) {
             ctx.fail("Invalid Application ID");
         }    
        if (event.session.new) {
            onSessionStarted({requestId: event.request.requestId}, event.session);
        }
        if (event.request.type === "LaunchRequest") {
            onLaunch(event.request, event.session);
        }  else if (event.request.type === "IntentRequest") {
            onIntent(event.request, event.session);
        } else if (event.request.type === "SessionEndedRequest") {
            onSessionEnded(event.request, event.session);
            ctx.succeed();
        }
    } catch (e) {
        console.log("EXCEPTION in handler:  " + e);
        ctx.fail("Exception: " + e);
    }
};

/**
 * Called when the session starts.
 */
function onSessionStarted(sessionStartedRequest, session) {
    console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId + ", sessionId=" + session.sessionId);
}

/**
 * Called when the user launches the skill without specifying what they want.
 */
function onLaunch(launchRequest, session, callback) {
    console.log("onLaunch requestId=" + launchRequest.requestId + ", sessionId=" + session.sessionId);

    // Dispatch to your skill's launch.
    getWelcomeResponse(callback);
}

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session ) {                  //, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId + ", sessionId=" + session.sessionId);

    var intent = intentRequest.intent,
    intentName = intentRequest.intent.name;

    console.log("REQUEST to string =" + JSON.stringify(intentRequest));
    var callback = null;   
    if ("CarIntent" === intentName) {
			
		// Determine if this is for Turn, for Direction, for Speed, or an error.
        var directionSlot = intent.slots.Direction,
			speedSlot = intent.slots.Speed,
			turnSlot = intent.slots.Turn,
			turnValue,
			directionValue,
			speedValue;

		if (turnSlot && turnSlot.value) { 
			turnValue = turnSlot.value.toLowerCase();
			
		    client.publish('taifur/vbot', turnValue, function(){
			var cardTitle = "Turnning";
			var repromptText = "What's next?";
			var sessionAttributes = {};
			var shouldEndSession = false;
			var speechOutput = "Turning " + turnValue + ". " + repromptText;
			//var shouldEndSession = true;
			ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
		    //client.end();
		    });  
		   
        }else if (directionSlot && directionSlot.value) { 
			directionValue = directionSlot.value.toLowerCase();
			
            client.publish('taifur/vbot', directionValue, function(){
			var cardTitle = "Going";
			var repromptText = "What's next?";
			var sessionAttributes = {};
			var shouldEndSession = false;
			var speechOutput = "Going " + directionValue +". " + repromptText;
			//var shouldEndSession = true;
			ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
		    //client.end();
            }); 
		    
        }else if (speedSlot && speedSlot.value) { 
			speedValue = speedSlot.value.toLowerCase();
			
		    client.publish('taifur/vbot', speedValue, function(){
			var cardTitle = "Setting Speed";
			var repromptText = "What's next?";
			var sessionAttributes = {};
			var shouldEndSession = false;
			var speechOutput = "Set speed to" + speedValue+ "percent. " + repromptText;
			//var shouldEndSession = true;
			ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
		    });  
		   
        }else { //If error
            //handleNoSlotRequest(response);
        }
		
    }else if ("LightIntent" === intentName) {
        
        var colorSlot = intent.slots.Color,
			colorValue;
			
		if (colorSlot && colorSlot.value) { 
			colorValue = colorSlot.value.toLowerCase();
			
		    client.publish('taifur/vbot', colorValue, function(){
			var cardTitle = "Making ";
			var repromptText = " What's next?";
			var sessionAttributes = {};
			var shouldEndSession = false;
			var speechOutput = "Made color " + colorValue + ". "+ repromptText;
			//var shouldEndSession = true;
			ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
		    //client.end();
		    });  
		  
		}
    }else if ("StopIntent" === intentName) {
        
        var stopSlot = intent.slots.stop,
			stopValue;
        
		if (stopSlot && stopSlot.value) { 
			stopValue = stopSlot.value.toLowerCase();
			
		    client.publish('taifur/vbot', stopValue, function(){
			var cardTitle = "Stop";
			var repromptText = " What's next?";
			var sessionAttributes = {};
			var shouldEndSession = false;
			var speechOutput = "Stopped. " + repromptText;
			//var shouldEndSession = true;
			ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
		    //client.end();
		    });  
		}
		
    }else if ("AMAZON.HelpIntent" === intentName) {
        getHelp(callback);
    }else if ("AMAZON.StopIntent" === intentName || "AMAZON.CancelIntent" === intentName) {
        handleSessionEndRequest(callback);
    }else {
        throw "Invalid intent";
    }
}

/**
 * Called when the user ends the session.
 * Is not called when the skill returns shouldEndSession=true.
 */
function onSessionEnded(sessionEndedRequest, session) {
    console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId + ", sessionId=" + session.sessionId);
    // Add cleanup logic here
}

// --------------- Functions that control the skill's behavior -----------------------

function getWelcomeResponse() {
    // If we wanted to initialize the session to have some attributes we could add those here.
    var sessionAttributes = {};
    var cardTitle = "Welcome";
    var speechOutput = "Welcome to the voice controlled car. Just ask me what should I do.";

    var repromptText = "I am ready for your command. For more instructions, please say help me.";
    var shouldEndSession = false;

    ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
}

function getHelp() {
	var sessionAttributes = {};
    var repromptSpeech = "What would you like me to do?";
    var speechOutput = "I can control a toy car. "
        + "To change the car's lights, say something like, change lights to blue. "
		+ "For a list of valid colors, try, what are the available colors. "
        + "To change the car's direction, say something like, go straight. "
		+ "For a list of valid directions, try, what are the available directions. "
		+ "To turn the car, say something like, turn the car right. "
		+ "For a list of valid turns, try, what are the available turns. "
		+ "If you want the car to stop, say something like, stop car. "
        + "If you want to exit, say exit. "
        + repromptSpeech;
	var cardTitle = speechOutput;
    var shouldEndSession = false;

    ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptSpeech, shouldEndSession)));
}

function handleSessionEndRequest() {
	var sessionAttributes = {};
    var cardTitle = "Session Ended";
    var speechOutput = "Thank you for calling me, Have a nice day!";
    var shouldEndSession = true;
	var repromptText = "";
    ctx.succeed(buildResponse(sessionAttributes, buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession)));
}


// --------------- Helpers that build all of the responses -----------------------

function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: "PlainText",
            text: output
        },
        card: {
            type: "Simple",
            title: title,
            content: output
        },
        reprompt: {
            outputSpeech: {
                type: "PlainText",
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    }
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: "1.0",
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    }
}

After uploading the Lambda code successfully you can test it from the test option.

Now, go to the Alexa Skill page again and test the skill from test tab. After testing the skill you can submit it for certification if you like to give access to your skill to others.

Step 5: Create an MQTT Account

MQTT is an easy way for Internet of Things (IoT) devices to communicate with each other. This light-weight protocol can be used with a simple 8-bit Arduino to a Raspberry Pi to a multi-core PC to Amazon Web Services. It is that versatile.

MQTT is a Client Server publish/subscribe messaging transport protocol. It is light weight, open, simple, and designed so as to be easy to implement. These characteristics make it ideal for use in many situations, including constrained environments such as for communication in Machine to Machine (M2M) and Internet of Things (IoT) contexts where a small code footprint is required and/or network bandwidth is at a premium.

[More about MQTT]

For sending and receiving MQTT message you need an MQTT Broker (server). Lots of free cloud servers are available. I am using Cloud MQTT for the purpose. To create an account from CloudMQTT go to the link https://customer.cloudmqtt.com/login and create an account. You may use your Google credentials for login.

After log into the account click on Create New Instance.A new window will open. Put a name in the name field like RobotControl and click on next. You will get some credentials which will be required to log in to the server. We will use this credentials in our code.

Step 6: Prepare Raspberry Pi

We will use Raspberry Pi as MQTT subscriber. When AWS Lambda sent an MQTT message to the server Raspberry Pi will receive it instantly and send it to Arduino. For developing program for raspberry pi I used python. You may also use Node.js like Lambda function. For receiving MQTT message an MQTT client is required. I am using paho mqtt client. To install paho client just type the following command from the terminal:

sudo pip install paho-mqtt

For sending data to Arduino using serial port python serial module is required. To install it in your raspberry pi use the following command:

sudo apt-get install python-serial

If you successfully install both the module you are ready to run the following python program which receives mqtt message from CloudMQTT server and sends it to Arduino.

import paho.mqtt.client as mqtt
import RPi.GPIO as GPIO
import serial

ser = serial.Serial('/dev/ttyACM0',9600)

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

led_pin = 17
GPIO.setup(led_pin,GPIO.OUT)

received_message = ""

# Define event callbacks
def on_connect(client, userdata, flags, rc):
    print("rc: " + str(rc))

def on_message(client, obj, msg):
    received_message = str(msg.payload)
    print(msg.topic + " " + str(msg.qos) + " " + received_message)
    ser.write(received_message)
    ser.write('\n')

def on_publish(client, obj, mid):
    print("mid: " + str(mid))

def on_subscribe(client, obj, mid, granted_qos):
    print("Subscribed: " + str(mid) + " " + str(granted_qos))

def on_log(client, obj, level, string):
    print(string)


client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish
client.on_subscribe = on_subscribe

client.username_pw_set("your user name", "your password")
#client.connect(url.hostname, url.port)

client.connect("m12.cloudmqtt.com", 15708, 60)

# Start subscribe, with QoS level 0
client.subscribe("taifur/vbot", 0)

# Publish a message
client.publish("taifur", "my message")

#client.loop_forever()
rc = 0
while rc == 0:
    rc = client.loop()
print("rc: " + str(rc))

Put your username and password in appropriate location, save the file as mqtt-receive.py and place the file in your raspberry pi /home/pi directory. Run the program using the command:

sudo python mqtt-receive.py

If you will get the output like the image attached above your raspberry pi is successfully connected to the MQTT server and is ready to receive a message from the server. Start the Alexa Skill by saying, 'Alexa, start v bot'. If alexa ask you to give command say "Go forward." Your robot will move forward.

Step 7: Programming Arduino

Arduino will receive the command from the Raspberry Pi and control two DC motor according to the received command. For controlling DC motor Motor driver is required as Arduino pin cannot provide enough current for driving the motor. I am using Adafruit Motor Driver shield for controlling the motors. For compiling the sketch you need Adafruit motor driver library. I attached the library in this step. Add the adamotor.zip to your arduino environment and upload the following code in the arduino board.

#include <AFMotor.h>

AF_DCMotor motor1(3);
AF_DCMotor motor2(4);

String inputString = "";         // a string to hold incoming data
boolean stringComplete = false;  // whether the string is complete

/*
const int red = 5;
const int green = 6;
const int blue = 7;
*/
void setup() {
  // initialize serial:
  Serial.begin(9600);
  // reserve 200 bytes for the inputString:
  inputString.reserve(200);

  motor1.setSpeed(car_speed);
  motor2.setSpeed(car_speed);
 
  motor1.run(RELEASE);
  motor2.run(RELEASE);
  /*
  pinMode(red, OUTPUT);
  pinMode(green, OUTPUT);
  pinMode(blue, OUTPUT);
  */
}

void loop() {
  /*
     LIST_OF_DIRECTIONS straight | forward | backward | reverse | back  Delete  Edit
     LIST_OF_TURNS left | right  Delete  Edit
     LIST_OF_COLORS  red | green | blue | orange | yellow | megenta  Delete  Edit
     STOP  stop | halt | wait | pause
   */
  if (stringComplete) {
    if(inputString == "straight" || inputString == "forward"){
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      delay(25);
      }
    else if(inputString == "backward" || inputString == "reverse" || inputString == "back"){
      motor1.run(BACKWARD);
      motor2.run(BACKWARD);
      delay(25);
      }
    else if(inputString == "left"){
      motor1.run(FORWARD);
      motor2.run(BACKWARD);
      delay(1000);
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      delay(500);
      }
    else if(inputString == "right"){
      motor1.run(BACKWARD);
      motor2.run(FORWARD);
      delay(1000);
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      delay(500);
      }
    else if(inputString == "stop" || inputString == "halt" || inputString == "wait" || inputString == "pause"){
      //car_stop();
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      delay(500);
      }
    /*
    else if(inputString == "red"){
      digitalWrite(red, HIGH);
      digitalWrite(green, LOW);
      digitalWrite(blue, LOW);
      }
    else if(inputString == "green"){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
      digitalWrite(blue, LOW);
      }
    else if(inputString == "blue"){
      digitalWrite(red, LOW);
      digitalWrite(green, LOW);
      digitalWrite(blue, HIGH);
      }
    else if(inputString == "orange"){
      digitalWrite(red, LOW);
      digitalWrite(green, HIGH);
      digitalWrite(blue, HIGH);
      }
    else if(inputString == "yellow"){
      digitalWrite(red, HIGH);
      digitalWrite(green, HIGH);
      digitalWrite(blue, LOW);
      }
    else if(inputString == "megenta"){
      digitalWrite(red, HIGH);
      digitalWrite(green, LOW);
      digitalWrite(blue, HIGH);
      }
      */  
    else if(inputString.endsWith("0")){
      int val = inputString.toInt();
      car_speed = map(val, 0, 100, 0, 255);
      //lcd.clear();
      //lcd.print(car_speed);
      motor1.setSpeed(car_speed);
      motor2.setSpeed(car_speed+12);
      }   
    // clear the string:
    inputString = "";
    stringComplete = false;
  }
}

/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */

void serialEvent() {
  while (Serial.available()) {    
    // get the new byte:
    char inChar = (char)Serial.read();     
    // if the incoming character is a newline, set a flag
    // so the main loop can do something about it:
    if (inChar == '\n') {
      stringComplete = true;
    }
    else
    // add it to the inputString:  
      inputString += inChar;
  }
}

Step 8: Connecting All the Things Together

If you followed all the step you are ready with a raspberry pi with the uploaded python program, arduino with the uploaded sketch and a working custom Alexa skill. Now, you need to connect all the staffs together. Attache the motor shield with the Arduino board. Then connect the motors. Provide the power to the motor shield from an external power supply. I used Li-ion battery and boost converter module to provide 9V to the shield.

Finally, connect raspberry pi and arduino by an arduino cable.

Share

    Recommendations

    • Spotless Contest

      Spotless Contest
    • Microcontroller Contest

      Microcontroller Contest
    • Science of Cooking

      Science of Cooking
    user

    We have a be nice policy.
    Please be positive and constructive.

    Tips

    2 Questions

    0

    It would be OK if you have some hands-on experience with raspberry pi.

    Great Instructable!

    Would it also be possible to send the Commands from the RPi to the Arduino just by connecting RX and TX?

    0

    Yes, it is possible with TX, RX and a common Ground .

    3 Comments

    Thanks.

    Thanks for sharing this looks like a very well documented project!