Keyestudio 4WD Bluetooth multifunctional car kit

From Embedded Lab Vienna for IoT & Security
Jump to: navigation, search

Summary

This documentation is about the keyestudio 4WD Bluetooth Multi-functional Car Kit. The documentation contains schematics, tipps and code for the car.

Requirements

  • Arduino IDE
  • 18650 Batteries (not included in kit)

Description

Component list

Product Name Quantity
keyestudio UNO R3 1
keyestudio Shield V5 1
keyestudio L298N Motor Shield 1
keyestudio Bluetooh HC-06 1
I2C 1602 LCD 1
keyestudio Line Tracking Sensor 3
HC-SR04 Ultrasonic Sensor 1
keyestudio Digital IR Receiver Module 1
4WD Top PCB 1
4WD Bottom PCB 1
Servo Motor 1
Servo Plastic Platform 1
IR Remote Control 1
Toggle Switch + Wire 1
18650 Battery Holder 1
DC Motor 4
Motor Fixed Part 4
Plastic Tire 4
Copper Pillar 40MM 6
Copper Pillar 10MM 16
USB Cable 1
Jumper Wire 30
M3*6MM Round Head Screw 60
M3*8MM Flat Head Screw 2
M3*30MM Round Head Screw 8
3MM Nut 16
Connector Wire (150mm, Black) 6
Connector Wire (150mm, Red) 6
Winding Wire (12CM) 1

Assembly

Follow the User Manual. If something is unclear then watch a assembly video. Be careful when installing the motors, make sure they’re all properly aligned, if not the car will pull to one side. Especially take care that no cables sticks into the motors.

Motor control

We control the motor using a H-Bridge L298N Motor Driver. Use a exxternal 5V logic supply when using more than 12V driving voltage.

Motor Driver.png

In our case we need to plug two motors to each motorA and motorB. Connect the power from the battery pack VSS and GND.

Motor Driver schematics.png

Wire the motor to the Arduino/Sensor Shield as adviced in the user manual.

Specification:

  • Working Mode: H bridge (double lines)
  • Control Chip: L298N (ST)
  • Logical Voltage: 5V
  • Driving Voltage: 5V-35V
  • Logical Current: 0mA-36mA>
  • Driving Current: 2A (MAX single bridge)
  • Storage Temperature: (-20 °C)-(+135 °C)
  • Maximum Power: 25W
  • Weight: 30g
  • Periphery Dimension: 43 x 43 x 27 mm(L x W x H)

Code

Initiation

//define the output pins.
int IN1=5;
int IN2=6;
int IN3=7;
int IN4=8;
int ENA=9;
int ENB=10;
void setup() {
  //set up the pins to act as output.
  for (int i = 5; i < 11;i++)
  {
    pinMode(i,OUTPUT);
  }
  delay(5000);
}

Rotate Counter Clockwise

void turnCounterClockwise()
{
 analogWrite(ENA,0);
 analogWrite(ENB,0);
 digitalWrite(IN1,LOW);
 digitalWrite(IN2,HIGH);

 digitalWrite(IN3,LOW);
 digitalWrite(IN4,HIGH);
 delay(150);
 analogWrite(ENA,200);
 analogWrite(ENB,200);
}

Rotate Clockwise

void turnClockwise()
{
 analogWrite(ENA,0);
 analogWrite(ENB,0);
 digitalWrite(IN1,HIGH);
 digitalWrite(IN2,LOW);

 digitalWrite(IN3,HIGH);
 digitalWrite(IN4,LOW);
 delay(150);
 analogWrite(ENA,200);
 analogWrite(ENB,200);
}

Drive Forward

void driveForward()
{
 analogWrite(ENA,0);
 analogWrite(ENB,0);
 digitalWrite(IN1,LOW);
 digitalWrite(IN2,HIGH);

 digitalWrite(IN3,HIGH);
 digitalWrite(IN4,LOW);
 delay(150);
 analogWrite(ENA,100);
 analogWrite(ENB,100);
}

Drive Reverse

void driveReverse()
{
 analogWrite(ENA,0);
 analogWrite(ENB,0);
 digitalWrite(IN1,HIGH);
 digitalWrite(IN2,LOW);
 
 digitalWrite(IN3,LOW);
 digitalWrite(IN4,HIGH);
 delay(150);
 analogWrite(ENA,100);
 analogWrite(ENB,100);
}

Brake

void brake()
{
 analogWrite(ENA,0);
 analogWrite(ENB,0);
}

I2C Display

The display is controlled with I2C. I am using the Wire and LiquidCrystal_I2C library to control the display.

Specification

  • I2C Address: 0x27
  • Back Lit (Blue with white char color)
  • Supply Voltage: 5V
  • Interface:I2C/TWI x1,Gadgeteer interface x2
  • Adjustable Contrast
  • Size:82x35x18 mm

Schematics

I2C Display Schematics.png

Code

Note: Don't use the library link that is in the manual, it contains a bug where only the first character of the strings is displayed on the I2C display. Download the latest version from https://www.arduinolibraries.info/libraries/liquid-crystal-i2-c.
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
//set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27,16,2);
void setup()
{
 //initialize the lcd
 lcd.init();
 //enable the backlight 
 lcd.backlight();
 //set the cursor to the first line.
 lcd.setCursor(3,0);
 //print text
 lcd.print("Hello");
 //set the cursor in the next line.
 lcd.setCursor(3,1);
 //print text
 lcd.print("world!");
}

void loop()
{}

Servo Motor

The Servo Motor is controlled with PWM. The Sketch rotates the motor in an angle between 110 and 180 degres.

Schematics

Servo Motor Schematics.png

Code

int servopin=2;// select digital pin 9 for servomotor signal line
int myangle;// initialize angle variable
int pulsewidth;// initialize width variable
int val;

void servopulse(int servopin,int myangle)// define a servo pulse function
{
  pulsewidth=(myangle*11)+500;// convert angle to 500-2480 pulse width
  digitalWrite(servopin,HIGH);// set the level of servo pin as “high”
  delayMicroseconds(pulsewidth);// delay microsecond of pulse width
  digitalWrite(servopin,LOW);// set the level of servo pin as “low”
  delay(20-pulsewidth/1000);
}

void setup()
{
  pinMode(servopin,OUTPUT);// set servo pin as “output”
  Serial.begin(9600);// connect to serial port, set baud rate at “9600”
  Serial.println("ready" ) ;
}

void loop(){
  val = 180;
  Serial.print("moving servo to ");
  Serial.print(val);
  Serial.println();
  for(int i=0;i<=25;i++) // giving the servo time to rotate to commanded position
  {
    servopulse(servopin,val);// use the pulse function
  }
  val = 110;
  Serial.print("moving servo to ");
  Serial.print(val);
  Serial.println();
  for(int i=0;i<=25;i++) // giving the servo time to rotate to commanded position
  {
    servopulse(servopin,val);// use the pulse function
  }
}

Ultra Sonic Sensor

I used the pins: echoPin 3 and trigPin 4 because 7 and 8 is already taken by the motordriver. If you don't understand the line: distance = duration/58.3;. The speed of sound is 343 m/s. We messure the round trip so we need to divide the 343 with 2 which gives us 171.5 m/s. But we don’t want to deal with meters and seconds we want centimeters and microseconds. 17150 cm/s = 0.017150 cm/us = 1cm/58.3 us.

Specification

  • Working Voltage: DC 5V
  • Working Current: 15mA
  • Working Frequency: 40Hz
  • Max Range: 4m
  • Min Range: 2cm
  • Measuring Angle: 15 degree
  • Trigger Input Signal: 10µS TTL pulse
  • Echo Output Signal Input TTL lever signal and the range in proportion
  • Size: 46*20.4mm
  • Weight: 9g

Schematics

Ultra Sonic Schematics.png

Code

#define echoPin 7 // Echo Pin
#define trigPin 8 // Trigger Pin
#define LEDPin 13 // Onboard LED

int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance

void setup() {
 Serial.begin (9600);
 pinMode(trigPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LEDPin, OUTPUT); // Use LED indicator (if required)
}

void loop() {
/* The following trigPin/echoPin cycle is used to determine the
 distance of the nearest object by bouncing soundwaves off of it. */ 
 digitalWrite(trigPin, LOW); 
 delayMicroseconds(2); 

 digitalWrite(trigPin, HIGH);
 delayMicroseconds(10); 
 digitalWrite(trigPin, LOW);
 duration = pulseIn(echoPin, HIGH);
 
 //Calculate the distance (in cm) based on the speed of sound.
 distance = duration/58.3;

 if (distance >= maximumRange || distance <= minimumRange){
  /* Send a negative number to computer and Turn LED ON 
  to indicate "out of range" */
  Serial.println("-1");
  digitalWrite(LEDPin, HIGH); 
 }
 else {
  /* Send the distance to the computer using Serial protocol, and
  turn LED OFF to indicate successful reading. */
  Serial.println(distance);
  digitalWrite(LEDPin, LOW); 
 } 
 //Delay 50ms before next reading.
 delay(50);
}

Line Tracking Sensor

Specification

  • Power Supply: +5V
  • Operating Current: <10mA
  • Operating Temperature Range: 0°C ~ + 50°C
  • Output Interface: 3-wire interface (1 - signal, 2 - power, 3 - power supply negative)
  • Output Level: TTL level

Schematics

Line Tracking Sensor Schematics.png

Code

I used the pins 0-2 for the 3 line tracking sensors. This sketch is used to test the line tracking sensors.

const int sensorPin1 = 0;
const int sensorPin2 = 1;
const int sensorPin3 = 2; // the number of the sensor pin
const int ledPin = 13;      // the number of the LED pin
int sensorState = 0;         // variable for reading the sensor status
void setup()
{
    pinMode(ledPin, OUTPUT);
    pinMode(sensorPin1, INPUT);
    pinMode(sensorPin2, INPUT);
    pinMode(sensorPin3, INPUT);
}
void loop()
{
    // read the state of the sensor value:
    sensorState = digitalRead(sensorPin1);
    // if the sensorState is HIGH:
    if (sensorState == HIGH)
    {
        digitalWrite(ledPin, HIGH);
    }
    else
    {
        digitalWrite(ledPin, LOW);
    }
}

Digital IR Receiver Module

Specification

  • Power Supply: 5V
  • Interface: Digital
  • Modulate Frequency: 38kHz
  • Module Interface Socket: JST PH2.0


Button HexValue DecValue
ArrowUp FF629D 16736925
ArrowDown FFA857 16754775
ArrowRight FFC23D 16761405
ArrowLeft FF22DD 16720605
1 FF6897 16738455
2 FF9867 16750695
3 FFB04F 16756815
4 FF30CF 16724175
5 FF18E7 16718055
6 FF7A85 16743045
7 FF10EF 16716015
8 FF38C7 16726215
9 FF5AA5 16734885
0 FF4AB5 16730805
OK FF02FD 16712445
* FF32BD 16728765
# FF52AD 16732845

Schematics

IR Receiver Schematics.png

Code

Output IR-Remote control values

My intention is to steer the car with the IR-Remote-Control included in the kit. This sketch outputs the values the IR-Receiver gets from the remote control so I know the values I'm working with.

# include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
    Serial.begin(9600);
    irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
    if (irrecv.decode(&results))
    {
        Serial.println(results.value, HEX);
        irrecv.resume(); // Receive the next value
    }
}

Steer car with IR-Remote control

# include <IRremote.h>
int IN1 = 5;
int IN2 = 6;
int IN3 = 7;
int IN4 = 8;
int ENA = 9;
int ENB = 10;
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
decode_results lastResult;
void setup()
{
    for (int i = 5; i < 11; i++)
    {
        pinMode(i, OUTPUT);
    }
    Serial.begin(9600);
    irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
    if (irrecv.decode(&results))
    {
        if (results.value != lastResult.value)
        {
            switch (results.value)
            {
                //ArrowUp
                case 16736925:
                    driveForward();
                    break;
                //ArrowDown
                case 16754775:
                    driveReverse();
                    break;
                //ArrowRight
                case 16761405:
                    turnClockwise();
                    break;
                //ArrowLeft
                case 16720605:
                    turnCounterClockwise();
                    break;
                //Ok
                case 16712445:
                    brake();
                    break;
            }
            lastResult = results;
        }
        irrecv.resume(); // Receive the next value
    }
}

void driveForward()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);

    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
    delay(150);
    analogWrite(ENA, 100);
    analogWrite(ENB, 100);
}

void driveReverse()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);

    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
    delay(150);
    analogWrite(ENA, 100);
    analogWrite(ENB, 100);
}

void turnClockwise()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);

    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
    delay(150);
    analogWrite(ENA, 150);
    analogWrite(ENB, 150);
}

void turnCounterClockwise()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);

    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
    delay(150);
    analogWrite(ENA, 150);
    analogWrite(ENB, 150);
}

void brake()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
}

Bluetooth Module

Specification

  • Bluetooth Protocol: Bluetooth 2.1+ EDR Standard
  • USB Protocol: USB v1.1/2.0
  • Operating Frequency: 2.4GHz ISM Frequency Band
  • Modulation Mode: Gauss Frequency Shift Keying
  • Transmit Power: ≤ 4dBm, Second Stage
  • Sensitivity: ≤-84dBm at 0.1% Bit Error Rate
  • Transmission Speed: 2.1Mbps(Max)/160 kbps(Asynchronous); 1Mbps/1Mbps(Synchronous)
  • Safety Feature: Authentication and Encryption
  • Supported Configuration: Bluetooth Serial Port (major and minor)
  • Supply Voltage: 5V DC 50mA
  • Operating Temperature: -20 to 55℃

Schematics

Bluetooth Module Schematics.png

Code

int val;
int ledpin = 13;
void setup()
{
    Serial.begin(9600);
    pinMode(ledpin, OUTPUT);
}
void loop()
{
    val = Serial.read();
    if (val == 'a')
    {
        digitalWrite(ledpin, HIGH);
        delay(250);
        digitalWrite(ledpin, LOW);
        delay(250);
        Serial.println("keyestudio");
    }
}

Obstacle Avoidance

This code measures the distance between the car and the object in front of it. If the distance between both is under 15cm the car will turn 180° and continue to drive forward. I used the Ultra-Sonic Sensor to measure the distance and the I2C-Display to display the current distance.

Code

#define echoPin 3 // Echo Pin
#define trigPin 4 // Trigger Pin

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
int maximumRange = 200; // Maximum range needed
int minimumRange = 0; // Minimum range needed
long duration, distance; // Duration used to calculate distance
LiquidCrystal_I2C lcd(0x27,3,1);
bool state = true;
int IN1 = 5;
int IN2 = 6;
int IN3 = 7;
int IN4 = 8;
int ENA = 9;
int ENB = 10;

void setup()
{
    Serial.begin(9600);
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    for (int i = 5; i < 11; i++)
    {
        pinMode(i, OUTPUT);
    }
    lcd.init();
    lcd.backlight();
    delay(5000);
    driveForward();
}

void loop()
{
    /* The following trigPin/echoPin cycle is used to determine the
     distance of the nearest object by bouncing soundwaves off of it. */
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);

    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);

    //Calculate the distance (in cm) based on the speed of sound.
    distance = duration / 58.3;

    if (distance >= maximumRange || distance <= minimumRange)
    {
        /* Send a negative number to computer and Turn LED ON 
        to indicate "out of range" */
        lcd.clear();
        lcd.setCursor(3, 0);
        lcd.print("-1");
        Serial.println("-1");
    }
    else
    {
        /* Send the distance to the computer using Serial protocol, and
        turn LED OFF to indicate successful reading. */
        if (distance <= 15 && state != false)
        {
            state = false;
            brake();
            delay(200);
            turnClockwise();
            delay(780);
            state = true;
            driveForward();
        }
        else if (distance >= 30 && state != true)
        {
            state = true;
            driveForward();
        }
        lcd.clear();
        lcd.setCursor(3, 0);
        lcd.print(distance);
        Serial.println(distance);
    }
    //Delay 50ms before next reading.
    delay(50);
}

void driveForward()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);

    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
    delay(150);
    analogWrite(ENA, 100);
    analogWrite(ENB, 100);
}

void driveReverse()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);

    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
    delay(150);
    analogWrite(ENA, 100);
    analogWrite(ENB, 100);
}

void turnClockwise()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);

    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
    delay(150);
    analogWrite(ENA, 200);
    analogWrite(ENB, 200);
}

void brake()
{
    analogWrite(ENA, 0);
    analogWrite(ENB, 0);
}

Used Hardware

Smart Robot Car Kit Bluetooth 4WD keyestudio

References