Bluetooth-Controlled Mini Lift Using Stepper Motor with Android Mobile App

Overview

This Mini Lift project is achieved with the use of a stepper motor. The motor will rotate either clockwise or counterclockwise depending if you want it to go up or down, controlled by a mobile app with Bluetooth. Additionally, the TFT LCD display is to show the user which floor it is currently on as well as when it is moving.


Hardware Used


  • Stepper Motor NEMA 17 (17HS4401) – 1
  • 
    5mmx8mm Motor Shaft Coupling – 1
  • 
    Stepper Motor Driver DRV8825 – 1
  • 
    
  • HC-05 Bluetooth Module – 1
  • 
    2.2-inch TFT LCD Display ILI9341 (240×320) – 1
  • 
    47Ω Resistor – 1
  • 
    100uF Capacitor – 1
  • 
    Breadboard – 1
  • 
    
  • 9V Power Supply – 1
  • Jumper Wires
  • 
    
  • Rubber Belt / String
  • Container / Platform
  • Software Used

    Libraries Used


    Application Description

    Stepper Motor NEMA 17

    A stepper motor, also known as step motor or stepping motor, is a type of brushless DC electric motor. Very precise positioning and speed control can be achieved with a computer controlled stepping. For this reason, stepper motors are the motor of choice for many precision motion control applications. 

    How does it work?

    Stepper motors divide a full rotation into a number of equal steps. They have multiple coils that are organized in groups called phases. By using electromagnets to energize each phase in sequence, the motor will rotate, one step at a time.

    Specifications:

    • Phase: 2
    • Step Angle: 1.8 degrees
    • Step angle accuracy: +/- 5% (full step, not load)
    • Rated Current: 1.3 A
    • Phase Resistance: 2.4 Ω
    • Resistance accuracy: +/- 10%
    • Phase Inductance: 2.8 mH
    • Inductance accuracy: +/- 20%
    • Holding Torque: 28 N.cm
    • Detent Torque: 1.6 N.cm
    • Rotor Inertia: 34 g.cm²

    Stepper Motor Driver DRV8825

    The DRV8825 stepper motor driver features adjustable current limiting, over-current protection, over-temperature protection, and six microstep resolutions (down to 1/32-step). It operates from 8.2 V to 45 V and can deliver up to approximately 1.5 A per phase without a heat sink or forced air flow (rated for up to 2.2 A per coil with sufficient additional cooling).

    How does it work?

    The stepper motor driver is the circuit that controls how the stepper motor operates. It works by sending current through various phases in pulses to the stepper motor. The DRV8825, which is a microstepping driver, allows higher resolutions by allowing intermediate step locations, which are achieved by energizing the coils with intermediate current levels.

    Specifications:

    • Operating Voltage: 8.2-45 V
    • Continuous current per phase: 1.5 A
    • Maximum current per phase: 2.2 A
    • Logic Voltage: 2.5-5.25 V
    • Microstep Resolutions: Full, 1/2, 1/4, 1/8, 1/16, and 1/32

    HC-05 Bluetooth Module

    The HC-05 Bluetooth Module is an easy to use Bluetooth SPP (Serial Port Protocol) module, designed for transparent wireless serial connection setup. It is one of the highest rated and used wireless communication protocols in embedded projects due to its low cost and wide range of applications.

    How does it work?

    Serial port Bluetooth module is fully qualified Bluetooth V2.0+EDR (Enhanced Data Rate) 3Mbps Modulation with complete 2.4GHz radio transceiver and baseband. It uses CSR Bluecore 04-External single chip Bluetooth system with CMOS technology and with Adaptive Frequency Hopping feature. In layman’s terms, the Bluetooth technology manages the wireless communication channel. The Bluetooth modules can transmit and receive the data wirelessly. It communicates via serial communication which makes an easy way to interface with a microcontroller.

    Specifications:

    • Input Voltage: 5 V
    • Communication Method: Serial
    • Frequency: 2.4 GHz
    • Default PIN/password: 1234
    • Master and slave mode can be switched

    2.2-inch TFT LCD Display ILI9341 (240×320)

    TFT LCD is short for thin-film-transistor liquid-crystal display. It is a variant of a LCD that uses thin-film transistor technology to improve image qualities such as addressability and contrast. These are commonly used in appliances including computer monitors, mobile phones, handheld devices, video game systems, navigation systems, projectors, and television.

    How does it work?

    All the pixels on a TFT LCD screen are configured in a row-and-column format, and each pixel is attached to a very tiny silicon transistor that rests directly on the glass panel. This setup allows each pixel to be given a charge and for the charge to be kept even when the screen is refreshed to produce a new image.


    Hardware Setup

    2.2-inch TFT LCD Display Connections

    Important note: The 2.2-inch TFT LCD display we are using can only work on 3.3V logic. Unlike most Arduino boards, the Arduino Due board runs at 3.3V making it the perfect one to use. Of course, other boards like the Arduino Uno can still be used as long as there is proper logic level shift applied using resistors. Click here for a guide on that.

    • SDO/MISO connected to Arduino Due SPI MISO2 pin
    • LED connected to Arduino Due 5V with a 47Ω resistor in series
    • SCK connected to Arduino Due SPI SCK2 pin
    • SDI/MOSI connected to Arduino Due SPI MOSI2 pin
    • DC/RS connected to Arduino Due pin 26
    • RESET connected to Arduino Due pin 22
    • CS connected to Arduino Due pin 24
    • Vcc and Gnd connected to Arduino Due 5V and Ground respectively

    HC-05 Bluetooth Module Connections

    • RXD connected to Arduino Due pin TX2 16
    • TXD connected to Arduino Due pin D4
    • Vcc and Gnd connected to Arduino Due 5V and Ground respectively

    Stepper Motor Driver DRV8825 Connections

    • DIR connected to Arduino Due pin 2
    • STEP connected to Arduino Due pin 3
    • RESET and SLEEP connected to Arduino Due 5V
    • GND (left of image) connected to Arduino Due Ground
    • VMT and GND (right of image) connected to 9V power supply and its Ground respectively with a 100uF capacitor in series

    Stepper Motor NEMA 17 Connections

    Important note: Before connecting the stepper motor to the driver, we must first limit the current of the driver that would be going into the motor.
    The stepper motor we are using has a maximum current rating of 1.3 A with a 2.4Ω phase resistance, which would indicate a maximum motor supply of 3.12V. Using this motor with a higher voltage would allow higher step rates, but the current must actively be limited to under 1.3 A to prevent damage to the motor.

    One way to set the current limit is to adjust and measure the voltage on the REF pin to calculate the resulting current limit. The REF pin is the circle on the circuit board and can be adjusted using a small screwdriver. The current limit is twice of the reference voltage so to set the current limit to 1.3A, we must set the reference voltage to 0.65V.

    • 1st wire (usually red) connected to Stepper Motor Driver pin 1B
    • 2nd wire (usually black) connected to Stepper Motor Driver pin 2B
    • 3rd wire (usually blue) connected to Stepper Motor Driver pin 1A
    • 4th wire (usually green) connected to Stepper Motor Driver pin 2A

    Android App Setup

    For the Android mobile app, we will use the cloud-based MIT app inventor. In just a few steps, you can set it up and start building apps! First things first, you will need to install the App Inventor Companion App on your Android device. If you do not have an Android device, you’ll need to install software on your computer so that you can use the on-screen Android emulator. Learn more about the initial setup by clicking here.

    Once all that is done, click on the Project tab, then start a new project and give it a proper name. When you’re in the main interface, you’ll see a palette on the left, a viewer in the middle, then a components and properties tab on the right. Drag and drop the following components from the palette onto the viewer screen accordingly and in order (left). To make it easier to identify the components, change their names to whatever you want using the rename button that is below (right). Following this format with specific components inside a certain arrangement makes it easier to hide or show a group of components at a time when needed later on.

    You can customize the labels and buttons to your own liking. Personally, I have added my own custom button images as well as a grayscale version of it to be used when the button is disabled. You can also add a background image on Screen1 to make it look prettier (left). After this, uncheck VerticalArrangement3’s visibility so it will look like a pre-connected screen (right).

    To see how the app looks on your phone, connect it to the App Inventor Companion by clicking on the connect button on the top menu and selecting AI companion. An importable .aia file download for this will be included below with the code, as well as an .apk for direct installation.


    Code

    Arduino Code

    #include "SPI.h"
    #include "Adafruit_ILI9341.h"
    
    #define dirPin 2
    #define stepPin 3
    #define stepsPerRevolution 200
    
    #define TFT_DC 26
    #define TFT_CS 24
    #define TFT_RST 22
    Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
    
    int input; //a string to hold incoming data
    int lastInput;
    int floorDiff;
    int compensation;
    bool stringComplete = false;
    
    void setup() {
      Serial2.begin(9600);
      tft.begin();
      displayFloor();
      //Set pins as output
      pinMode(stepPin, OUTPUT);
      pinMode(dirPin, OUTPUT);
      Serial.println("Mini Lift program has started.");
    }
    
    void moveUp() {
      digitalWrite(dirPin, HIGH);
      for (int i = 0; i < (1.8*stepsPerRevolution*floorDiff)+compensation ; i++) {
        digitalWrite(stepPin, HIGH); //These four lines result in 1 step
        delayMicroseconds(1000);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(1000);
      }
    }
    
    void moveDown() {
      digitalWrite(dirPin, LOW);
      for (int i = 0; i < (1.8*stepsPerRevolution*floorDiff)-compensation; i++) {
        digitalWrite(stepPin, HIGH); //These four lines result in 1 step
        delayMicroseconds(1000);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(1000);
      }
    }
    
    unsigned long displayFloor() {
      tft.fillScreen(ILI9341_BLACK);
      tft.setRotation(1);
      tft.setCursor(0, 70);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
      tft.setTextColor(ILI9341_WHITE); tft.setTextSize(5);
      tft.println("Mini Lift");
      tft.setTextColor(ILI9341_MAGENTA);  tft.setTextSize(3);
      tft.print("Current Floor:");
      tft.setTextColor(ILI9341_MAGENTA);  tft.setTextSize(3);
      tft.println(input);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
    }
    
    unsigned long displayMoving() {
      tft.fillScreen(ILI9341_BLACK);
      tft.setRotation(1);
      tft.setCursor(0, 80);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
      tft.setTextColor(ILI9341_CYAN); tft.setTextSize(3);
      tft.print("Lift is moving ");
      if (lastInput < input) {
        tft.println((char)24);
      }
      else if (lastInput > input) {
        tft.println((char)25);
      }
      tft.print("from floor ");
      tft.print(lastInput);
      tft.print(" - ");
      tft.println(input);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
    }
    
    void serialEvent() {
      while (Serial2.available()) {
        input = Serial2.read();
        displayMoving();
        stringComplete = true;
      }
    }
    
    void loop() {
      serialEvent();
      if (stringComplete) {
        Serial2.print(lastInput);
        if (lastInput < input) {
          floorDiff = input - lastInput;
          moveUp();
        }
        else if (lastInput > input) {
          floorDiff = lastInput - input;
          moveDown();
        }
        displayFloor();
      }
      delay(100);
      lastInput = input;
      stringComplete = false;
    }

    MIT App Inventor Code


    Code Breakdown

    Arduino Code

    Pre-Initialization

    #include "SPI.h"
    #include "Adafruit_ILI9341.h"

    Before we start, we must include the libraries to be used in the project. The Adafruit_ILI9341 library is needed to control what the TFT LCD display, and since it uses and depends on Serial Peripheral Interface, the SPI library is also included.

    #define dirPin 2
    #define stepPin 3
    #define stepsPerRevolution 200
    
    #define TFT_DC 26
    #define TFT_CS 24
    #define TFT_RST 22
    Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

    After that, we define the direction and step pins for the stepper motor, as well as the steps per revolution. Typical stepper motors are 1.8 degrees per step, which is 200 steps per revolution. Next, we define the DC, CS, and reset pins for the TFT LCD display and create TFT object with the respective pins assigned.

    int input; //a string to hold incoming data
    int lastInput;
    int floorDiff;
    int compensation;
    bool stringComplete = false;

    Next, we initialize the variables to be used later on. input is to store the incoming input data. lastInput is to store the previous input. The other variables will be explained later down the line.

    void setup()

    Serial2.begin(9600);
      tft.begin();
      displayFloor();
      //Set pins as output
      pinMode(stepPin, OUTPUT);
      pinMode(dirPin, OUTPUT);

    Inside the setup() function, we set the Serial2 baud rate to 9600 bps which is the default for serial communication. Arduino Due has 4 serial pins and we’re using Serial2 which is located on pins 16 and 17. We also initialize the TFT and immediately call in the displayFloor function (to be explained later). Next, we set the stepper motor pins as output.

    Stepper motor control functions

    void moveUp() {
      digitalWrite(dirPin, HIGH);
      for (int i = 0; i &lt; (1.8*stepsPerRevolution*floorDiff)+compensation ; i++) {
        digitalWrite(stepPin, HIGH); //These four lines result in 1 step
        delayMicroseconds(1000);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(1000);
      }
    }
    
    void moveDown() {
      digitalWrite(dirPin, LOW);
      for (int i = 0; i &lt; (1.8*stepsPerRevolution*floorDiff)-compensation; i++) {
        digitalWrite(stepPin, HIGH); //These four lines result in 1 step
        delayMicroseconds(1000);
        digitalWrite(stepPin, LOW);
        delayMicroseconds(1000);
      }
    }

    The moveUp and moveDown functions are pretty similar with the only difference being the direction pin being set to HIGH for rotating the motor clockwise, and LOW for rotating it counter-clockwise. It’s basically a for loop that would turn the motors up to a certain point and the delayMicroseconds dictate how fast you want it to go. The steps per revolution multiplied by the floorDiff to dictate how many times it should rotate and then added by a compensation value. This compensation value is important if you are using a one-sided rolling belt method for the lift like I did, because as the rubber belt rolls, it will accumulate radius and require lesser rotations to reach the same height.

    TFT display functions

    unsigned long displayFloor() {
      tft.fillScreen(ILI9341_BLACK);
      tft.setRotation(1);
      tft.setCursor(0, 70);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
      tft.setTextColor(ILI9341_WHITE); tft.setTextSize(5);
      tft.println("Mini Lift");
      tft.setTextColor(ILI9341_MAGENTA);  tft.setTextSize(3);
      tft.print("Current Floor:");
      tft.setTextColor(ILI9341_MAGENTA);  tft.setTextSize(3);
      tft.println(input);
      tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
      tft.println("--===---===----===---===--");
    }

    The displayFloor function prints the text on the TFT LCD display. First, the screen is filled black and rotated 90 degrees so it will be on landscape view. The 1 in the setRotation parameter indicates 90 degrees and you can set it from 0-3. Then, the cursor is set on the specific coordinates to have the text that is about to be printed on the center of the screen. If you want it at the top, then the cursor coordinates would be 0 and 0. Printing the text would be similar to how you’d normally print it in the serial monitor. A cool thing with the library we used is that we can also customize the text color and text size.

    The displayMoving function is what gets called when the stepper motor is moving. It basically just shows from which floor to which floor it is moving. (char)24 and (char)25 are up and down arrows respectively. Like the displayFloor function, I have tried to make it look a bit more fancy by setting text colors and adding makeshift borders.

    serialEvent function

    void serialEvent() {
      while (Serial2.available()) {
        input = Serial2.read();
        displayMoving();
        stringComplete = true;
      }
    }

    The serialEvent function checks for when there is data in the Bluetooth Serial. While there’s data available, it will store that data in the input variable and then set the boolean stringComplete to true to indicate that it has received the data successfully.

    void loop()

    serialEvent();
      if (stringComplete) {
        Serial2.print(lastInput);
        if (lastInput &lt; input) {
          floorDiff = input - lastInput;
          moveUp();
        }
        else if (lastInput &gt; input) {
          floorDiff = lastInput - input;
          moveDown();
        }
        displayFloor();
      }
      delay(100);
      lastInput = input;
      stringComplete = false;

    Inside the loop() function, we call in the serialEvent which will tell us when it has received data successfully. If it has received data, it goes into the if statement and sends the received data to through Serial2. If the last input is lesser than the new input then it calls the moveUp function, otherwise, it calls the moveDown function. floorDiff is calculated here so it knows how many times to move up or move down. After moving, it calls the displayFloor function to display which floor it is currently at. The delay here is necessary so there is time for the communication to process. Next, the new input is stored as the last input and the boolean stringComplete is set back to false to indicate that it has finished receiving the data and there are no more available to receive.

    There’s a long block of code in the loop where I set the calibration values depending on how much the rubber belt has rolled that I did not include here (but is in the downloadable file) since that depends on what rubber belt you are using, and if you are even using the one-sided rolling belt method.

    MIT App Inventor Code

    Connection Buttons

    Since the MIT App Inventor uses code blocks, it should be easier to understand. When the BluetoothBTN (ListPicker) is clicked, “.BeforePicking” is what happens before the user picks something from a certain list. In this case, we want to show the user a list of Bluetooth devices nearby that they can connect to so we set the BluetoothBTN’s elements to the that.

    “.AfterPicking” is what happens after the user has picked a Bluetooth device to connect to. If it has connected to the HC-05 Bluetooth module successfully, it will set the visibility of VerticalArrangement2, which contains the ConnectLabel and BluetoothBTN to false and set visibility of VerticalArrangement3, which contains the other components to true. Following that, it checks for the state of the lift so the app takes off where it has left. If for example, it was at floor 1, the floor 1 button would be disabled. The app should look like this afterwards.

    The DisconnectBTN does exactly what it names implies – it disconnects the app from the Bluetooth device and sets VerticalArrangement2 back to true and VerticalArrangement3 back to false, which are the settings prior to connection.

    Floor Buttons

    For the rest of the code, it’s what happens when you click on the floor buttons. When the Floor1BTN is clicked, it checks if the user is still connected to the Bluetooth device and sends the value 1 via Bluetooth for the HC-05 Bluetooth module to receive. This value will be stored in the input variable in the Arduino code which helps in telling the stepper motor how many times it has to rotate with the calculations explained above.

    The rest of the code is just to disable the button after it has been pressed by setting enabled to false and changing the button image to the grayscale version, then enable the other buttons which would have been previously disabled by setting enabled to true and changing the button image back to the regular version.


    Conclusion

    Stepper motors are really strong. The motor’s position can be caused to move and hold at one of these steps as long as the motor is carefully sized to the application in respect to torque and speed. In my case, it was able to lift up a bunch of office supplies. It can lift weights heavier than this, according to several experiments that have been conducted by other sources. Furthermore, they are used in a wide variety of applications such as industrial machines, medical scanners, blood analysis machinery, 3D printing equipment, etc.


    References

    The post Bluetooth-Controlled Mini Lift Using Stepper Motor with Android Mobile App appeared first on CreateLabz.

    17hs4401AndroidArduinoArduino dueBluetoothDriverDrv8825Hc-05Hc05Ili9341KnowledgebaseLcdLiftMit app inventorNemaNema 17QvgaSpiStepperStepper motorTft

    Leave a comment

    All comments are moderated before being published