Wei WangHao DongXiyi ChenNengneng YuPeiqing Chen
Published

Blinds Robot

Control blinds’ lift and tilt via smartphone

IntermediateFull instructions provided155
Blinds Robot

Things used in this project

Hardware components

FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
DFRobot FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
×1
Greartisan 12V motor
×2
Ultrasonic Sensor - HC-SR04
SparkFun Ultrasonic Sensor - HC-SR04
×2
SparkFun Full-Bridge Motor Driver Breakout - L298N
SparkFun Full-Bridge Motor Driver Breakout - L298N
×1

Software apps and online services

Serial Bluetooth Terminal

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

enclosure_for_slats_NpCRzlEKM5.f3z

roller_v13_g7f8zts2tA.f3d

motor_stand_Nw3v5o8UeC.f3z

Schematics

861734299698__pic_EH7bk70hdq.jpg

Code

main.cpp

Arduino
#include <Arduino.h>
#include "BluetoothSerial.h"
#include "esp_bt.h"
#include "esp_log.h"
#include "esp_gap_bt_api.h"
#include "WiFi.h"
#include <time.h>  

int triggerPin_up = 5;
int echoPin_up = 18;
int triggerPin_down = 17;
int echoPin_down = 16;

const int IN1 = 33;    
const int IN2 = 32;    
const int EN = 23;  

// Motor 2
const int IN3 = 25;    
const int IN4 = 26;  

char motorDirection = 'U'; 
char rotateDirection = 'V';
// 'V' - Stop
// 'B' - Rotate
// 'N' - Inverse Roatae
char cmd;
bool isMovingToMiddle = false; 

bool testResults[10];  
int testIndex = 0;     
int successCount = 0;  

BluetoothSerial SerialBT;

time_t rotateStartTime; 
unsigned long lastLoopTime = 0;  
const float MAX_POSITION = 50.0f;
const float MIN_POSITION = 0.0f;
float rotatePosition = (MAX_POSITION + MIN_POSITION) / 2;   

long detectDistance(int triggerPin, int echoPin) {
  long duration = 0, distance = -1;
  digitalWrite(triggerPin, LOW);
  delayMicroseconds(2);
  digitalWrite(triggerPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(triggerPin, LOW);
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * 0.0343;
  return distance;
}

void setup() {
  Serial.begin(9600);
  pinMode(triggerPin_up , OUTPUT);
  pinMode(echoPin_up, INPUT);
  pinMode(triggerPin_down , OUTPUT);
  pinMode(echoPin_down, INPUT);

  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  pinMode(EN, OUTPUT);

  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);

  digitalWrite(EN, HIGH);

  WiFi.mode(WIFI_OFF);
  btStop();

  esp_log_level_set("*", ESP_LOG_VERBOSE);

  if (!SerialBT.begin("ESP32test")) {
    Serial.println("Bluetooth initialization failed!");
    while (1);
  }

  esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
  Serial.println("Bluetooth initialized successfully. You can pair now!");
  cmd = 'S';
}

int up_distance_less_than_20 = 0;
int down_distance_less_than_20 = 0;
int up_distance_greater_than_20 = 0;
int down_distance_greater_than_20 = 0;
int is_less_than_20 = 0;
int is_greater_than_20 = 0;

void compareDistance(int* is_less_than_20, int* is_greater_than_20){
 up_distance_less_than_20 = 0;
  down_distance_less_than_20 = 0;
  up_distance_greater_than_20 = 0;
  down_distance_greater_than_20 = 0;
  *is_less_than_20 = 0;
  *is_greater_than_20 = 0;
  for(int i = 0; i < 10; i++){
    long curtain_position_up = detectDistance(triggerPin_up, echoPin_up);
    long curtain_position_down = detectDistance(triggerPin_down, echoPin_down);
    if(curtain_position_up < 20){
      up_distance_less_than_20++;
    }
    if(curtain_position_down < 20){
      down_distance_less_than_20++;
    }
    if(curtain_position_up > 20){
      up_distance_greater_than_20++;
    }
    if(curtain_position_down > 20){
      down_distance_greater_than_20++;
    }
      Serial.print("Motor1: Distances: ");
    Serial.print(curtain_position_up);
    Serial.print(",");
    Serial.println(curtain_position_down);
    SerialBT.print("Motor1: Distances: ");
    SerialBT.print(curtain_position_up);
    SerialBT.print(",");
    SerialBT.println(curtain_position_down);
    delay(20);
  }
  if(up_distance_less_than_20 > 2* up_distance_greater_than_20 && down_distance_less_than_20 > 2*down_distance_greater_than_20){
    *is_less_than_20 = 1;
  } else if(up_distance_greater_than_20 > 2* up_distance_less_than_20 && down_distance_greater_than_20 > 2* down_distance_less_than_20){
    *is_greater_than_20 = 1;
  }

  Serial.print("Motor1: Distances: ");
  Serial.print(up_distance_less_than_20?"up less than 20":"up greater than 20");
  Serial.print(",");
  Serial.println(down_distance_less_than_20?"down less than 20":"down greater than 20");
  SerialBT.print("Motor1: Distances: ");
  SerialBT.print(up_distance_less_than_20?"up less than 20":"up greater than 20");
  SerialBT.print(",");
  SerialBT.println(down_distance_less_than_20?"down less than 20":"down greater than 20");
}

void readCommand(){
  cmd = ' ';

  if (SerialBT.available() > 0) {
    cmd = SerialBT.read();
    cmd = toupper(cmd);
  }

  if (cmd == 'U') {
    motorDirection = 'U';
    Serial.println("Motor1: Moving Up");
    SerialBT.println("Motor1: Moving Up");
  } else if (cmd == 'D') {
    motorDirection = 'D';
    Serial.println("Motor1: Moving Down");
    SerialBT.println("Motor1: Moving Down");
  } else if (cmd == 'S') {
    motorDirection = 'S';
    Serial.println("Motor1: Stopped");
    SerialBT.println("Motor1: Stopped");
  }
  
  if (cmd == 'V') {
    rotateDirection = 'V';
    isMovingToMiddle = false; 
    SerialBT.println("Motor2: Set rotation: Stop");
  } else if (cmd == 'B') {
    rotateDirection = 'B';
    isMovingToMiddle = false; 
    SerialBT.println("Motor2: Set rotation: Open");
  } else if (cmd == 'N') {
    rotateDirection = 'N';
    isMovingToMiddle = false;  
    SerialBT.println("Motor2: Set rotation: Close");
  } else if (cmd == 'M') {
    isMovingToMiddle = true; 
    float middlePosition = (MAX_POSITION + MIN_POSITION) / 2;
    if (rotatePosition < middlePosition - 0.1) {
      rotateDirection = 'B';
      SerialBT.println("Motor2: Moving to middle position: Opening");
    } else if (rotatePosition > middlePosition + 0.1) {
      rotateDirection = 'N';
      SerialBT.println("Motor2: Moving to middle position: Closing");
    } else {
      rotateDirection = 'V';
      isMovingToMiddle = false; 
      SerialBT.println("Motor2: Already at middle position");
    }
  }
}

void loop() {
  
  readCommand();

  // Motor1:
  // up down motor: compare distance
  compareDistance(&is_less_than_20, &is_greater_than_20);
  if(motorDirection == 'U' && is_greater_than_20){
    motorDirection = 'S';
    Serial.println("Motor1: Hit the top");
    SerialBT.println("Motor1: Hit the top");
  } else if(motorDirection == 'D' && is_less_than_20){
    motorDirection = 'S';
    Serial.println("Motor1: Hit the bottom");
    SerialBT.println("Motor1: Hit the bottom");
  }

  // up down motor: move or stop
  if (motorDirection == 'U') {
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
  } else if (motorDirection == 'D') {
    Serial.println("Motor1: in Down");
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);
  } else if (motorDirection == 'S') {
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
  }

  // Motor2:
  unsigned long currentTime = millis();
  float deltaTime = (currentTime - lastLoopTime) / 1000.0f;  
  lastLoopTime = currentTime;

  if (rotateDirection == 'B') {  
    if (rotatePosition < MAX_POSITION) {
        digitalWrite(IN3, HIGH);
        digitalWrite(IN4, LOW);
        rotatePosition += deltaTime;  
        float displayPosition = constrain(rotatePosition, MIN_POSITION, MAX_POSITION);
        float percentage = (displayPosition / MAX_POSITION) * 100;  
        Serial.printf("Motor2: Rotating position: %.1f%%\n", percentage);   
        SerialBT.printf("Motor2: Rotating position: %.1f%%\n", percentage);
    } else {
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        rotateDirection = 'V';
        Serial.println("Motor2: Reached max position, stopping");
        SerialBT.println("Motor2: Reached max position, stopping");
    }
  } else if (rotateDirection == 'N') { 
    if (rotatePosition > MIN_POSITION) {
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, HIGH);
        rotatePosition -= deltaTime;  
        float displayPosition = constrain(rotatePosition, MIN_POSITION, MAX_POSITION);
        float percentage = (displayPosition / MAX_POSITION) * 100;  
        Serial.printf("Motor2: Rotating position: %.1f%%\n", percentage);   
        SerialBT.printf("Motor2: Rotating position: %.1f%%\n", percentage);
    } else {
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        rotateDirection = 'V';
        Serial.println("Motor2: Reached min position, stopping");
        SerialBT.println("Motor2: Reached min position, stopping");
    }
  } else if (rotateDirection == 'V') {
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, LOW);
  }

  if (rotateDirection != 'V' && isMovingToMiddle) {  
    float middlePosition = (MAX_POSITION + MIN_POSITION) / 2;
    if (rotatePosition >= middlePosition - 0.1 && rotatePosition <= middlePosition + 0.1) {
        rotateDirection = 'V';
        digitalWrite(IN3, LOW);
        digitalWrite(IN4, LOW);
        isMovingToMiddle = false; 
        SerialBT.println("Motor2: Reached middle position, stopping");
        Serial.println("Motor2: Reached middle position, stopping");
    }
  }

  delay(50);
}

Credits

Wei Wang
1 project • 0 followers
Contact
Hao Dong
0 projects • 0 followers
Contact
Xiyi Chen
0 projects • 0 followers
Contact
Nengneng Yu
0 projects • 0 followers
Contact
Peiqing Chen
0 projects • 0 followers
Contact

Comments

Please log in or sign up to comment.