ESP8266 & Stepper Motors

Nothing outrageously complicated but when I used the default arduino stepper library to control my 28BYJ-48 stepper motors on my ESP8266 they only turned one direction. With modifications to the library it was possible to get one stepper motor working correctly but the ESP crashed if I tried to control 2 stepper motors, solution sketch below:

What did work:
– Sketch below. (Note: No fancy acceleration/deceleration but I didnt need it)

int pos_rot = 0;  
int pos_elev = 0; 

int rot_counter = 0;
int elev_counter = 0;

int next_rot = -1;
int next_elev = 1;

int step_delay = 10; //Delay between steps in ms

const int motor_pin_1 = 16; // ESP D0
const int motor_pin_2 = 5;  // ESP D1
const int motor_pin_3 = 4;  // ESP D2
const int motor_pin_4 = 0;  // ESP D3
const int motor_pin_5 = 2;  // ESP D4
const int motor_pin_6 = 14; // ESP D5
const int motor_pin_7 = 12; // ESP D6
const int motor_pin_8 = 13; // ESP D7

void setup() {
  pinMode(motor_pin_1, OUTPUT); // Blue
  pinMode(motor_pin_2, OUTPUT); // Pink
  pinMode(motor_pin_3, OUTPUT); // Yellow
  pinMode(motor_pin_4, OUTPUT); // Orange
  pinMode(motor_pin_5, OUTPUT);
  pinMode(motor_pin_6, OUTPUT);
  pinMode(motor_pin_7, OUTPUT);
  pinMode(motor_pin_8, OUTPUT);
  
  // Begin Serial communication at a baud rate of 9600:
  Serial.begin(115200);
  delay(100);Serial.println("Leaving Setup");delay(100);
}

void loop() {
    //test_sweep();
    rot(2038);delay(2000);rot(-2038);   // 2038 steps clockwise followed by the same counterclockwise
    elev(1019);delay(2000);elev(-1019); // 1019 steps clockwise followed by the same counterclockwise
}

void test_sweep(){
      Serial.print("Rotating CCW, pos_rot = ");Serial.println(pos_rot);

    while (pos_rot < 2038) {
    rot(1);
    pos_rot = pos_rot + 1;
 
        if ((pos_rot < 1019) && ((pos_rot % 2) == 0)) {
          elev(2);          
        }
        else if ((pos_rot > 1019) && ((pos_rot % 2) == 0)) {
          elev(-2);
        }
  }
    while (pos_rot > 0) {
    rot(-1);
    pos_rot = pos_rot - 1;
 
        if ((pos_rot > 1019) && ((pos_rot % 2) == 0)) {
          elev(2);
        }
        else if ((pos_rot < 1019) && ((pos_rot % 2) == 0)) {
          elev(-2);
        }
  }
}

void elev(int num_steps) {
    if (num_steps > 0) {
        while (elev_counter < num_steps) {        
          elev_step(next_elev);
          next_elev = next_elev +1;
          if (next_elev > 7) { next_elev = 0;}
          elev_counter = elev_counter +1;
        }
    }
    else {
        num_steps = abs(num_steps);
        while (elev_counter < num_steps) {        
          elev_step(next_elev);
          next_elev = next_elev - 1;
          if (next_elev < 0) { next_elev = 7;}
          elev_counter = elev_counter +1;
        }    
    }
    elev_counter = 0;
}

void rot(int num_steps) {
    if (num_steps > 0) {
    
        while (rot_counter < num_steps) {        
          rot_step(next_rot);
          next_rot = next_rot +1;
          if (next_rot > 7) { next_rot = 0;}
          rot_counter = rot_counter +1;
        }
    }
    else {
        num_steps = abs(num_steps);
        while (rot_counter < num_steps) {        
          rot_step(next_rot);
          next_rot = next_rot - 1;
          if (next_rot < 0) { next_rot = 7;}
          rot_counter = rot_counter +1;
        }    
    }

    rot_counter = 0;  
}

void rot_step(int go_step) {
  switch (go_step) {
      case 0:  // 0001
        digitalWrite(motor_pin_1, 0);  // Blue
        digitalWrite(motor_pin_2, 0);  // Pink
        digitalWrite(motor_pin_3, 0);  // Yellow
        digitalWrite(motor_pin_4, 1);  // Orange
      break;
      case 1:  // 0011
        digitalWrite(motor_pin_1, 0);
        digitalWrite(motor_pin_2, 0);
        digitalWrite(motor_pin_3, 1);
        digitalWrite(motor_pin_4, 1);
      break;
      case 2:  //0010
        digitalWrite(motor_pin_1, 0);
        digitalWrite(motor_pin_2, 0);
        digitalWrite(motor_pin_3, 1);
        digitalWrite(motor_pin_4, 0);
      break;
      case 3:  //0110
        digitalWrite(motor_pin_1, 0);
        digitalWrite(motor_pin_2, 1);
        digitalWrite(motor_pin_3, 1);
        digitalWrite(motor_pin_4, 0);
      break;
      case 4:  // 0100
        digitalWrite(motor_pin_1, 0);
        digitalWrite(motor_pin_2, 1);
        digitalWrite(motor_pin_3, 0);
        digitalWrite(motor_pin_4, 0);
      break;
      case 5:  // 1100
        digitalWrite(motor_pin_1, 1);
        digitalWrite(motor_pin_2, 1);
        digitalWrite(motor_pin_3, 0);
        digitalWrite(motor_pin_4, 0);
      break;
      case 6:  //1000
        digitalWrite(motor_pin_1, 1);
        digitalWrite(motor_pin_2, 0);
        digitalWrite(motor_pin_3, 0);
        digitalWrite(motor_pin_4, 0);
      break;
      case 7:  //1001
        digitalWrite(motor_pin_1, 1);
        digitalWrite(motor_pin_2, 0);
        digitalWrite(motor_pin_3, 0);
        digitalWrite(motor_pin_4, 1);
      break;
    }
    delay(step_delay);
}

void elev_step(int go_step) {
  //Serial.println(go_step);
  switch (go_step) {
      case 0:  // 0001
        digitalWrite(motor_pin_5, LOW);
        digitalWrite(motor_pin_6, LOW);
        digitalWrite(motor_pin_7, LOW);
        digitalWrite(motor_pin_8, HIGH);
      break;
      case 1:  // 0011
        digitalWrite(motor_pin_5, LOW);
        digitalWrite(motor_pin_6, LOW);
        digitalWrite(motor_pin_7, HIGH);
        digitalWrite(motor_pin_8, HIGH);
      break;
      case 2:  //0010
        digitalWrite(motor_pin_5, LOW);
        digitalWrite(motor_pin_6, LOW);
        digitalWrite(motor_pin_7, HIGH);
        digitalWrite(motor_pin_8, LOW);
      break;
      case 3:  //0110
        digitalWrite(motor_pin_5, LOW);
        digitalWrite(motor_pin_6, HIGH);
        digitalWrite(motor_pin_7, HIGH);
        digitalWrite(motor_pin_8, LOW);
      break;
      case 4:  // 0100
        digitalWrite(motor_pin_5, LOW);
        digitalWrite(motor_pin_6, HIGH);
        digitalWrite(motor_pin_7, LOW);
        digitalWrite(motor_pin_8, LOW);
      break;
      case 5:  // 1100
        digitalWrite(motor_pin_5, HIGH);
        digitalWrite(motor_pin_6, HIGH);
        digitalWrite(motor_pin_7, LOW);
        digitalWrite(motor_pin_8, LOW);
      break;
      case 6:  //1000
        digitalWrite(motor_pin_5, HIGH);
        digitalWrite(motor_pin_6, LOW);
        digitalWrite(motor_pin_7, LOW);
        digitalWrite(motor_pin_8, LOW);
      break;
      case 7:  //1001
        digitalWrite(motor_pin_5, HIGH);
        digitalWrite(motor_pin_6, LOW);
        digitalWrite(motor_pin_7, LOW);
        digitalWrite(motor_pin_8, HIGH);
      break;
    }
    delay(step_delay);
}

That’s it!

Capacitive Touch Hack (for Fluval Edge Aquarium Control)

This post is about automating the light on the Fluval Edge Aquarium but can be applied to any capacitive touch button I imagine. It turns the light on at 10am in the morning, turns it blue at 8pm and finally turns it off at midnight. It has real time clock (RTC) to keep track of time and can recover from power outages due to storing current state in EEPROM.

My first attempt was to have passive control by creating capacitance on a piece of aluminium foil/tape and manipulating this to activate the sensor but I could not get it working so the not so elegant solution is to have a servo ‘touch’ the sensor on a schedule.

Video of it in action:

Parts Required:
Arduino (any), I used Nano.
RTC (any), I used DS1307.
Servo (any), I used HK15178 10g servo.

Connections: (aside from power which are all 5V)
Arduino A4 -> RTC SDA
Arduino A5 -> RTC SCL
Arduino D3 -> Servo Control (was yellow wire for me)

Paste of Arduino code below, don’t forget to add the RTC library, hosted here if you don’t have it already.

#include <Wire.h>
#include "RTClib.h"
#include <EEPROM.h>
#include <Servo.h>

Servo myservo;  // create servo object to control a servo 

RTC_DS1307 RTC;

char receivedChar;
boolean newData = false;
int pos_standby = 180;    // variable to store the servo position 
int pos_active = 100;
int led = 13;
int mode = 1;             //1 for PROD, 2 for DEV (Serial Input
int bulb_status = 0;
int starttime = 0;
int endtime = 0;
int loopcount = 0;
int address = 12;
byte value;

void setup() { 
  Serial.begin(9600);
  Wire.begin();
  RTC.begin();
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
  }
  
  read_eeprom();              // Gets current position from EEPROM
  myservo.attach(3);          // Attaches the servo on pin 3 to the servo object 
  myservo.write(pos_standby); // Puts servo in default position
  Serial.println("Setup Complete");

  //#### Uncomment the below to set the RTC to the date & time this sketch was compiled ###
  //#### Then comment it out again and reupload sketch to Arduino ###  
  //RTC.adjust(DateTime(__DATE__, __TIME__));
}

void loop() {
  print_time();
  delay(500); 
  while (true){
   
      if (mode == 1) {
        bulb_sequence();
        }      
  
      starttime = millis();
      endtime = starttime;
      while (((endtime - starttime) <=10000) || (loopcount < 10000)) // do this loop for up to 10000mS
        {
        loopcount = loopcount+1;
        endtime = millis();
        }  
        
   recvOneChar();
   showNewData();

    if (receivedChar=='a') {
    Serial.println("A Selected");
    servo_move(1); //Bulb ON
    }  
    else if (receivedChar=='b') {
    Serial.println("B Selected");
    servo_move(2); //Bulb BLUE
    }     
    else if (receivedChar=='c') {
    Serial.println("C Selected");
    servo_move(3); //Bulb OFF
    }    
   receivedChar='d';
        
  }
}

void recvOneChar() {
 if (Serial.available() > 0) {
 receivedChar = Serial.read();
 newData = true;
 }
}

void showNewData() {
 if (newData == true) {
 //Serial.print("This just in ... ");
 //Serial.println(receivedChar);
 newData = false;
 }
}

void bulb_sequence() {
      DateTime now = RTC.now();
      if (now.hour() > 10 && now.hour() < 20 && bulb_status!=1) {
          servo_move(1); //Bulb ON
          }
      else if (now.hour() > 19 && now.hour() < 23 && bulb_status!=2) {
          servo_move(2); //Bulb BLUE
          }
      else if (now.hour()>=23 && bulb_status!=3) {
          servo_move(3); //Bulb OFF
          }   
          //Serial.println(bulb_status); 
          //Serial.println(now.hour);     
}

void servo_move(int x) 
{ 
  read_eeprom();
  while (bulb_status != x) {
    servo(); 
  }
  write_eeprom();   
} 

void servo() 
{ 
  myservo.write(pos_active);              // tell servo to go to position in variable 'pos' 
  delay(1000);                     // waits 1s for the servo to reach the position                       
  myservo.write(pos_standby);              // tell servo to go to position in variable 'pos' 
  delay(1000);                     // waits 1s for the servo to reach the position  
  bulb_status += 1;
  if (bulb_status == 4) {
    bulb_status = 1;
    digitalWrite(led, HIGH);  
    }
  digitalWrite(led, LOW);  
} 

void print_time() {
    DateTime now = RTC.now(); 
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
}

void read_eeprom()
{
  // read a byte from the current address of the EEPROM
  value = EEPROM.read(address);
  Serial.print("EERPROM Stored Value at Address: "); 
  Serial.print(address);
  Serial.print("\t");
  Serial.print(value, DEC);
  Serial.println();
  bulb_status = value;
}

void write_eeprom()
{
  EEPROM.write(address, bulb_status);
  Serial.print("New EEPROM: ");
  Serial.println(bulb_status);
}

That’s it!