Hackers – Distance Sensor

Some of our Hackers have projects of their own that they are working on, to possibly submit to BT Young Scientists or elsewhere. Last Saturday, those people were focused on working on their own project, with occasional help from peers or mentors where needed.

Those who were not working on their own projects extended last week’s Arduino project to add an ultrasonic distance sensor, replacing the variable resistor that they used last week.

Ultrasonic distance sensors are interesting: like sonar in a submarine or how bats navigate, they send out a short sound pulse (ultrasonic – too high for humans to hear) and then see how long it takes for an echo to come back. Since the speed of sound in air is known, we can calculate the distance to the nearest object based on the time for the round trip.

Here is a good tutorial on how it works: https://howtomechatronics.com/tutorials/arduino/ultrasonic-sensor-hc-sr04/

Above is a circuit designed by mentor Kevin for an ultrasonic distance sensor and a buzzer, to work like a car parking sensor that beeps faster as you get closer to an obstacle.

Below is Kevin’s Arduino program to control the distance sensor and print out the distance. Some people in the group modified this to use buzzers, others turned on 1, 2 or 3 LEDs depending on distance. #

const int triggerPin = 12;
const int echoPin = 10;

// The speed of sound in air at standard temperature and pressure is 343m/s.
// The range of the sensor is 4m.  It takes 2*4/343 seconds for an ultrasonic
// pulse to travel that far and back.
// We'll use that as a timeout later.  There's no point in waiting any longer
// than the time it takes to read an object at the maximum range of the sensor.
unsigned long echo_timeout = 2*4000000/343;

void setup() {
 Serial.begin(9600);
 pinMode(triggerPin, OUTPUT);
 pinMode(echoPin, INPUT);
 pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  unsigned long duration;
  float distance;

  // Begin by resetting the distance sensor 
  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);
  // Write out a short pulse for 10 microseconds
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);
  
  // pulseIn will wait for the input on echoPin to go HIGH.  Then it will
  // time how long it takes to go LOW.
  // The duration in microseconds is returned.
  // We'll wait, at most, echo_timeout microseconds for a pulse. 
  duration = pulseIn(echoPin, HIGH, echo_timeout);
  Serial.print("duration = ");
  Serial.print(duration);
  Serial.print(" microseconds;  ");
  
  // Convert duration to distance. Note decimal point here, needed to get floating point calculation.
  distance = duration * 343.0 / 1000 / 2;
  Serial.print("distance = ");
  Serial.print(distance);
  Serial.println(" mm");
}

Hackers – Basic Arduino inputs and outputs

Rheostat_bb

This week in the Hackers group at CoderDojo Athenry, we built on last week’s work on blinky lights, in which we made a simple circuit involving LEDs and resistors connected to an Arduino, and wrote code to get the LEDs to blink.

An LED is an example of an output from our microcontroller. We would also like to have inputs. Examples of circuit inputs are:

  • Switches
  • Dials
  • Sensors that measure something

We focused on dials, specifically a variable resistor or rheostat. This is the kind of knob or dial you find on dimmer switches, volume controls on old radios, electric guitars, and many others.

A variable resistor has 3 connectors: the two outer ones connect across a voltage source (e.g. 5V and ground pins on the Ardiuno) and the voltage at the middle pin can be adjusted from 0 to 5V by turning the knob.

We connected the middle pin of the variable resistor to Analog input 2 of the Arduino. The connections are shown above.

Then, the code to read its value is:

potValue = analogRead(potPin);

where potValue and potPin are ints that were defined already.

The value that you get is in the range 0-1024, and changes as you turn the dial.

Here is a full Arduino program to read a value and display it on the Serial Monitor window if you have a computer connected to your Arduino:

int potPin = 2;    // select the input pin for the potentiometer
int potValue = 0;  // value to read from potentiometer

void setup() {
  Serial.begin(9600);  // need for print commands later
}

void loop() {
  potValue = analogRead(potPin);    // read the value from the sensor
  Serial.println(potValue);
}

In the group, we used this as the basis to improve last week’s program. This time, the speed at which the LED blinks is controlled by turning the potentiometer dial.

The previous code to control how long the LED blinks for was:

delay(one_second);

We changed this to:

delay(potValue);

Of course, we also had to add the code to read the potentiometer value at the top of the loop() function.

Hackers – blinky lights

Today we built our first circuits on a breadboard.

A breadboard is used to try out electronic circuits and figure out what works.  Once we are happy with a circuit we can make a permanent version on something like strip-board.

Breadboards have blue and red lines across the top and bottom.  A wire strip runs across the board under each line.  If we connect a power source to any point on the lines, all of the points (holes) on the line receive the power.

The middle area of the board has wire strips running vertically.  A wire strip runs down the board under each line of holes.  If we connect a power source to any point on the lines, all of the points (holes) above or below receive power.

The first circuit was one to power a single LED:

circuit01_bb.png
We used the Arduino here as a simple 5V battery.  Current flows from the 5V pin on the Arduino, through the resistor, then the LED, and on to the GND pin on the Arduino.  We should always used a resistor with an LED to protect it.  It doesn’t take much current to damage an LED.

This has the LED on permanently – not very exciting, but good to get started with.  It’s a good idea to start with a minimal circuit and build up to the more complicated circuit we actually want.  That way, we can test and verify as we go, so that we don’t have too much testing and backtracking to do if something goes wrong.

It took a while to get everyone’s circuit working.  Some of the LEDs had legs that were the same length, and there was no obvious way to see which one was the anode or cathode, so we had to guess and test.
Some of the resistors we took at random from the box were too high:  200 kΩ, for example, so the LEDs wouldn’t light up.  We found some 220 Ω (red-red-brown) and 330Ω (orange-orange-brown) resistors to get us going.
Some of the LEDs were very dim.  180 Ω resistors (brown-grey-brown) helped there.
We did a quick calculation to see what value of resistor we really needed:

According to the spec sheet, our LEDs had a forward voltage of 2.2 V and a forward current of 20 mA. In other words, the voltage drop across the LED is 2.2 V, and they can draw up to 0.02 A without burning out.
If our supply is 5 V, then the voltage across the resistor is 5 – 2.2 = 2.8 V.  This is Kirchoff’s Voltage Law.
Applying Ohm’s Law (V = RI), 2.8 = R*0.02, so R = 2.8/0.02 = 140 Ω.
A 140 Ω resistor will make our LED as bright as possible. Less than that will burn out the LED. More than that will produce a dimmer light. So, 180, 220, and 330 Ω are all fine.
Different LEDs have different forward voltages and currents, so it’s important to keep and consult the specification sheets before using them.

The next step in our circuit building was to connect the Arduino’s ground pin to the ground rail on the breadboard.  Then we connected the negative (cathode) pin of the LED to the ground rail.  This is an important step in circuit building:  using a common ground for all our circuits on one board.  It allows us to only have one wire running back to the Arduino ground, instead of one for each circuit.  We would run out of space on the Arduino very quickly otherwise.
Next we did the same on the positive side. This isn’t necessarily as useful as the common ground as we’ll see later.

Once we were happy that we all had a working circuit, we moved on to use the Arduino to control the LED.
We did this by taking the wire that went to the 5V pin on the Arduino and plugging it into digital pin 12 instead.  We went back to our Arduino sketches and defined a new integer variable, ledPin, and gave it a value of 12 to match where we plugged it in.
Then we changed every occurrence of LED_BUILTIN in our sketches from last week to ledPin instead.  The Find (Replace with) function on the Edit menu of the IDE was helpful here.

Once we compiled the sketch and uploaded it to the Arduino, we had the LED on
the breadboard blinking our messages, just like the internal LED was last week.

Next, we added a second LED and resistor to the board, and wired it up the same as the first.  The positive side of the resistor was connected to the positive power rail, and from there on to the Arduino. Now both LEDs blinked together.
To get them to blink separately, we took the wire from our second LED going to the positive rail and plugged it into digital pin 8 on the Arduino.

circuit06_bb.png

Then we created a new variable in our sketch, led2Pin, with a value of 8.
We added setup code for pin 8.  Finally, we added two more lines to the loop, to have the output to LED 2 go low after LED 1 was set high, and vice versa.
The outcome was LED 2 was on when LED 1 was off and LED 2 was off when LED 1 was on.
Some demonstration code is shown below.

// Blink 2 LEDs: one on, one off
// Demonstration for CoderDojo Athenry

int led1Pin = 12;
int led2Pin = 8;

int one_second = 1000;  // delay() function expects milliseconds

void setup() {
  pinMode(led1Pin, OUTPUT);
  pinMode(led1Pin, OUTPUT);
}

void loop() {
  digitalWrite(led1Pin, HIGH);  // on
  digitalWrite(led2Pin, LOW);
  delay(one_second);
  digitalWrite(led1Pin, LOW);  // off
  digitalWrite(led2Pin, HIGH);
  delay(one_second);
}

Hackers – From Programming in Scratch to Programming in C

CoderDojo-Hackers-IntroToC

Maybe you can already program in a language like C, you just don’t know that you know it yet?

This week at Hackers, we had some wide-ranging discussion about:

  • Turing Equivalence (the idea that different programming languages are can do the same job, if they have some key features)
  • Alan Turing (computer scientist and code-breaker, after whom Turing equivalence is named)
  • The Turing Test (Alan Turing’s test for whether an AI system can be considered to be intelligent)

Our main focus, however, was on relating a programming language that everyone is familiar with, Scratch, with the language that is used to program Arduino, which is based on C/C++. C and C++ are professional programming languages, text based, that don’t look much like Scratch.

However, it turns out that they share important key features that make them Turing equivalent, and these are the basis for basically all major programming languages:

  • Variables and operators
  • Loops
  • Decisions

Therefore, if you can come up with an idea of out how to write a program in Scratch, you can probably translate that idea into a language like C.

Here are the notes in PDF: CoderDojo-Hackers-IntroToC

We also spent a bit of time lighting an LED by connecting it to a battery in series with a resistor. Next week, we will use this as the starting point for making an Arduino-controlled electrical circuit.

led+resistor+battery

 

 

Hackers – Starting Programming Arduino

arduino

In our first week in the Hackers group, we began with an intro to what we do, which is to help people work on their own projects. In the first few weeks, we will focus on learning some useful technologies that people can then start applying to their own work.

Everyone introduced themselves and talked about what projects, if any, they planned to work on, and the mentors suggested some possible technologies that may be useful.

We decided to start by learning how to program the Arduino, which is a microcontroller that runs one program at a time – as soon as it is powered up, it runs the code in a function called setup(), and then it keeps running code in a function called loop().

Arduino is programmed in a version of the C Programming Language, which is a very well-known language.

To write a new program for Arduino, you connect it to a computer and use the Arduino IDE (interactive development environment), which we downloaded here: https://www.arduino.cc/en/Main/Software

Arduino is mainly used to control hardware, and we will see how to do that in future weeks. For this week, we did not control external hardware, but just a built-in LED.

We began by following this tutorial to write code to make an LED blink: https://www.arduino.cc/en/tutorial/blink

Then we started expanding it …

  • We decided to flash an SOS message in Morse Code
  • We found out that a dash is 3 times as long as a dot, and the interval is the same length as a dot
  • We found out that you need a short delay at the end of each letter (3 dots long) and a longer one at the end of each word (7 dots long)
  • We made functions for dot(), dash(), and letters such as S and O
  • We looked up Morse Code for the other letters, and wrote functions for them
  • We added a variable so we could control the speed of the flashes

Here is one version of the final Arduino program. Note that it is incomplete, it just has a few of the letters of the alphabet.

// Code by Michael from CoderDojo Athenry.
// A program to display messages in Morse Code by flashing an LED.
// This is not complete - just some examples.

int interval = 300; // this controls the speed of messages in milliseconds

void setup() {
  // Set up the LED as an output pin. The built-in LED is represented by LED_BUILTIN.
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // Keep repeating our message over and over.
  A(); // Morse code for a letter
  B();
  S();
  endword(); // At the end of each word there is an extra delay
}

void dot() {
  digitalWrite(LED_BUILTIN, HIGH); // send 5 volts
  delay(interval);
  digitalWrite(LED_BUILTIN, LOW); // send 0 volts  
  delay(interval);
}

void dash() {
  digitalWrite(LED_BUILTIN, HIGH); // send 5 volts
  delay(3 * interval);
  digitalWrite(LED_BUILTIN, LOW); // send 0 volts 
  delay(interval);
}

void endword() {
  digitalWrite(LED_BUILTIN, LOW); // send 0 volts  
  delay(4 * interval);
}

void endletter() {
  digitalWrite(LED_BUILTIN, LOW); // send 0 volts  
  delay(2 * interval);
}

void A() {
  dot();
  dash();
  endletter(); 
}

void B() {
  dash();
  dot();
  dot();
  dot();
  endletter(); 
}

void S() {
  dot();
  dot();
  dot(); 
  endletter(); 
}

void O() {
  dash();
  dash();
  dash();  
  endletter(); 
}

Hackers – code for our first prototype remote-controlled robot

Here is a video of the first tests of our remote-controlled robot with 2-wheel drive.

The control for this is based on the calculations we described in an earlier post: https://coderdojoathenry.org/2019/02/24/hackers-how-to-control-a-robots-wheel-motors-based-on-joystick-movements/

Here is the code:

// Code by Luke Madden, CoderDojo Athenry, with some comments added by Michael.
// This code controls a robot with 2-wheel drive, based on movements of a joystick.

// These are the motor H bridge control pins
#define in1 8
#define in2 9
#define in3 10
#define in4 11

// These hold values read from channels of the LemonRX receiver
int ch1;
int ch2; // not currently used
int ch3;

// These are the min and max values we read on each channel when we move the joystick
int joymin = 950;
int joymax = 1950;

// X and Y are joystick values in range -1 to +1
float X;
float Y;

// M1 and M2 are values for Motors 1 and 2, in range -1 to +1
int M1;
int M2; 

void setup() {
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);

  Serial.begin(9600);
}

void loop() {

  // read pulse width values from each channel of lemonRX
  ch1 = pulseIn(5, HIGH, 25000);
  ch2 = pulseIn(6, HIGH, 25000);
  ch3 = pulseIn(7, HIGH, 25000);

  // Convert them to floats in range -1 to 1: map uses int, so set it to int in range -1000 to 1000 and then divide by 1000.0
  X = map(ch1, joymin, joymax, -1000, 1000)/1000.0;
  Y = map(ch3, joymin, joymax, -1000, 1000)/-1000.0;

  // This is the fomula for how much power to send to each motor
  // Motor values should be in range -255 to 255, not -1 to 1, so multiply by 255
  M1 = (X + Y) * 255;
  M2 = (X - Y) * 255;

  // Our fomula can end up with values greater than 255, so constrain them to this range
  M1 = constrain(M1, -255, 255);
  M2 = constrain(M2, -255, 255);

  // Call our function to actually drive the motors
  drive(M1,M2);

  // print out for debugging
  Serial.print("Channels: C1=\t"); // Print the value of
  Serial.print(ch1);        // each channel
  Serial.print("\t M1=\t");
  Serial.print(M1);
  Serial.print("\t M2=\t");
  Serial.print(M2);
  Serial.print("\t C3:\t");
  Serial.println(ch3);

  // this delay seems to help reading joystick
  delay(300);
}

void drive(int M1, int M2) {
  // drive both motors at speeds M1, M2 in range -255, 255
  if (M1 > 0) {
    analogWrite(in1, M1);
    analogWrite(in2, 0);
  }
  else {
    analogWrite(in1, 0);
    analogWrite(in2, -M1);
  }

  if (M2 > 0) {
    analogWrite(in3, M2);
    analogWrite(in4, 0);
  }
  else {
    analogWrite(in3, 0);
    analogWrite(in4, -M2);
  }
}

Hackers – How to Steer an Autonomous Wheeled Robot to Drive Towards a Detected Object

During the same session at which we figured out how to translate joystick movements into motor signals for a robot with two drive wheels (https://coderdojoathenry.org/2019/02/24/hackers-how-to-control-a-robots-wheel-motors-based-on-joystick-movements/), we moved on to figuring out how to control the motor so as to steer an autonomous robot towards an object of interest.

Again, we did a bunch of calculations on a whiteboard (see end of post), and I have re-drawn them for this post.

This builds on the previous work, led by Kevin, on object detection in Python: https://coderdojoathenry.org/2018/12/06/hackers-starting-with-object-recognition/

We assume the setup is as follows:

  • We have a robot with two wheels attached to motors, one on the left and one on the right
  • We have code to control the motors for the two wheels (which we call Motor M1 and Motor M2) with a value in the range -1 to 1, where 1 is full speed ahead, 0 is no movement, and -1 is full speed reverse
  • We have a camera mounted on the robot, facing directly ahead
  • We have code to get an image from the camera and can detect an object of interest, and find its centre (or centroid) within the image

The objective is:

  1. If the object is in the middle of the image, robot should go straight ahead (M1=1, M2=1)
  2. If the object is to the right, move forward-right (e.g. M1=1, M2=0.7)
  3. Likewise, if the object is to the left of centre, move forward-left (e.g. M1=0.7, M2=1)
  4. If the object is not found, we turn the robot around in a circle to search for it (M1=1, M2=-1)

The first three of these are illustrated below:

steering

Our solution is to treat this as a variant of what we previously worked out before, where we had a joystick input, where the X direction of the joystick controls forward movement and its Y direction controls whether to move left or right. In this case, we are steering left/right while always moving forward. Therefore, X has a fixed value (X=1) and Y is a value that depends on the direction of the object of interest.

The equations we came up with are:

X = 1 (a fixed value)

Y = (W – HWid) * YMax / HWid

Then use X and Y to calculate the motor control values as before:

M1 = X + Y, constrained to being between -1 and +1

M2 = X – Y, constrained to being between -1 and +1

steering3

Here:

  • X is a fixed positive value: X=1 for full speed, or make it smaller to move forward more slowly
  • Y is calculated from the equation above
  • W is the distance of object’s centre from left edge of the image, in pixels
  • HWid is half the width of the image, in pixels (for example, for a basic VGA image, 640×480, HWid is 640/2 = 320)
  • YMax is a value approximately 0.5, but needs to be calibrated – it depends on how sharply you want your robot to steer towards the object
  • M1 is the control signal for Motor M1, in the range -1 (full reverse) to +1 (full forward)
  • M2 is the same for Motor M2
  • Constrained means: if the calculated value is less than -1, set it to -1; if it is greater than +1, set it to +1.

Here are our calculations on the whiteboard:

whiteboard-calcs2

Hackers – How to Control a Robot’s Wheel Motors Based on Joystick Movements

robot+controller

At our most recent session in the Hackers group in CoderDojo Athenry, we spent out time on practical mathematics, figuring out how, if we want to make a robot that is controlled by a person with a joystick, how exactly do we translate movements of the joystick to signals sent to the motors.

joystick-robot-assumptions

Our assumptions are:

  • We are controlling robot with 2 drive wheels, one on the left and one on the right, like the one shown in the photo above (which we made last year)
  • We assume that we have code to control the motors for the two wheels (which we call Motor M1 and Motor M2) with a value in the range -1 to 1, where 1 is full speed ahead, 0 is no movement, and -1 is full speed reverse
  • To make the robot turn, drive the motors M1 and M2 at different speeds
  • We assume that we have code to receive signals from the joystick, and get X and Y values in the range -1 to 1, as shown in the diagram below

Our approach was to think about what joystick positions (X and Y) should result in what robot movements (M1 and M2), and then see if we could come up a way of expressing M1 and M2 in terms of X and Y. We filled a whiteboard with satisfying diagrams and calculations; see the bottom of this post. I have re-dawn them for clarity below.

The resulting equations are quite simple:

M1 = X + Y, constrained to being between -1 and +1

M2 = X – Y, constrained to being between -1 and +1

Here:

  • M1 is the control signal for Motor M1, in the range -1 (full reverse) to +1 (full forward)
  • M2 is the same for Motor M2
  • X is the forward position of the joystick from -1 (full back) to +1 (full forward)
  • Y is the left/right position of the joystick from -1 (full left) to +1 (full right)
  • Constrained means: if the calculated value is less than -1, set it to -1; if it is greater than +1, set it to +1.

Here is the full set of joystick positions and motor movements that we considered, showing how the equations work:

joystick-all-calcs

We previously figured out how to control motors with a H-bridge controller from an Arduino: https://coderdojoathenry.org/2019/02/07/hackers-controlling-robot-wheels-and-handling-interrupts-in-arduino/

Each motor needs two control signals in the range 0-255, one for forward and one for reverse, so we will need more code to convert our M1 and M2 to what is needed for the H-bridge, but that is a fairly easy job for a different day.

whiteboard-calcs1

Hackers – Controlling Robot Wheels and Handling Interrupts in Arduino

IMG_20190202_135834

Controlling Robot Wheels

Last week, we figured out how to control a motor with a H-bridge. We expanded this to controlling a pair of wheels using the H-bridge. Above is a photo of the hardware. The wiring of the H-bridge is:

  • H-bridge [+] and [-] are connected to a 9V battery
  • H-bridge [IN1] to [IN4] is connected to Arduino Pins 6, 7, 8, 9
  • H-bridge [Motor A] and [Motor B] pins are connected directly to the two motors

Below is Arduino code by Hackers member Luke to control this.

// Luke Madden, CoderDojo Athenry
// Control motors using a H Bridge

// The H bridge has 4 input pins: in1-in4
#define in1 6
#define in2 7
#define in3 8
#define in4 9

int fast = 150;// range 1-255
int slow = 80;// slower speed
int hyperspeed = 255;// hits the hyperdrive

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  drive();
}

 void drive() {
  // Test the functions
  Serial.println("move forward");
  forward();
  delay(2000);

  Serial.println("hit the hyperdrive");
  hyperdrive();
  delay(2000);

  Serial.println("go backwards");
  backwards();
  delay(2000);
}

void forward() {
  //makes motor go forwards
  analogWrite(in1, fast);
  analogWrite(in2, 0);
  analogWrite(in3, fast);
  analogWrite(in4, 0);
}

void hyperdrive() {
  //hits the hyperdrive
  analogWrite(in1, hyperspeed);
  analogWrite(in2, 0);
  analogWrite(in3, hyperspeed);
  analogWrite(in4, 0);
}

void backwards() {
  //makes motor go backwards
  analogWrite(in1, 0);
  analogWrite(in2, fast);
  analogWrite(in3, 0);
  analogWrite(in4, fast);
}

void stopping(){
  //makes it stop
  analogWrite(in1, 0);
  analogWrite(in2, 0);
  analogWrite(in3, 0);
  analogWrite(in4, 0);
}

Handling Interrupts in Arduino

In Arduino, you can set up special functions that are a called depending on the state of some digital pins – these are called Interrupt Service Routines (ISRs). These routines are called separately from the main loop() that is always running, even if the main loop() is in the middle of another operation.

For controlling our robots, our Arduino might receive a signal on a pin, and if we want the robot to react quickly, an ISR can handle it. The ISR can send a signal on a different pin or change the state of a variable.

This code is simple and correctly-working demonstration of how interrupts work. Note that you don’t need to build any circuitry to try this out. A built-in LED on the Arduino, at pin 13, turns on/off depending on whether Pin 2 is connected/disconnected from the the GROUND pin.

There are three main tasks:

  1. Define the ISR function: this is a function declared as void with no arguments: for example, our ISR is called changed and is defined as:
    void changed() { … }
    In our code, it sets the value of a variable called controlState and it turns the LED on/off. Note that the value of controlState is printed out repeatedly in the main program loop, showing how the ISR can change a variable that is used elsewhere.
  2. In the setup() function, set the pin mode of the control pin to INPUT or INPUT_PULLUP (see below for the difference). For example, we have defined the variable control to have value 2 and are setting its mode like this:
    pinMode(controlPin, INPUT_PULLUP);
  3. In setup(), attach the ISR to the pin:
    attachInterrupt(digitalPinToInterrupt(controlPin), changed, CHANGE);

One extra note about the above line of code: all pins have numbers and all interrupts have numbers, and these are not (necessarily) the same numbers. The function digitalPinToInterrupt() returns the interrupt number corresponding to a given digital pin.

Some other things to note:

  • The Interrupt Service Routine (ISR) should be short and run fast: delay() calls are ignored and print() can cause problems.
  • You can’t attach two interrupts to the one pin: use CHANGE and then test pin state
  • If you initiate the pin with INPUT_PULLUP, it is triggered by connecting it to GROUND; otherwise, if you initiate it with INPUT, you need a circuit with 10k resistor.
  • On an Uno, can only attach interrupts to pins 2 and 3.
  • If you are changing a variable in the ISR and need to use it elsewhere, declare it as volatile.

Here is the full Arduino code:

// Michael Madden, CoderDojo Athenry
//
// Test a pin interrupt to which an interrupt service routine (ISR) is attached.
// When the control pin is connected to GROUND, the LED on the board is turned on.

// Things we have figured out:
// * The interrupt service routine (ISR) is a function declared as void with no arguments.
// * It should be short and run fast: delay() calls are ignored and print() can cause problems.
// * You can't attach two interrupts to the one pin: use CHANGE and then test pin state
// * If you initiate the pin with INPUT_PULLUP, it is triggered by connecting it to GROUND;
// * otherwise, with INPUT, you need a circuit with 10k resistor.
// * On an Uno, can only attach interrupts to pins 2 and 3.
// * If you are changing a variable in the ISR and need to use it elsewhere, declare it as volitile.  

const byte controlPin = 2; // Want to react when this pin is triggered
const byte ledPin = 13; // no circuit needed: there is a built in LED on 13
volatile int controlState = 0; // will change this value in ISR

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(controlPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(controlPin), changed, CHANGE);

  Serial.begin(9600);
}

void loop() {
  // The main loop does not do much, it just prints out the value of the
  // control pin's state every 2 seconds.
  Serial.print("Current value of control pin = ");
  Serial.println(controlState);
  delay(2000);
}

void changed()
{
  // This is our interrupt service routine.
  // It is triggered when the control pin changes,
  // so we check its state and turn on/off the LED.
  //
  controlState = digitalRead(controlPin);
  if(controlState > 0) {
    digitalWrite(ledPin, HIGH);
  }
  else {
    digitalWrite(ledPin, LOW);
  }
}

Hackers – Controlling Motors with an Arduino and H-Bridge

Previously in Hackers we have studied how transistors work, and made a transistor-based circuit to control a motor from an Arduino: Hackers – a Joule Thief and Controlling Motors.

When you write to a pin on the Arduino, it outputs a voltage. However, you can’t use this directly to drive an electric motor, because they require too much current, and it would damage the Arduino. The solution is to use a 6V battery as an external power supply, and connect it to the motor via a transistor circuit. When you apply a signal with small current to the middle leg of the transistor, a much larger current can flow from the battery to the motor.

While this works, a more elaborate circuit is needed if you want to be able to control two motors, and make them go backwards and forwards. This circuit is called a Dual H-Bridge. The Wikipedia page has technical details: https://en.wikipedia.org/wiki/H_bridge

We are using a pre-built integrated circuit for our H-Bridge, as they are low-cost, small, and work well. Here is the one we are using:

h-bridge

It has several connectors:

  • [+] and [-] are where the external battery is connected
  • [IN1] and [IN2] control Motor A (details below)
  • [IN3] and [IN4] control Motor B
  • [Motor A] and [Motor B] each have two pins that are connected directly to motors

To control Motor A, connect [IN1] and [IN2] to two pins of the Arduino, such as 6 and 7:

  • [IN1] HIGH and [IN2] LOW: Motor A goes forward full speed
  • [IN1] LOW and [IN2] HIGH: Motor A goes backward full speed
  • Both LOW: Motor A does not turn (no power, it coasts)
  • Both HIGH: Motor A does not turn (is braked)
  • To control speed, use a value for the pins connected to [IN1] or [IN2] in the range 0-255 (0=LOW, 255=HIGH)

Here is Arduino code to control a motor with a H-Bridge, written by Luke, one of our Hackers:

// Luke Madden, CoderDojo Athenry
// Control motors using a H Bridge

// The H bridge has 4 input pins: in1-in4
#define in1 6
#define in2 7

int fast = 100;// range 1-255
int slow = 50;// slower speed
int hyperspeed = 255;// hits the hyperdrive

void setup() {
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  drive();
}

 void drive() {
  // Test the functions
  Serial.println("move forward");
  forward();
  delay(2000);

  Serial.println("hit the hyperdrive");
  hyperdrive();
  delay(2000);

  Serial.println("go backwards");
  backwards();
  delay(2000);
}

void forward() {
  //makes motor go forwards
  analogWrite(in1, fast);
  analogWrite(in2, 0);
}

void hyperdrive() {
  //hits the hyperdrive
  analogWrite(in1, hyperspeed);
  analogWrite(in2, 0);
}

void backwards() {
  //makes motor go backwards
  analogWrite(in1, 0);
  analogWrite(in2, slow);
}

void stopping(){
  //makes it stop
  analogWrite(in1, 0);
  analogWrite(in2, 0);
}