RC Car controlled using Echo Dot and Sonar Object Detection

This page describes how to use a wifi module to communicate with the echo dot. Using this process, this page also describes how to incorporate this into an RC cop car (see image below). This project was completed with the help of lab partner Ari Bleemer.

Parts Used

Police Car:

https://images-na.ssl-images-amazon.com/images/I/71oZ4oT4oML._SL1500_.jpg

https://www.amazon.com/gp/product/B01KU58SMQ/ref=oh_aui_detailpage_o02_s00?ie=UTF8&psc=1

Wifi Chip:

https://cdn-shop.adafruit.com/970x728/2471-10.jpg

https://www.adafruit.com/product/2471?gclid=Cj0KEQjwuZvIBRD-8Z6B2M2Sy68BEiQAtjYS3FcKfLZdwwYWTf_4KFshe1nKPc1VD89-tK0WrDH6m18aAjbS8P8HAQ

Sonar Module:

http://www.mouser.com/images/sparkfun/images/sen-13959_SPL.jpg

http://www.mouser.com/ProductDetail/SparkFun-Electronics/SEN-13959/?qs=wwacUt%252bV97u8zvpWEUiqvw%3D%3D&gclid=Cj0KEQjwuZvIBRD-8Z6B2M2Sy68BEiQAtjYS3OOepGcR_u3Ny1b6DDnO5cmbn3G4LkO-ocXiCeoXdhgaAhCS8P8HAQ

Encoder:

https://cdn.sparkfun.com//assets/parts/9/3/1/1/12629-01.jpg

https://www.sparkfun.com/products/12629

Amazon Echo Dot:

https://images-na.ssl-images-amazon.com/images/I/61ikAJnULvL._SL1000_.jpg

https://www.amazon.com/Amazon-Echo-Dot-Portable-Bluetooth-Speaker-with-Alexa-Black/dp/B01DFKC2SO/ref=sr_1_1?s=digital-text&ie=UTF8&qid=1493651616&sr=1-1&keywords=echo+dot

Wiring

Picture of the Working Model:

/media/uploads/vceyssens3/img_0205_Nt66qWI.jpg

Wiring Table:

/media/uploads/vceyssens3/pinout.png

The controller for the car strictly uses push buttons for every function. Thus, in order to control the car wires were soldered to the high voltage side of the buttons, and the mbed connects these to GND when needed. A picture of the remote control chip, complete with visible buttons and the on switch, can be seen below. The on switch was by-passed by soldering a wire to the power pin on the normally off side to allow the mbed to turn on the controller. The car itself must be turned on manually. This can be changed, but requires that the car be gutted to find the control board and solder a wire similar to that now on the controller control board. A battery pack was added to the car to allow for power to the mbed and other components while the car is driving around. This can be seen in subsequent pictures and in the video sitting on the hood of the police car.

Car Controller Chip:

/media/uploads/vceyssens3/controller_chip_1.jpg

Amazon Echo Dot

The Echo Dot functions on a custom Amazon Skill and an AWS Lambda function. See the code below for details.

The only way we successfully enabled wireless communication between the Echo Dot and the ESP8266 chip hooked up to the mbed was by using port forwarding on a local, personal router. The Lambda funciton posted to this port, and that information was then directly forwarded to the local IP address of the ESP 8266 chip. This application will not work unless the router has been configured for port forwarding and the ESP 8266 chip is receiving from that router.

Amazon Code

Amazon Skill Intent Schema

{
  "intents": [
    {
      "slots": [
        {
          "name": "Direction",
          "type": "DIRECTION"
        }
      ],
      "intent": "MoveIntent"
    },
    {
      "slots": [
        {
          "name": "Turndir",
          "type": "DIRECTION"
        }
      ],
      "intent": "TurnIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}

DIRECTION was added as a Custom Slot Type with values "forward", "backward", "back", "right", and "left".

Amazon Sample Utterances

MoveIntent move {Direction}
MoveIntent go {Direction}
TurnIntent turn {Turndir}

Amazon Lambda Function

"""
Lambda function for controlling an RC cop car.
"""
 
from __future__ import print_function
import socket
HOST = '73.137.56.212'    # Local host
PORT = 1896               # Arbitrary port chosen
 
 
# --------------- Helpers that build all of the responses ----------------------
  
def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }
 
 
def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }
 
 
# --------------- Functions that control the skill's behavior ------------------
 
def get_welcome_response():
    """
    Welcome message.
    """
 
    session_attributes = {}
    card_title = "Welcome"
    speech_output = "You now get to drive your very own cop car!"
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "Please tell me your command.  For example, say, " \
                    "Move forward."
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))
 
 
def handle_session_end_request():
    """
    Message for ending car control.
    """
    
    card_title = "Session Ended"
    speech_output = "Thanks for protecting the city. " \
                    "Have a great day! "
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))
 
 
def send_move(intent, session):
    """
    Sends move command to mbed. Command in RPC format.
    """
 
    card_title = intent['name']
    session_attributes = {}
    should_end_session = False
    
    if intent['slots']['Direction']['value'] ==  "forward":
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/moveForward/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    elif intent['slots']['Direction']['value'] == 'right':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/turnRight/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close();
        s.connect((HOST, PORT))
        msg = '/moveForward/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    elif intent['slots']['Direction']['value'] == 'left':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/turnLeft/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close();
        s.connect((HOST, PORT))
        msg = '/moveForward/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    elif intent['slots']['Direction']['value'] == 'back' or intent['slots']['Direction']['value'] == 'backward':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/moveBackward/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    else:
        speech_output = "I'm not sure what you said. " \
                    "Please try again."
        reprompt_text = "I'm not sure what you said. " \
                    "Please try again."
    # Builds speech output
    speech_output = "Driving " + intent['slots']['Direction']['value'] + "."
    reprompt_text = "The city isn't going to protect itself."
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))
        
def send_turn(intent, session):
    """
    Sends turn command to mbed in RPC format.
    """
    
    card_title = intent['name']
    session_attributes = {}
    should_end_session = False

    if intent['slots']['Turndir']['value'] == 'right':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/turnRight/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    elif intent['slots']['Turndir']['value'] == 'left':
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((HOST, PORT))
        msg = '/turnLeft/run'
        msg = str(unichr(48+len(msg))) + msg
        s.sendall(msg)
        payload = s.recv(1024)
        s.close()
    else:
        speech_output = "I'm not sure what your command is. " \
                        "Please try again."
        reprompt_text = "I'm not sure what your command is. " \
                        "Please try again."
    # Builds speech output
    speech_output = "Turning " + intent['slots']['Turndir']['value'] + "." 
    reprompt_text = "The city won't protect itself; give me a command."
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))
 
# --------------- Events ------------------
 
def on_session_started(session_started_request, session):
    """ Called when the session starts """
 
    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])
 
 
def on_launch(launch_request, session):
    """ Called when the user launches the skill without a command.
    """
 
    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Go to welcome
    return get_welcome_response()
 
 
def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """
 
    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])
 
    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']
 
    # Dispatch to your skill's intent handlers
    if intent_name == "MoveIntent":
        return send_move(intent, session)
    elif intent_name == "TurnIntent":
        return send_turn(intent, session)
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")
 
 
def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.
 
    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
 
# --------------- Main handler ------------------
 
def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])
 
    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])
 
    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])

mbed Code

mbed Car Control Function

#include "mbed.h"
#include "Car.h"
#include "mywifi.h"
#include "mbed_rpc.h"
#include "ultrasonic.h"

Serial pc(USBTX, USBRX);
Serial esp(p28, p27);
char ssid[32] = "WIFI NAME";
char pwd[32] = "WIFI PASSWORD";
char port[32] = "1896"; // must be port forwarded
char timeout[32] = "28800"; // 28800 is max
volatile int tx_in=0;
volatile int tx_out=0;
volatile int rx_in=0;
volatile int rx_out=0;
const int buffer_size = 4095;
char tx_buffer[buffer_size+1];
char rx_buffer[buffer_size+1];
char cmdbuff[1024];
char rx_line[1024];
char distTrav[30];
int ticker;
int volatile right_var = 0;
int volatile left_var = 0;

DigitalOut start(p30,1);
DigitalOut right(p19,1);
DigitalOut left(p18,1);
DigitalOut up(p17,1);
DigitalOut down(p25,1);
DigitalOut on_switch(p24,0);
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
InterruptIn encoder(p15);

RPCFunction rpcTurnRight(&carTurnRight, "turnRight");
RPCFunction rpcTurnLeft(&carTurnLeft, "turnLeft");
RPCFunction rpcMoveForward(&carMoveForwardDistance, "moveForward");
RPCFunction rpcMoveBackward(&carMoveBackwardDistance, "moveBackward");

void drive_func();
void start_func();
void ticker_func();
 
void dist(int distance) //necessary for the sonar to work. Empty callback function.
{
}

ultrasonic front(p6, p7, .1, 1, &dist);    //Set the trigger pin to D8 and the echo pin to D9
ultrasonic rightc(p8,p9,.1,1, &dist); 
ultrasonic leftc(p21,p22,.1,1, &dist);    //have updates every .1 seconds and a timeout after 1
ultrasonic back(p13,p14,0.1,1, &dist); 

int main() {
    pc.baud(9600);
    esp.baud(9600);
    front.startUpdates();
    rightc.startUpdates();
    leftc.startUpdates();
    back.startUpdates();
    encoder.mode(PullUp);
    encoder.fall(&ticker_func);
    encoder.rise(&ticker_func);
    start_func();
    wait(2);
    esp.attach(&Rx_interrupt, Serial::RxIrq);
    esp.attach(&Tx_interrupt, Serial::TxIrq);
    wait(5);
    connectToNetwork();
    char rpc_in[256];
    char rpc_out[256];
    while (1) {
        getReply();
        memset(&rpc_in[0], 0, sizeof(rpc_in));
        memset(&rpc_out[0], 0, sizeof(rpc_out));
        int length = (int)rx_line[3] - 48; // bytes 0 to 2 are trash; byte 3 is length of message
        if (length > 0 && length < 256) {
            for (int i = 0; i < length; i++) {
                rpc_in[i] = rx_line[i+4]; // bytes 4 to length+3 are the valid data
            }
            pc.printf("rpc call: %s\r\n", rpc_in);
            RPC::call(rpc_in, rpc_out);
            pc.printf("%s\n", rpc_out);
        }
        // lambda function is event-triggered and non-persistent
        // after it terminates, existing connection closes and a new one opens
        strcpy(cmdbuff, "srv:close()\r\n"); 
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "srv=net.createServer(net.TCP,");
        strcat(cmdbuff, timeout);
        strcat(cmdbuff, ")\r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "srv:listen(");
        strcat(cmdbuff, port);
        strcat(cmdbuff, ",function(conn)\r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "conn:on(\"receive\", function(conn, payload) \r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "conn:send('");
        strcat(cmdbuff, reportStatus());
        strcat(cmdbuff, "')\r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "print(payload)\r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "end)\r\n");
        sendCMD();
        wait(.5);
        getReply();
        strcpy(cmdbuff, "end)\r\n");
        sendCMD();
        wait(.5);
        getReply();
    }
    
}

/* CAR FUNCTIONS */

void starting_commands(){ // toggles the button to start the cop car
    start = 0;
    wait(0.5);
    start = 1;
    wait(0.5);
    }
 
 
void start_func() // sequence that gets the cop car into no noise run mode
{
    led1=1;led2=1;led3=1;led4=1;
    on_switch =1;
    starting_commands();
    starting_commands();
    starting_commands();
    starting_commands();
    starting_commands();
    led1=0;led2=0;led3=0;led4=0;
}
 
void drive_for() // pulses the drive pin; the pulsing is so that the car doesnt go too fast
{
    front.checkDistance();
    while(front.getCurrentDistance() > 450){
        pc.printf("%d\r\n", front.getCurrentDistance());
        front.checkDistance();
        up = 0;
        wait(0.1);
        up = 1;
        wait(0.1);
    }
    down = 0;
    wait(0.3);
    down = 1;
    wait(0.1);
}

void drive_back() // pulses the drive pin; the pulsing is so that the car doesnt go too fast
{
    back.checkDistance();     
    while(back.getCurrentDistance() >400){
        front.checkDistance();
        down = 0;
        wait(0.1);
        down = 1;
        wait(0.1);
        }
    up = 0;
    wait(0.3);
    up = 1;
    wait(0.1);
}
 
void stop_func() // stops the car and checks right and left sonars for obstructions
{
    up = 1;
    down = 0;
    wait(0.1);
    down = 1;
    front.checkDistance();     
    rightc.checkDistance();
    leftc.checkDistance();
    back.checkDistance();
    if (rightc.getCurrentDistance()<300) right_var = 1;
    if (leftc.getCurrentDistance()<300) left_var = 1;
}
        
void turn_func() // turns the car until the front sonar is unobstructed
{
    int turn_var = 0;
    while(turn_var == 0){
        if (right_var == 0){
            down = 0;
            wait(0.1);
            down = 1;
            right=up=0;
            wait(0.1);
            right=up=1;
            if(front.getCurrentDistance()>300) turn_var = 1;
        }
        else if (left_var == 0){
            down = 0;
            wait(0.1);
            down = 1;
            left=up=0;
            wait(0.1);
            left=up=1;
            if(front.getCurrentDistance()>300) turn_var = 1;
        }
        else {
            down = 0;
            wait(0.2);
            down = 1;
            if (rightc.getCurrentDistance()>300) right_var = 0;
            if (leftc.getCurrentDistance()>300) left_var = 0;
        }
    }
    left_var = right_var = 0;
}

void carMoveForwardDistance(Arguments *in, Reply *out) {
      led1=1; led4=1;
      drive_for();
}

void carMoveBackwardDistance(Arguments *in, Reply *out) {
    drive_back();
}

void carTurnRight(Arguments *in, Reply *out) {
    right = 0;
    wait(0.3);
    up = 0;
    wait(0.95);
    up = 1;
    wait(0.15);
    down = 0;
    wait(0.3);
    right = 1;
    wait(0.1);
    left = 0;
    wait(0.65);
    down = left = 1;
    wait(0.1);
    up = 0;
    wait(0.25);
    up = 1;
    wait(0.1);
}

void carTurnLeft(Arguments *in, Reply *out) {
    left = 0;
    wait(0.3);
    up = 0;
    wait(0.95);
    up = 1;
    wait(0.15);
    down = 0;
    wait(0.3);
    left = 1;
    wait(0.1);
    right = 0;
    wait(0.65);
    down = right = 1;
    wait(0.1);
    up = 0;
    wait(0.25);
    up = 1;
    wait(0.1);
}

/* WIFI FUNCTIONS */

void connectToNetwork() {
    pc.printf("# Resetting ESP\r\n");
    strcpy(cmdbuff,"node.restart()\r\n");
    sendCMD();
    wait(5);
    getReply();

    pc.printf("# Setting Mode\r\n");
    strcpy(cmdbuff, "wifi.setmode(wifi.STATION)\r\n");
    sendCMD();
    getReply();

    wait(2);
    pc.printf("# Connecting to AP\r\n");
    pc.printf("# ssid = %s\t\tpwd = %s\r\n", ssid, pwd);
    strcpy(cmdbuff, "wifi.sta.config(\"");
    strcat(cmdbuff, ssid);
    strcat(cmdbuff, "\",\"");
    strcat(cmdbuff, pwd);
    strcat(cmdbuff, "\")\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=0,led2=0,led3=1;
    pc.printf("# Get IP Address\r\n");
    strcpy(cmdbuff, "print(wifi.sta.getip())\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=1,led2=0,led3=0;
    pc.printf("# Get Connection Status\r\n");
    strcpy(cmdbuff, "print(wifi.sta.status())\r\n");
    sendCMD();
    getReply();
    
    wait(2);
    led1=0,led2=1,led3=0;
    pc.printf("# Listen on Port\r\n");
    strcpy(cmdbuff, "srv=net.createServer(net.TCP,");
    strcat(cmdbuff, timeout);
    strcat(cmdbuff, ")\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=0,led2=0,led3=1;
    strcpy(cmdbuff, "srv:listen(");
    strcat(cmdbuff, port);
    strcat(cmdbuff, ",function(conn)\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=1,led2=0,led3=0;
    strcpy(cmdbuff, "conn:on(\"receive\", function(conn, payload) \r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=0,led2=1,led3=0;
    strcpy(cmdbuff, "conn:send('");
    strcat(cmdbuff, reportStatus());
    strcat(cmdbuff, "')\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=0,led2=0,led3=1;
    strcpy(cmdbuff, "print(payload)\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=1,led2=0,led3=0;
    strcpy(cmdbuff, "end)\r\n");
    sendCMD();
    getReply();

    wait(2);
    led1=0,led2=1,led3=0;
    strcpy(cmdbuff, "end)\r\n");
    sendCMD();
    getReply();

    wait(2);
    //led1=1,led2=1,led3=1;
    led1=0,led2=0,led3=0;
    pc.printf("# Ready\r\n");
}

void sendCMD()
{
    int i;
    char temp_char;
    bool empty;
    i = 0;
// Start Critical Section - don't interrupt while changing global buffer variables
    NVIC_DisableIRQ(UART1_IRQn);
    empty = (tx_in == tx_out);
    while ((i==0) || (cmdbuff[i-1] != '\n')) {
// Wait if buffer full
        if (((tx_in + 1) % buffer_size) == tx_out) {
// End Critical Section - need to let interrupt routine empty buffer by sending
            NVIC_EnableIRQ(UART1_IRQn);
            while (((tx_in + 1) % buffer_size) == tx_out) {
            }
// Start Critical Section - don't interrupt while changing global buffer variables
            NVIC_DisableIRQ(UART1_IRQn);
        }
        tx_buffer[tx_in] = cmdbuff[i];
        i++;
        tx_in = (tx_in + 1) % buffer_size;
    }
    if (esp.writeable() && (empty)) {
        temp_char = tx_buffer[tx_out];
        tx_out = (tx_out + 1) % buffer_size;
// Send first character to start tx interrupts, if stopped
        esp.putc(temp_char);
    }
// End Critical Section
    NVIC_EnableIRQ(UART1_IRQn);
    return;
}

// Read a line from the large rx buffer from rx interrupt routine
void getReply() {
    int i;
    i = 0;
// Start Critical Section - don't interrupt while changing global buffer variables
    NVIC_DisableIRQ(UART1_IRQn);
// Loop reading rx buffer characters until end of line character
    while ((i==0) || (rx_line[i-1] != '\r')) {
// Wait if buffer empty
        if (rx_in == rx_out) {
// End Critical Section - need to allow rx interrupt to get new characters for buffer
            NVIC_EnableIRQ(UART1_IRQn);
            while (rx_in == rx_out) {
            }
// Start Critical Section - don't interrupt while changing global buffer variables
            NVIC_DisableIRQ(UART1_IRQn);
        }
        rx_line[i] = rx_buffer[rx_out];
        i++;
        rx_out = (rx_out + 1) % buffer_size;
    }
// End Critical Section
    NVIC_EnableIRQ(UART1_IRQn);
    rx_line[i-1] = 0;
    return;
}

char* reportStatus() {
      float distTravelled = float(ticker) * 2.5 / 12;
      sprintf(distTrav, "%.1f", distTravelled);
      return distTrav;
}

// Interupt Routine to read in data from serial port
void Rx_interrupt() {
    //led3=1;
// Loop just in case more than one character is in UART's receive FIFO buffer
// Stop if buffer full
    while ((esp.readable()) && (((rx_in + 1) % buffer_size) != rx_out)) {
        rx_buffer[rx_in] = esp.getc();
// Uncomment to Echo to USB serial to watch data flow
        pc.putc(rx_buffer[rx_in]);
        rx_in = (rx_in + 1) % buffer_size;
    }
    return;
}


// Interupt Routine to write out data to serial port
void Tx_interrupt() {
    //led2=1;
// Loop to fill more than one character in UART's transmit FIFO buffer
// Stop if buffer empty
    while ((esp.writeable()) && (tx_in != tx_out)) {
        esp.putc(tx_buffer[tx_out]);
        tx_out = (tx_out + 1) % buffer_size;
    }
    //led2=0;
    return;
}

void ticker_func()
{
    ticker++;
}

Video

Future Improvements

  • Features to be added in the future:
  1. Effective side sonar detection
  2. Better all around object detection by incorporating IR sensors with the current Sonar
  3. Effective usage of encoder for accurate distance measurements
  4. Hack the Cop Car's power switch so that it can be turned on/off from the mbed using a MOSFET


Please log in to post comments.