Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save john212/d1339fa0cf29c1306c05 to your computer and use it in GitHub Desktop.
Save john212/d1339fa0cf29c1306c05 to your computer and use it in GitHub Desktop.
Vex Mini Robot - Arduino Uno - Vex 393 DC Motors - Sparkfun IR 9-Button Remote - Ping Ultrasonic Rangefinder
/**************************************************
Udemy Arduino Step-by-Step Course
Section 5 DC Motors Lecture 47 Part 2 Using the L298N H Bridge
To Control Speed/Direction of a 2-Motor Robot with A 9-Button
Infrared Remote Control and an Ultrasonic Distance Sensor.
by J. Cantlin
February 17, 2016
***************************************************/
/**************************************************
Description of Program
An Arduino Uno is connected to a L298N H- Bridge DC Motor Controller
which is used to control two DC motors. The DC motors are
the drive motors of a small robot made using Vex Robotics components.
The L298N changes the polarity of the DC voltage supply to the motors
when signalled to do so by the Arduino. The will cause the motors
to rotate in the opposite direction. The L298H takes the low
voltage (5vdc) digital high/low signal from the Arduino and reverses
the polarity of the higher voltage (7.2 vdc in this case) supplied to the DC motors.
The motor speed ramps from high speed to low speed proportional
to a PWM signal sent to the L298N from the Arduino.
For this sketch, a simple 9-button infrared remote control from
Sparkfun is used to send commands to a 38kHz demodulating Infrared Receiver
Modules connected to the Arduino to control the DC motors via the L298N.
A battery pack with 6 rechargable NiCad batteries is used to provide
7.2 vdc to the H-Bridge and DC motors. The Arduino is powered by a
9 vdc battery or, if more power is needed, by a LiPo Backup USB Charger.
A mini DC voltmeter is mounted on the back of the robot to
monitor the voltage of the 6 AA battery pack. This voltmeter was from
on eBay and costs $2.99 - it works great.
http://www.ebay.com/itm/201320503051?_trksid=p2060353.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
***************************************************/
/**************************************************
L298N DC Motor Controller
This controller, mounted on a breakout board, can control
one or two DC Motors or DC Stepper Motors.
A supply voltage of about 6vdc min to a max of 35vdc is supplied
to the L298N board. The IC converts the low voltage signals
form the Arduino to the appropriate higher voltage signals to
control the voltage (speed) and direction of rotation (polarity,
positive or negative) of the two motors.
Summary of L298N H Bridge Contoller Pins/Terminals/Jumpers Used:
OUT1 = + Supply Voltage to "LEFT" DC Motor = DC Motor 1
OUT2 = - Supply Voltage to "LEFT" DC Motor = DC Motor 1
OUT3 = - Supply Voltage to "RIGHT" DC Motor = DC Motor 2
OUT4 = + Supply Voltage to "RIGHT" DC Motor = DC Motor 2
12V Jumper = On since supply volts = 7.2vdc, take off if supply > 12vdc
if off, the 5vdc supply pin is not used, not using this anyway.
+12V In = Supply is 7.2vdc for this project. About 6-35vdc OK.
GND = Ground Note: common ground to Arduino should be connected.
+5V Out = Not Used. Regulated 5vdc available if <=12vdc supplied.
ENA1 Jumper = OFF, PWM Signal to Motor 1 from Arduino Digital Pin 9
IN1 = Arduino Digital Pin 4 = HIGH/LOW = CW/CCW Rotation Motor 1
IN2 = Arduino Digital Pin 5 = PWM = Speed Motor 1
IN3 = Arduino Digital Pin 6 = PWM = Speed Motor 2
IN4 = Arduino Digital Pin 7 = HIGH/LOW = CW/CCW Rotation Motor 2
ENA2 Jumper = OFF, PWM Signal to Motor 2 from Arduino Digital Pin 10
The Arduino Uno PWM pins, identified with a ~, can send their PWM signal directly
to the ENA1 and ENA2 pins on the L298N. To do this, remove the jumpers on these
pins (this exposes two pins each) and connect the Arduino PWM pins to the pin exposed by
removing the jumper that is closest to the edge of the board. The inboard pin is only used,
as far as I know, by the "shoting" jumper that is installed by default.
The PWM pins on the Arduino Uno operate at different frequencies, to match the
PWMs best to the two robot drive motors, it seems like good practice to
use pins with the same PWM frequency, so I did.
Arduino Uno PWM Pins and Frequencies:
* Pins 5 and 6: controlled by timer0, base frequency 62500Hz
* Pins 9 and 10: controlled by timer1, base frequency 31250Hz, used here
* Pins 11 and 3: controlled by timer2, base frequency 31250Hz
A good L298N tutorial referenced in the Udemy course is at:
http://tronixlabs.com/news/tutorial-l298n-dual-motor-controller-module-2a-and-arduino/
A well written tutorial on using the L298N and the PWM control is at:
http://tronixstuff.com/2014/11/25/tutorial-l298n-dual-motor-controller-modules-and-arduino/
***************************************************/
/**************************************************
Ping Ultasonic Distance Sensor
This sketch uses a PING ultrasonic distance sensor (made by Parallax) to find the
distance to the closest object in the sensor's range (3 cm to 3.3 meters). If set up
properly, it can be accurate to the nearest half centimeter. To measure a distance,
the Arduino sends a pulse to the sensor to initiate a "ping" via the sensor's speaker
and the sensor then listens for a echo of the "ping" to retun via its microphone.
The time it takes to hear the return echo is how long it takes sound to travel
to the object and back. Knowing the speed of sound in air at sea level (approximately
774 mph) allows calculating the distance from the detected object from the sensor.
Sensor connections:
* +5V and Ground
* One Digital Pin (any) of the Arduino
Ref.: http://www.arduino.cc/en/Tutorial/Ping
***************************************************/
/**************************************************
DC Motors
Two Vex 393 DC Motors are used in this project. These motors
can run > 12vdc but are designed for running at 7.2vdc; which
was the voltage supplied to the L298N controller in this project.
More information on the 393 motors is at:
http://www.vexrobotics.com/wiki/2-Wire_Motor_393.
***************************************************/
/**************************************************
IR Remote
The 9 buttons IR Remote is a simple infrared remote from Sparkfun,
kit #13235 which includes:
* A CR2025 Coin Cell Battery for the remote (used).
* Two 38kHz demodulating Infrared Receiver Modules (one used).
* Two 950nm-emitting Infrared LEDs (not used).
* A handful of 330Ω resistors (not used).
This nine button remote emits unique 32-bit codes for each button press.
Button Code
POWER 0x10EF D827
A 0x10EF F907
B 0x10EF 7887
C 0x10EF 58A7
^ 0x10EF A05F
< 0x10EF 10Ef
o 0x10EF 20DF
> 0x10EF 807F
\/ 0x10EF 00FF
The output of an IR Receiver Module (38 kHz demodulating
version) is connected to any Arduino's digital pin.
The IR Receiver Module should also be powered off the
Arduino's 5V and GND rails. The remote only sends commands to
the Arduino, so only the IR Receiver is needed on the robot.
The IRLibrary by Ken Shirriff is used and is on GitHub.
Reference Ken Shirriff's blog at:
http://www.righto.com/2009/08/multi-protocol-infrared-remote-library.html
This infrared remote library consists of two parts: IRsend transmits IR remote packets,
while IRrecv receives and decodes an IR message. IRsend uses an infrared LED
connected to a digital pin (pin 3 in the example). To send a message, call the send method
for the desired protocol with the data to send and the number of bits to send. Sending
is not needed or used to control the robot's motors.
That is, to transmit commands to the robot, only the IR Receiver will be used.
Some library documentation excerpts FYI:
The IRrecv class performs the decoding, and is initialized with enableIRIn().
The decode() method is called to see if a code has been received; if so,
it returns a nonzero value and puts the results into the decode_results
structure. Once a code has been decoded, the resume() method must be called
to resume receiving codes. Note that decode() does not block; the sketch
can perform other operations while waiting for a code because the codes
are received by an interrupt routine. The IRrecv library consists of two parts.
An interrupt routine is called every 50 microseconds, measures the length
of the marks and spaces, and saves the durations in a buffer. The user
calls a decoding routine to decode the buffered measurements into the
code value that was sent (typically 11 to 32 bits). The decode library tries
decoding different protocols in succession, stopping if one succeeds. It
returns a structure that contains the raw data, the decoded data, the
number of bits in the decoded data, and the protocol used to decode the data.
Bottom line, the IR Remote library code is surprisgly...complicated. Use
the library, I don't recommend trying to write this code yourself. :-)
***************************************************/
//Include the IR Remote Control libraries.
#include <IRremote.h>
#include <IRremoteInt.h>
/***************************************************/
/* ************************************************
Define the IR remote button codes. Only the least signinficant two bytes
of these codes are defined. Each one should actually has 0x10EF in front of it.
If your remote is not documented, find these codes by running the IRrecvDump
example sketch included with the IRremote library. Sparkfun provides these
codes with the IR Remote Control kit documentation.
****************************************************/
#define NUM_BUTTONS 9 // The remote has 9 buttons
const uint16_t BUTTON_POWER = 0xD827; // i.e. 0x10EFD827 prefix for all is 0x10EF
const uint16_t BUTTON_A = 0xF807;
const uint16_t BUTTON_B = 0x7887;
const uint16_t BUTTON_C = 0x58A7;
const uint16_t BUTTON_UP = 0xA05F;
const uint16_t BUTTON_DOWN = 0x00FF;
const uint16_t BUTTON_LEFT = 0x10EF;
const uint16_t BUTTON_RIGHT = 0x807F;
const uint16_t BUTTON_CIRCLE = 0x20DF;
/* Connect the output of the IR receiver diode to pin 11. */
int RECV_PIN = 11;
/* Initialize the irrecv part of the IRremote library */
IRrecv irrecv(RECV_PIN);
decode_results results; // This will store the IR received codes
uint16_t lastCode = 0; // This keeps track of the last code RX'd
/**************************************************
Summary of Arduino Uno Analog Pins Used:
A0 =
A1 =
A2 =
A3 =
A4 =
A5 =
***************************************************/
/**************************************************
Summary of Arduino Uno Digital Pins Used:
To use PWM, call analogWrite(pin, dutyCycle), where dutyCycle
is a value from 0 to 255, and pin is one of the PWM pins
(3, 5, 6, 9, 10, or 11). A square wave is output, there is
no control over frequency but higher duty cycle = higher volts.
00 =
01 =
02 =
03 =
04 = L298N IN1 Motor 1 = "LEFT" Motor Direction of Rotation
05 = L298N IN2 Motor 1 = "LEFT" Motor Direction of Rotation
06 = L298N IN3 Motor 2 = "RIGHT" Motor Direction of Rotation
07 = L298N IN5 Motor 2 = "RIGHT" Motor Direction of Rotation
08 = Ping Ultrasonic Distance Sensor ping out/in
09 = L298N ENA1 Motor 1 = "LEFT" Motor Speed via ~PWM Pin
10 = L298N ENA2 Motor 2 = "RIGHT" Motor Speed via ~PWM Pin
11 = IR Receiver Module (38 kHz demodulating version) ~PWM Pin
12 =
13 =
***************************************************/
//Global variable assignments
//motor related
int M1T1 = 4; //Motor 1 Rotation - High/Low changes direction, T=Terminal
int M1T2 = 5; //Motor 1 Rotation - High/Low changes direction, T=Terminal
int M2T1 = 6; //Motor 2 Rotation - High/Low changes direction, T=Terminal
int M2T2 = 7; //Motor 2 Rotation - High/Low changes direction, T=Terminal
int ENAPWM1 = 9; //Motor 1 Speed via PWM High/Low Enables/Stops
int ENAPWM2 = 10; //Motor 2 Speed via PWM High/Low Enables/Stops
//IR Remote related
int slow = 64; //use IR Remote Button A
int medium = 127; //use IR Remote Button B, default
int fast = 255; //use IR Remote Button C
int speedSetButton = 127; //initial speed
//Ping Ultrasonic distance sensor related
const int pingPin = 8; //assign pin to the Ping ultrasonic distance sensor.
int reset_Value = 0; //distance sensor triggered reset value
void setup()
{//****start setup function****
Serial.begin(9600); //set the serial port to 9600 baud if monitor is used.
// set all the motor control pins on L298N to outputs
pinMode(M1T1, OUTPUT);
pinMode(M1T2, OUTPUT);
pinMode(M2T1, OUTPUT);
pinMode(M2T2, OUTPUT);
pinMode(ENAPWM1, OUTPUT);
pinMode(ENAPWM2, OUTPUT);
//set the pin used for the Ping ultasonic distance sensor to an output
pinMode(pingPin, OUTPUT);
// Start the IR Receiver Module
irrecv.enableIRIn();
}//****endof setup function****
void loop()
{//****start infinite loop****
/***********************************/
//Find distance to object using Ping ultrasonic distance sensor
// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, inches, cm;
// The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);
// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);
// convert the time into a distance
inches = microsecondsToInches(duration);
cm = microsecondsToCentimeters(duration);
//debugging print lines ... comment out when not needed
//Serial.print(inches);
//Serial.print("in, ");
//Serial.print(cm);
//Serial.print("cm");
//Serial.println();
delay(10);
if (irrecv.decode(&results))
{
/* read the RX'd IR into a 16-bit variable: */
uint16_t resultCode = (results.value & 0xFFFF);
/* The remote will continue to transmit 0xFFFFFFFF if a
button is held down. If we get 0xFFFFFFF, let's just
assume the previously pressed button is being held down */
if (resultCode == 0xFFFF)
{
resultCode = lastCode;
}
else
{
lastCode = resultCode;
}
// This switch statement checks the received IR code against
// all of the known codes. Each button press produces a
// serial output, and has an effect on the IR LED output.
switch (resultCode)
{
case BUTTON_POWER:
Serial.println("Power");
//button pressed action here
//stop all motors
digitalWrite(M1T1, LOW);
digitalWrite(M1T2, LOW);
digitalWrite(M2T1, LOW);
digitalWrite(M2T2, LOW);
break;
case BUTTON_A:
Serial.println("A");
//button pressed action here
speedSetButton = slow;
break;
case BUTTON_B:
Serial.println("B");
//button pressed action here
speedSetButton = medium;
break;
case BUTTON_C:
Serial.println("C");
//button pressed action here
speedSetButton = fast;
break;
case BUTTON_UP:
Serial.println("Up");
//button pressed action here
digitalWrite(M1T1, LOW); //Set Forward Rotation Direction
digitalWrite(M1T2, HIGH); //Set Forward Rotation Direction
digitalWrite(M2T1, HIGH); //Set Forward Rotation Direction
digitalWrite(M2T2, LOW); //Set Forward Rotation Direction
analogWrite(ENAPWM1, speedSetButton); //Set Speed 0-255
analogWrite(ENAPWM2, speedSetButton); //Set Speed 0-255
Serial.print("SpeedSetButton: ");
Serial.println(speedSetButton);
break;
case BUTTON_DOWN:
Serial.println("Down");
//button pressed action here
digitalWrite(M1T1, HIGH); //Set Reverse Rotation Direction
digitalWrite(M1T2, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T1, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T2, HIGH); //Set Reverse Rotation Direction
analogWrite(ENAPWM1, speedSetButton); //Set Speed 0-255
analogWrite(ENAPWM2, speedSetButton); //Set Speed 0-255
break;
case BUTTON_LEFT:
Serial.println("Left");
//button pressed action here
digitalWrite(M1T1, HIGH); //Set Reverse Rotation Direction
digitalWrite(M1T2, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T1, HIGH); //Set Forward Rotation Direction
digitalWrite(M2T2, LOW); //Set Forward Rotation Direction
analogWrite(ENAPWM1, 255); //Set Speed 0-255
analogWrite(ENAPWM2,255); //Set Speed 0-255
break;
case BUTTON_RIGHT:
Serial.println("Right");
//button pressed action here
digitalWrite(M1T1, LOW); //Set Forward Rotation Direction
digitalWrite(M1T2, HIGH); //Set Forward Rotation Direction
digitalWrite(M2T1, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T2, HIGH); //Set Reverse Rotation Direction
analogWrite(ENAPWM1, 255); //Set Speed 0-255
analogWrite(ENAPWM2, 255); //Set Speed 0-255
break;
case BUTTON_CIRCLE:
Serial.println("Circle");
//button pressed action here
//stop all motors
digitalWrite(M1T1, LOW);
digitalWrite(M1T2, LOW);
digitalWrite(M2T1, LOW);
digitalWrite(M2T2, LOW);
break;
default:
Serial.print("Unrecognized code received: 0x");
Serial.println(results.value, HEX);
break;
}
irrecv.resume(); // Receive the next value
}
//if robot senses an object is too close, stop, back up a little, repeat until OK
if(inches < 4)
{
Serial.print("inches less than 4, ");
Serial.println(inches);
//if (reset_Value == 0) Note: reset_Value not currently used
{
//stop all motors as long as sensed object is too close
digitalWrite(M1T1, LOW);
digitalWrite(M1T2, LOW);
digitalWrite(M2T1, LOW);
digitalWrite(M2T2, LOW);
delay(1000); //time to unfreeze robot
//reverse robot for short period of time.
digitalWrite(M1T1, HIGH); //Set Reverse Rotation Direction
digitalWrite(M1T2, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T1, LOW); //Set Reverse Rotation Direction
digitalWrite(M2T2, HIGH); //Set Reverse Rotation Direction
analogWrite(ENAPWM1, 180); //Set Speed 0-255
analogWrite(ENAPWM2, 180); //Set Speed 0-255
delay(3500);
//stop all motors
digitalWrite(M1T1, LOW);
digitalWrite(M1T2, LOW);
digitalWrite(M2T1, LOW);
digitalWrite(M2T2, LOW);
//reset_Value = 1;
}
//else
//{
//reset_Value = 0;
//}
}
}//****endof infinite loop****
//SUPPORTING FUNCTIONS
/***********************************/
long microsecondsToInches(long microseconds) {
// According to Parallax's datasheet for the PING))), there are
// 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
// second). This gives the distance travelled by the ping, outbound
// and return, so we divide by 2 to get the distance of the obstacle.
// See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
return microseconds / 74 / 2;
}
/***********************************/
long microsecondsToCentimeters(long microseconds) {
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}
/***********************************/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment