-->
Page 1 of 2

4 motor project

PostPosted: Thu Apr 16, 2020 6:02 pm
by GeforceUK
Hi all, I'm very new to this and just started with electronics to this level. I am an IT Systems Engineer and Mechanical Engineer by trade and I have found myself here after looking into a project that I have set myself and I am sure it is possible but I have been unable to find any examples so far.
My plan is to motorise a pair of vertical blinds so that they can twist from closed to open (90 degree twist) and slide back and forth. I am looking at using an ESP8266 with an L293D motor control module to drive 4 motors, 2 for each blind. One motor to manage the 90 degree twist, and one motor to pull the blind backward and forward. Ideally controlled over WiFi (Alexa would be the intended final solution) with a manual push button control 'override' to allow tactile control if required. Any pointers to projects like this would be a great help. I have set up a simple setup with two motors on the ESP8266 and they work using a web interface but now I am out of my depth and looking for pointers on things like the motors stopping when they get a heavy load (at the end of the run or there is a jam in the blinds) and setting a count on the number of revolutions the motor can do in each direction before it will only go the other way (at the moment this is done manually via the web interface and its possible to try and send the motors in the wrong direction which has already caused the demise of one board! Any pointers to tutorials or examples of this sort of project will be appreciated. Thanks in advance.

Re: 4 motor project

PostPosted: Thu Apr 16, 2020 7:58 pm
by rudy
In the industry I am involved in the actuator have limit switches that open the motor circuit at the extremes of travel. Often, but not always, a pot is used for position feedback. Along with the position the pot is used to detect movement, or the lack of movement. If power is applied to the motor and expected movement is not detected, in a certain timeframe, power is turned off and an alarm occurres.

Re: 4 motor project

PostPosted: Fri Apr 17, 2020 4:47 am
by Barnabybear
Hi, I used stepper motors with drivers to open and close my blind project. They can be controlled from external sources (phone, Alexa or MQTT) via a simple get request. I’ve attached the code below as it might give you some ideas.
Code: Select all*
    STILL UNDER DEVELOPMENT - mostly works 23/08/16.
    V1.0

    This sketch will drive a 28BYJ-48 stepper motor
    with ULN2003 to open & close a roller blind,
    or anything realy.
    The coils A,B,C & D are on GPIO's 12, 13, 14 & 15.
    with 4.7K pull down resistors.
    GPIO's 0 & 2 are used as manual control,
    LOW active with 10K pull ups.
    GPIO 2 toggles the blind open & closed,
    dependant on it's current state.
    GPIO 0 will enter inch mode, the blind
    can be inched to a known open postion
    postion with GPIO 2 & then stored as open.
    After GPIO 0 first press - inch closed,
    after GPIO 0 second press - inch open,
    after GPIO 0 third press - exit inch mode &
    store in EEPROM as open.
    Remote access is via the following commands:
    http://server_ip/blind/open will open the blinds,
    http://server_ip/blind/close will close the blinds.

    'open_length' sets the number of steps required
    to open or close the blind.
*/

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <EEPROM.h>

const char* ssid = "xxxxxxxx";
const char* password = "xxxxxxxx";
IPAddress ip(192,168,1,85);
IPAddress gateway(192,168,1,1);
int coilA = 12;
int coilB = 13;
int coilC = 14;
int coilD = 15;
int manual_operate = 2;
int manual_inch = 0;
int step_number = 1;
int step_delay = 2000;
long open_length = 35000; // actual value
//long open_length = 5000; // test value
int flag_current = 0;
byte flag_last = 1;
int flag_adjust = 0;

// Create an instance of the server
// specify the port to listen on as an argument
WiFiServer server(80);

void setup() {
  Serial.begin(115200);
  delay(10);
 
  // set outputs.
  pinMode(coilA, OUTPUT);
  pinMode(coilB, OUTPUT);
  pinMode(coilC, OUTPUT);
  pinMode(coilD, OUTPUT);
  pinMode(manual_operate, INPUT);
  pinMode(manual_inch, INPUT);
  digitalWrite(coilA, LOW);
  digitalWrite(coilB, LOW);
  digitalWrite(coilC, LOW);
  digitalWrite(coilD, LOW);

  // Connect to WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  //WiFi.mode(WIFI_AP_STA);
      WiFi.config(ip, gateway);
  WiFi.begin(ssid, password);


  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  // Start the server
  server.begin();
  Serial.println("Server started");

  // Start OTA
  ArduinoOTA.begin();

  // Print the IP address
  Serial.println(WiFi.localIP());
 
  // Print sketch file name and compile date & time
//  Serial.print("Current file is: ");
//  Serial.println(__FILE__);
//  Serial.print("Complied on: ");
//  Serial.print(__DATE__);
//  Serial.print(" at ");
//  Serial.println(__TIME__);
  EEPROM.begin(1);
//    EEPROM.write(0, 1);  // set current / last postion flag to 2 = closed.
//    EEPROM.commit();
  Serial.println("EEPROM value is ");
  Serial.println(EEPROM.read(0));
  Serial.println("flag_last is ");
  Serial.println(flag_last);
}

void loop() {


  ArduinoOTA.handle();
  // Check if a client has connected or
  // manual opperation required.

  // Check for remote request.
  WiFiClient client = server.available();
  if (!client) { // if no remote request check manual buttons.
    delay(100);

    // Check for GPIO 0 low - enter inch mode.
    if (!digitalRead(manual_inch)) { // if GPIO 0 low.
      manual_adjust(); // jump to void manual_adjust.
    }

    // Check for GPIO 2 low reverse blind postion.
    // if open, close if closed, open.
    if (!digitalRead(manual_operate)) { // if GPIO 2 low.
      flag_last = EEPROM.read(0);
      switch (flag_last) { // select dependant on blind currently open or closed.
        case 1: // blind currently open.
          close(); // jump to void close().
          break;
        case 2: // blind currently closed.
          open(); // jump to void open().
          break;
      }
    }
    return;
  }
  // If remote request.
  // Read the first line of the request.
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();

  // Match the request
  int val;
  if (req.indexOf("/blind/open") != -1)
    flag_current = 1; // set flag to open blind.
  else if (req.indexOf("/blind/close") != -1)
    flag_current = 2; // set flag to close blind.
  else if (req.indexOf("/blind/status") != -1)
    flag_current = 3; // set flag to refresh.
  else if (req.indexOf("/blind/setup") != -1)
    flag_current = 4; // set flag to return status.
  else {
    Serial.println("invalid request");
    client.print("HTTP/1.1 404\r\n");
    client.flush();
    client.stop();
    return;
  }

  client.flush();

  // Prepare the response
  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n<font size=\"7\">";
  switch (flag_current) { // select dependant on request.

    case 1:
      s += "The blind is OPEN.";
      s += "<br><br>Click <a href=\"/blind/close\">here</a> to CLOSE.";
      s += "<br><br>Or <a href=\"/blind/status\">here</a> to check see if this has<br><br>changed since you last visited.";
      break;

    case 2:
      s += "The blind is CLOSED";
      s += "<br><br>Click <a href=\"/blind/open\">here</a> to OPEN.";
      s += "<br><br>Or <a href=\"/blind/status\">here</a> to check see if this has<br>changed since you last visited.";
      break;

    case 3:
      s += "The blind is ";
      flag_last = EEPROM.read(0);
      if (flag_last == 2){
      s += "CLOSED";
      s += "<br><br>Click <a href=\"/blind/open\">here</a> to OPEN.";
      s += "<br><br>Or <a href=\"/blind/status\">here</a> to check see if this has<br>changed since you last visited.";
      }
      if (flag_last == 1){
      s += "OPEN";
      s += "<br><br>Click <a href=\"/blind/close\">here</a> to CLOSE.";
      s += "<br><br>Or <a href=\"/blind/status\">here</a> to check see if this has<br>changed since you last visited.";
      }
      break;
     
      case 4:
      flag_last = EEPROM.read(0);
      if (flag_last == 2){
      s += "The blind is CLOSED";
      }
      if (flag_last == 1){
      s += "The blind is OPEN";
      }
      s += "<br>";
      s += "Move length is set at ";
      s += open_length;
      s += "<br>";       
      s += "File ";
      s +=  __FILE__;
      s += "<br>";
      s += "Complied ";
      s += __DATE__;
      s += " ";
      s += __TIME__;
      s += "<br>";
      break;
  }
  s += "</font></html>\n";

  // Send the response to the client
  client.print(s);
  delay(100);
  client.flush();
  client.stop();
  Serial.println("Client disonnected");

  switch (flag_current) { // select dependant on request.
    case 1:
      flag_last = EEPROM.read(0);
      open(); // jump to void open().
      break;

    case 2:
      flag_last = EEPROM.read(0);
      close(); // jump to void close().
      break;

    case 3:
     break;
  }
}

//************ Manual adjust (inch mode)************
void manual_adjust() {
  Serial.println("Enter inch mode");
  flag_adjust = 2; // set flag to close.
  delay(1000);
  yield();

  while (flag_adjust > 0) { // adjust flag set to open or close (1 or 2).
    if (!digitalRead(manual_inch)) { // GPIO 0 low.
      flag_adjust = flag_adjust - 1; // reduce flag by 1 (step through options).
      if (flag_adjust < 0) { // check flag for negative value.
        flag_adjust = 0; // set flag to 0 if negative.
      }
      delay(1000);

    }
    switch (flag_adjust) { // inch open or closed dependant on adjust flag (set above).

      case 1: // open
        while (!digitalRead(manual_operate)) { // if GPIO 2 low.
          for (step_number = 1; step_number < 9; step_number++) {
            output_write(); // move stepper one set of moves in open direction.
            delayMicroseconds(step_delay);
            yield();
          }
        }

      case 2: // close
        while (!digitalRead(manual_operate)) { // if GPIO 2 low.
          for (step_number = 8; step_number > 0; step_number--) {
            output_write(); // move stepper one set of moves in closed direction.
            delayMicroseconds(step_delay);
            yield();
          }
        }

        yield();
    }
  }
  // adjust flag is 0, turn off outputs & drop out of loop.
  Serial.println("Exit inch mode, outputs off");
  digitalWrite(coilA, LOW);
  digitalWrite(coilB, LOW);
  digitalWrite(coilC, LOW);
  digitalWrite(coilD, LOW);
  EEPROM.write(0, 1);  // blind in open postion
  EEPROM.commit();
  Serial.println("EEPROM value is ");
  Serial.println(EEPROM.read(0));
  Serial.println("flag_last is ");
  Serial.println(flag_last);
}

//************ Open Loop ************
void open() {
  if (flag_last == 0 || flag_last == 2) { // check for power up or blind closed.
    Serial.println("opening blind");
    for (long dist_loop = 0; dist_loop < open_length; dist_loop++) { // number of steps to open blind.
      ++step_number;
      if (step_number > 8) step_number = 1;
      output_write(); // jump to void output write().
      delayMicroseconds(step_delay);
      yield();
    }
    // final write to turn all outputs off.
    Serial.println("move complete, outputs off");
    digitalWrite(coilA, LOW);
    digitalWrite(coilB, LOW);
    digitalWrite(coilC, LOW);
    digitalWrite(coilD, LOW);
    flag_current = 0; // set current move flag to 0 = none.
    EEPROM.write(0, 1); // set current / last postion flag to 1 = open.
    EEPROM.commit();
  }
}
//************ Close Loop ************
void close() {
  if (flag_last == 0 || flag_last == 1) { // check for power up or blind open.
    Serial.println("closing blind");
    for (long dist_loop = 0; dist_loop < open_length; dist_loop++) { // number of steps to close blind.
      --step_number;
      if (step_number < 1) step_number = 8;
      output_write(); // jump to void output write().
      delayMicroseconds(step_delay);
      yield();
    }
    // final write to turn all outputs off.
    Serial.println("move complete, outputs off");
    digitalWrite(coilA, LOW);
    digitalWrite(coilB, LOW);
    digitalWrite(coilC, LOW);
    digitalWrite(coilD, LOW);
    flag_current = 0; // set current move flag to 0 = none.
    EEPROM.write(0, 2);  // set current / last postion flag to 2 = closed.
    EEPROM.commit();
  }
}

//************ Output write ************
void output_write() {
  switch (step_number) {
    case 1:
      digitalWrite(coilA, HIGH);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, LOW);
      break;

    case 2:
      digitalWrite(coilA, HIGH);
      digitalWrite(coilB, HIGH);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, LOW);
      break;

    case 3:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, HIGH);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, LOW);
      break;

    case 4:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, HIGH);
      digitalWrite(coilC, HIGH);
      digitalWrite(coilD, LOW);
      break;

    case 5:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, HIGH);
      digitalWrite(coilD, LOW);
      break;

    case 6:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, HIGH);
      digitalWrite(coilD, HIGH);
      break;

    case 7:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, HIGH);
      break;

    case 8:
      digitalWrite(coilA, HIGH);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, HIGH);
      break;

    default:
      digitalWrite(coilA, LOW);
      digitalWrite(coilB, LOW);
      digitalWrite(coilC, LOW);
      digitalWrite(coilD, LOW);
      break;
  }
}

Re: 4 motor project

PostPosted: Fri Apr 17, 2020 12:15 pm
by GeforceUK
Thanks Barnabybear very interesting and a good starting point. Do you know if it is achievable to run 4 motors from one ESP8266 or would I be best splitting each side to a single control system to just have two motors per side? I can seem to find any 4 motor projects?