Actuators


By Prof. Seungchul Lee
http://iai.postech.ac.kr/
Industrial AI Lab at POSTECH

Table of Contents

1. Actuators

  • Devices that cause something to happen in the physical world
  • Outputs of the IoT device
    • Visual: LED, LCD, monitor
    • Audio: buzzer, speaker
    • Motion: motors, valve, pump
  • Physical Output

    • DC motor

    • Servo motor

    • Stepper motor

2. Visual Outputs

2.1. Segments

  • A 7 Segment LED Display is a electronic device that contains an array of 8 individual LEDs.
  • The 7 Segment LED Display we will be using for the lab is a Common Anode type.
    • Unlike the LEDs we have been using, the LED will be turned on if the value of the pin is LOW.
    • Please refer to the video below for more information.
In [1]:
%%html
<iframe src="https://www.youtube.com/embed/Irgz_qy27qc" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Lab 1: 7 Segment

  • Turn all leds in 7 segment

  • With 390 ohm resistor

  • When a pin is LOW, the corresponding LED is on.

const int a = 2;
const int b = 3;
const int c = 4;
const int d = 5;
const int e = 6;
const int f = 7;
const int g = 8;
const int dp = 9;

void setup()
{
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(dp, OUTPUT);
}
void loop()
{  
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  digitalWrite(dp, LOW);
  delay(1000);
}

Lab 2: 7 Segment LED Counter from 0 to 9

  • With 390 ohm resistor

In [2]:
%%html
<iframe src="https://www.youtube.com/embed/f_W370eWKxE" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Naive code

const int a = 2;
const int b = 3;
const int c = 4;
const int d = 5;
const int e = 6;
const int f = 7;
const int g = 8;

void setup()
{
  pinMode(a, OUTPUT);
  pinMode(b, OUTPUT);
  pinMode(c, OUTPUT);
  pinMode(d, OUTPUT);
  pinMode(e, OUTPUT);
  pinMode(f, OUTPUT);
  pinMode(g, OUTPUT);
}
void loop()
{
  //Display 0
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, HIGH);
  delay(1000);

  //Display 1
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
  delay(1000);

  //Display 2
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, HIGH);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 3
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 4
  digitalWrite(a, HIGH);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 5
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 6
  digitalWrite(a, LOW);
  digitalWrite(b, HIGH);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 7
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, HIGH);
  digitalWrite(e, HIGH);
  digitalWrite(f, HIGH);
  digitalWrite(g, HIGH);
  delay(1000);

  //Display 8
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, LOW);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  delay(1000);

  //Display 9
  digitalWrite(a, LOW);
  digitalWrite(b, LOW);
  digitalWrite(c, LOW);
  digitalWrite(d, LOW);
  digitalWrite(e, HIGH);
  digitalWrite(f, LOW);
  digitalWrite(g, LOW);
  delay(1000);
}

Using 2D array

byte digits[10][7] = {
  {0, 0, 0, 0, 0, 0, 1}, // 0
  {1, 0, 0, 1, 1, 1, 1}, // 1
  {0, 0, 1, 0, 0, 1, 0}, // 2
  {0, 0, 0, 0, 1, 1, 0}, // 3
  {1, 0, 0, 1, 1, 0, 0}, // 4
  {0, 1, 0, 0, 1, 0, 0}, // 5
  {0, 1, 0, 0, 0, 0, 0}, // 6
  {0, 0, 0, 1, 1, 1, 1}, // 7
  {0, 0, 0, 0, 0, 0, 0}, // 8
  {0, 0, 0, 1, 1, 0, 0}  // 9
};

void displayDigit(int num) {
  int pin = 2;
  for (int i = 0; i < 7; i++) {
    digitalWrite(pin + i, digits[num][i]);
  }
}

void setup() {
  for (int i = 2; i < 10; i++) {
    pinMode(i, OUTPUT);
  }
  digitalWrite(9, HIGH);
}

void loop() {
  for (int i = 0; i < 10; i++) {
    delay(1000);
    displayDigit(i);
  }
}

Lab 3: 7 Segment LED Counter with Buttons

  • Controlling the display with 2 push buttons to count up and down
  • 390 ohm and 2 $\times$10k ohm

In [3]:
%%html
<iframe src="https://www.youtube.com/embed/0VLL_Gqmwuw" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#define PLUS 11
#define MINUS 12

int digit = 0;

byte digits[10][7] = {
  {0, 0, 0, 0, 0, 0, 1}, // 0
  {1, 0, 0, 1, 1, 1, 1}, // 1
  {0, 0, 1, 0, 0, 1, 0}, // 2
  {0, 0, 0, 0, 1, 1, 0}, // 3
  {1, 0, 0, 1, 1, 0, 0}, // 4
  {0, 1, 0, 0, 1, 0, 0}, // 5
  {0, 1, 0, 0, 0, 0, 0}, // 6
  {0, 0, 0, 1, 1, 1, 1}, // 7
  {0, 0, 0, 0, 0, 0, 0}, // 8
  {0, 0, 0, 1, 1, 0, 0} // 9
};

void displayDigit(int num) {
  int pin = 2;
  for (int i = 0; i < 7; i++) {
    digitalWrite(pin + i, digits[num][i]);
  }
}

void setup() {
  pinMode(PLUS, INPUT);
  pinMode(MINUS, INPUT);

  for (int i = 2; i < 10; i++) {
    pinMode(i, OUTPUT);
  }
  digitalWrite(9, HIGH);
}

void loop() {
  if (digitalRead(PLUS) == HIGH) {
    ++digit;
    if (digit > 9) {
      digit = 0;
    }
  }

  if (digitalRead(MINUS) == HIGH) {
    --digit;
    if (digit < 0) {
      digit = 9;
    }
  }
  displayDigit(digit);
  delay(100);
}

2.2. LCD Display

  • Liquid crystal displays (LCDs) are commonly used to display data in devices such as calculators, microwave ovens, and many other electronic devices.
  • The LiquidCrystal library allows you to control LCD displays.
  • Syntax
    • LiquidCrystal(rs, enable, d4, d5, d6, d7)
    • LiquidCrystal(rs, rw, enable, d4, d5, d6, d7)
    • LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7)
    • LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7)
  • Parameters

    • rs: the number of the Arduino pin that is connected to the RS pin on the LCD

    • rw: the number of the Arduino pin that is connected to the RW pin on the LCD (optional)

    • enable: the number of the Arduino pin that is connected to the enable pin on the LCD

    • d0, d1, d2, d3, d4, d5, d6, d7: the numbers of the Arduino pins that are connected to the corresponding data pins on the LCD. d0, d1, d2, and d3 are optional; if omitted, the LCD will be controlled using only the four data lines (d4, d5, d6, d7).

  • A potentiometer will be used to control the contrast of the LCD
    • Note that a 1 k ohm potentiometer may be used instead of a 10k ohm (The change rate of the contrast will be faster)

In [4]:
%%html
<iframe src="https://www.youtube.com/embed/85LvW1QDLLw"
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Lab 4: Simple and Static LCD Display

In [5]:
%%html
<iframe src="https://www.youtube.com/embed/OqLmj_BVOVw" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#include <LiquidCrystal.h>

// initialize the library by providing the nuber of pins to it
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);

  // set cursor position to start of first line on the LCD
  lcd.setCursor(0, 0);
  //text to print
  lcd.print("   16x2 LCD");
  // set cusor position to start of next line
  lcd.setCursor(0, 1);
  lcd.print("   DISPLAY");
}

void loop() {

}

Lab 5: LCD Counter

In [6]:
%%html
<iframe src="https://www.youtube.com/embed/24v2BrXJApw" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#include <LiquidCrystal.h>

int cnt = 0;

// initialize the library by providing the nuber of pins to it
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);

  // set cursor position to start of first line on the LCD
  lcd.setCursor(0, 0);
  //text to print
  lcd.print("    COUNTER");
  delay(100);

  lcd.setCursor(0, 1);
  lcd.print("       ");
  lcd.print(cnt);
}

void loop() {
  cnt = cnt + 1;
  delay(1000);
  lcd.setCursor(0, 1);
  lcd.print("       ");
  lcd.print(cnt);
}

Note

  • Only basic methods of the LiquidCrystal class are illustrated in this lecture.
  • For more information, see Arduino LiquidCrystal Library

Check the below simple game using LCD

In [7]:
%%html
<iframe src="https://www.youtube.com/embed/oX6Z890Zd2A?start=9" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

3. Physical Outputs

In [8]:
%%html
<iframe src="https://player.vimeo.com/video/84274150" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

3.1. DC Motor

Two terminals

  • when you apply direct current to one terminal and ground the other, the motor spins in one direction.

  • When you apply current to the other terminal and ground the first terminal, the motor spins in the opposite direction.

Control DC motor

  • By switching the polarity of the terminals, you can reverse the direction of the motor.

  • By varying the current supplied to the motor (analog $\rightarrow$ PWM), you vary the speed of the motor.

In [9]:
%%html
<iframe src="https://www.youtube.com/embed/j6D9-GKhAyc" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

3.1.1. Transistor

The small DC motor, is likely to use more power than an Arduino digital output can handle directly. If we tried to connect the motor straight to an Arduino pin, there is a good chance that it could damage the Arduino. Due to the fact that drawing too much current from the Arduino may damage the circuit, transistors are often used to modulate the current flow.

A small transistor can be used as a switch that uses just a little current from the Arduino digital output to control the much bigger current of the motor.

The transistor that we will be using for the lab may have a slightly different layout from some references, so please be sure to make sure that you have checked the layout of the transistor. Right below is the pin layout of the transistor.


The transistor has three leads. Most of the electricity flows from the Collector to the Emitter, but this will only happen if a small amount is flowing into the Base connection. This small current is supplied by the Arduino digital output.

Water Analogy

1) On (when $V_B$ is high)

2) Off (when $V_B$ is low)

3) Linear flow control (when $V_B$ is PWM)

The diagram below is called a schematic diagram. Like a breadboard layout, it is a way of showing how the parts of an electronic project are connected together.

The pin D3 of the Arduino is connected to the resistor. Just like when using an LED, this limits the current flowing into the transistor through the base.

Diode

There is a diode connected across the connections of the motor. Diodes only allow electricity to flow in one direction (the direction of their arrow).

When you turn the power off to a motor, you get a negative spike of voltage, that can damage your Arduino or the transistor. The diode protects against this, by shorting out any such reverse current from the motor.

In [10]:
%%html
<iframe src="https://www.youtube.com/embed/4EpZKJsYl1o" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
int transistorPin = 3;

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

void loop() {
  digitalWrite(transistorPin, HIGH);
  delay(1000);
  digitalWrite(transistorPin, LOW);
  delay(1000);
}

3.1.2. Speed

  • Speed is proportional to the supplied voltage.
  • The most effective way to adjust the speed via Arduino is by using pulse width modulation (PWM).
  • You pulse the motor on and off at varying rates, to simulate an analog voltage.


In [11]:
%%html
<iframe src="https://player.vimeo.com/video/93555504" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Lab 7: DC Motor Speed Control

int transistorPin = 3;                  // connected to the base of the transistor
int speed = 100;

void setup() {
  pinMode(transistorPin, OUTPUT);       // set  the transistor pin as output:
}

void loop() {  
  analogWrite(transistorPin, speed);    // use that to control the transistor:
}

3.1.3. Direction

The rotational direction of a DC motor can be reversed by switching the polarity of the applied DC voltage. However, this is not practical in an electronic control system.

You can use switching arrangement known as an H-bridge, consisting of four switches with the motor in the center.

  • When switches 1 and 4 are closed and 2 and 3 are open, voltage flows from the supply to 1 to the motor to 4 to ground.
  • When 2 and 3 are closed and 1 and 4 are open, polarity is reversed, and voltage flows from the supply to 3 to the motor to 2 to ground.


Below is a diagram of the H-bridge and which pins do what in our example. Included with the diagram is a truth table indicating how the motor will function according to the state of the logic pins (which are set by our Arduino).

The L293NE/SN754410 is a very basic H-bridge. It has two bridges, one on the left side of the chip and one on the right, and can control 2 motors.

In [12]:
%%html
<iframe src="https://player.vimeo.com/video/100357623?portrait=0" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Lab 8: DC Motor Direction Control Using an H-Bridge


In [13]:
%%html
<iframe src="https://www.youtube.com/embed/uzIj4oR1ws0" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
const int switchPin = 2;    // switch input
const int motor1Pin = 3;    // H-bridge leg 1 (pin 2, 1A)
const int motor2Pin = 4;    // H-bridge leg 2 (pin 7, 2A)
const int enablePin = 9;    // H-bridge enable pin

void setup() {
  // set the switch as an input:
  pinMode(switchPin, INPUT);

  // set all the other pins you're using as outputs:
  pinMode(motor1Pin, OUTPUT);
  pinMode(motor2Pin, OUTPUT);
  pinMode(enablePin, OUTPUT);  

  // set enablePin high so that motor can turn on:
  digitalWrite(enablePin, HIGH);
}

void loop() {
  // if the switch is high, motor will turn on one direction:
  if (digitalRead(switchPin) == HIGH) {
    digitalWrite(motor1Pin, LOW);   // set leg 1 of the H-bridge low
    digitalWrite(motor2Pin, HIGH);  // set leg 2 of the H-bridge high
  }
  // if the switch is low, motor will turn in the other direction:
  else {
    digitalWrite(motor1Pin, HIGH);  // set leg 1 of the H-bridge high
    digitalWrite(motor2Pin, LOW);   // set leg 2 of the H-bridge low
  }
}

3.2. Servo Motor

The position of the servo motor is set by the length of a pulse. The servo expects to receive a pulse roughly every 20 milliseconds (50 Hz). If that pulse is high for 1 millisecond, then the servo angle will be zero, if it is 1.5 milliseconds, then it will be at its center position and if it is 2 milliseconds it will be at 180 degrees.

  • A servo is different from regular motors in that it has a position sensor, which allows to postion it precisely to a certain angle.

  • The 'position sensor' is often a potentiometer mechanically connected to the actuator shaft.

  • The resistance value of the potentiometer is compared with the desired position by a motor controller. The controller moves the moter until the position is matched.

In [14]:
%%html
<iframe src="https://player.vimeo.com/video/93608912" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
In [15]:
%%html
<iframe src="https://www.youtube.com/embed/qatqVNh9uj4" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Lab 9: Controlling the Position of a Servo

You want to control the position of a servo using an angle. Use the Servo library distributed with Arduino.


In [16]:
%%html
<iframe src="https://www.youtube.com/embed/r59k-1LGjH8" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#include <Servo.h>

Servo myservo;        // create servo object to control a servo
int angle = 0;        // variable to store the servo position

void setup()
{
  myservo.attach(9);  // attaches the servo on pin 10 to the servo object
}

void loop()
{
  for (angle = 0; angle < 180; angle += 1) // goes from 0 degrees to 180 degrees
  { // in steps of 1 degree
    myservo.write(angle); // tell servo to go to position in variable 'angle'
    delay(20);            // waits 20ms between servo commands
  }
  for (angle = 180; angle >= 1; angle -= 1) // goes from 180 degrees to 0 degrees
  {
    myservo.write(angle);   // tell servo to go to position in variable 'angle'
    delay(20);            // waits 20ms between servo commands
  }
}

Lab 10: Controlling a Servo with a Potentiometer or Sensor

You want to control one or two servos with a potentiometer.


In [17]:
%%html
<iframe src="https://www.youtube.com/embed/wybU2--v7ME" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#include <Servo.h>

Servo myservo;    // create servo object to control a servo
int potpin = 0;   // analog pin used to connect the potentiometer
int val;          // variable to read the value from the analog pin

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  val = analogRead(potpin);         // reads the value of the potentiometer
  val = map(val, 0, 1023, 0, 179);  // scale it to use it with the servo
  myservo.write(val);               // sets position to the scaled value
  delay(15);                        // waits for the servo to get there
}

Advanced Servo

Besides the servo library provided in Arduino, you may control the servo without using the library.

In [18]:
%%html
<iframe src="https://www.youtube.com/embed/BSUqhNZYBxY" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
#define SERVO_MIN_PULSE_WIDTH 544  // microseconds
#define SERVO_MAX_PULSE_WIDTH 2400 // microseconds
#define SERVO_MIN_PULSE_CYCLE 20000 // 20 ms -> 50Hz

unsigned long lCyclePrevTime = 0; // micro sec.
unsigned long lCycleCurrTime = 0; // micro sec.
unsigned long lPulseOnPrevTime = 0; // micro sec.
unsigned int nInput = SERVO_MIN_PULSE_WIDTH;


void setup() {
  // put your setup code here, to run once:
  // Serial communication set
  Serial.begin(9600);

  // Pin mode set
  pinMode(9, OUTPUT);
  digitalWrite(9, LOW);

}

void loop() {
  // put your main code here, to run repeatedly:
  lCyclePrevTime = micros();
  while (1)
  {
    // Serial input
    if (Serial.available())
    {
      nInput = Serial.parseInt();
      if (nInput > 180) nInput = 180;
      else if (nInput < 0) nInput = 0;
      //
      nInput = map(nInput, 0, 180, SERVO_MIN_PULSE_WIDTH,  SERVO_MAX_PULSE_WIDTH);
      Serial.println(nInput);
    }

    lCycleCurrTime = micros();
    if (lCycleCurrTime - lCyclePrevTime >= SERVO_MIN_PULSE_CYCLE)
    {
      lCyclePrevTime = lCycleCurrTime;

      lPulseOnPrevTime = micros();
      digitalWrite(9, HIGH);
      while (1)
      {
        if (micros() - lPulseOnPrevTime >= nInput)
        {
          digitalWrite(9, LOW);
          break;
        }
      }
    }
  }
}

Demo: Robotic Hand with Servo Motor and Flexible Sensor

In [19]:
%%html
<iframe src="https://www.youtube.com/embed/qMtHEOxHDGo" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

Online Tutorial: Servo motor and transisitors by Jeremy Blum

In [20]:
%%html
<iframe src="https://www.youtube.com/embed/5bHPKU4ybHY" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>

3.3 Stepper Motor (Optional)

In [21]:
%%html
<iframe src="https://www.youtube.com/embed/PEwpAoLKzVc"
width="560" height="315" frameborder="0" allowfullscreen></iframe>
In [22]:
%%html
<iframe src="https://www.youtube.com/embed/bkqoKWP4Oy4"
width="560" height="315" frameborder="0" allowfullscreen></iframe>

3.4. Summary

In [23]:
%%html
<iframe src="https://www.youtube.com/embed/3A-pcONMSWI" 
width="560" height="315" frameborder="0" allowfullscreen></iframe>
In [24]:
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')