Controlling a stepper motor with light sensor

I have an Adafruit TSL2591 High Dynamic Range Digital Light Sensor and Nema 17 stepper motor. Both are connected to seperate arduino unos. I want the light sensor to communicate with the stepper motor that when there is a significant drop in lux, to signal the stepper motor to turn off. Do I need to incorporate my two seperate codes into one? Or can I link them together from two seperate arduino unos.

Based off my research, connecting the A4 and A5 pins will allow the two unos to communicate. The issue is for my light sensor, the A4 and A5 pins are already occupied.

Also, see attached for layout of both schematics.

Light Sensor Code:

/* TSL2591 Digital Light Sensor */
/* Dynamic Range: 600M:1 */
/* Maximum Lux: 88K */

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"

// Example for demonstrating the TSL2591 library - public domain!

// connect SCL to I2C Clock
// connect SDA to I2C Data
// connect Vin to 3.3-5V DC
// connect GROUND to common ground

Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)

/**************************************************************************/
/*
   Displays some basic information on this sensor from the unified
   sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
 sensor_t sensor;
 tsl.getSensor(&sensor);
 Serial.println(F("------------------------------------"));
 Serial.print  (F("Sensor:       ")); Serial.println(sensor.name);
 Serial.print  (F("Driver Ver:   ")); Serial.println(sensor.version);
 Serial.print  (F("Unique ID:    ")); Serial.println(sensor.sensor_id);
 Serial.print  (F("Max Value:    ")); Serial.print(sensor.max_value); Serial.println(F(" lux"));
 Serial.print  (F("Min Value:    ")); Serial.print(sensor.min_value); Serial.println(F(" lux"));
 Serial.print  (F("Resolution:   ")); Serial.print(sensor.resolution, 4); Serial.println(F(" lux"));  
 Serial.println(F("------------------------------------"));
 Serial.println(F(""));
 delay(500);
}

/**************************************************************************/
/*
   Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
 // You can change the gain on the fly, to adapt to brighter/dimmer light situations
 //tsl.setGain(TSL2591_GAIN_LOW);    // 1x gain (bright light)
 tsl.setGain(TSL2591_GAIN_MED);      // 25x gain
 //tsl.setGain(TSL2591_GAIN_HIGH);   // 428x gain
 
 // Changing the integration time gives you a longer time over which to sense light
 // longer timelines are slower, but are good in very low light situtations!
 //tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS);  // shortest integration time (bright light)
 // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
 tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
 // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
 // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
 // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)

 /* Display the gain and integration time for reference sake */  
 Serial.println(F("------------------------------------"));
 Serial.print  (F("Gain:         "));
 tsl2591Gain_t gain = tsl.getGain();
 switch(gain)
 {
   case TSL2591_GAIN_LOW:
     Serial.println(F("1x (Low)"));
     break;
   case TSL2591_GAIN_MED:
     Serial.println(F("25x (Medium)"));
     break;
   case TSL2591_GAIN_HIGH:
     Serial.println(F("428x (High)"));
     break;
   case TSL2591_GAIN_MAX:
     Serial.println(F("9876x (Max)"));
     break;
 }
 Serial.print  (F("Timing:       "));
 Serial.print((tsl.getTiming() + 1) * 100, DEC); 
 Serial.println(F(" ms"));
 Serial.println(F("------------------------------------"));
 Serial.println(F(""));
}


/**************************************************************************/
/*
   Program entry point for the Arduino sketch
*/
/**************************************************************************/
void setup(void) 
{
 Serial.begin(9600);
 
 Serial.println(F("Starting Adafruit TSL2591 Test!"));
 
 if (tsl.begin()) 
 {
   Serial.println(F("Found a TSL2591 sensor"));
 } 
 else 
 {
   Serial.println(F("No sensor found ... check your wiring?"));
   while (1);
 }
   
 /* Display some basic information on this sensor */
 displaySensorDetails();
 
 /* Configure the sensor */
 configureSensor();

 // Now we're ready to get readings ... move on to loop()!
}

/**************************************************************************/
/*
   Shows how to perform a basic read on visible, full spectrum or
   infrared light (returns raw 16-bit ADC values)
*/
/**************************************************************************/
void simpleRead(void)
{
 // Simple data read example. Just read the infrared, fullspecrtrum diode 
 // or 'visible' (difference between the two) channels.
 // This can take 100-600 milliseconds! Uncomment whichever of the following you want to read
 uint16_t x = tsl.getLuminosity(TSL2591_VISIBLE);
 //uint16_t x = tsl.getLuminosity(TSL2591_FULLSPECTRUM);
 //uint16_t x = tsl.getLuminosity(TSL2591_INFRARED);

 Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
 Serial.print(F("Luminosity: "));
 Serial.println(x, DEC);
}

/**************************************************************************/
/*
   Show how to read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
 // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
 // That way you can do whatever math and comparisons you want!
 uint32_t lum = tsl.getFullLuminosity();
 uint16_t ir, full;
 ir = lum >> 16;
 full = lum & 0xFFFF;
 Serial.print(F("[ ")); Serial.print(millis()); Serial.print(F(" ms ] "));
 Serial.print(F("IR: ")); Serial.print(ir);  Serial.print(F("  "));
 Serial.print(F("Full: ")); Serial.print(full); Serial.print(F("  "));
 Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F("  "));
 Serial.print(F("Lux: ")); Serial.println(tsl.calculateLux(full, ir), 6);
}

/**************************************************************************/
/*
   Performs a read using the Adafruit Unified Sensor API.
*/
/**************************************************************************/
void unifiedSensorAPIRead(void)
{
 /* Get a new sensor event */ 
 sensors_event_t event;
 tsl.getEvent(&event);

 /* Display the results (light is measured in lux) */
 Serial.print(F("[ ")); Serial.print(event.timestamp); Serial.print(F(" ms ] "));
 if ((event.light == 0) |
     (event.light > 4294966000.0) | 
     (event.light <-4294966000.0))
 {
   /* If event.light = 0 lux the sensor is probably saturated */
   /* and no reliable data could be generated! */
   /* if event.light is +/- 4294967040 there was a float over/underflow */
   Serial.println(F("Invalid data (adjust gain or timing)"));
 }
 else
 {
   Serial.print(event.light); Serial.println(F(" lux"));
 }
}


/**************************************************************************/
/*
   Arduino loop function, called once 'setup' is complete (your own code
   should go here)
*/
/**************************************************************************/
void loop(void) 
{ 
 //simpleRead(); 
 advancedRead();
 // unifiedSensorAPIRead();
 
 delay(500);
}

Stepper Motor Code:

int smDirectionPin = 2; //Direction pin
int smStepPin = 3; //Stepper pin
int smEnablePin = 7; //Motor enable pin
 
void setup(){
  /*Sets all pin to output; the microcontroller will send them(the pins) bits, it will not expect to receive any bits from thiese pins.*/
  pinMode(smDirectionPin, OUTPUT);
  pinMode(smStepPin, OUTPUT);
  pinMode(smEnablePin, OUTPUT);
 
  digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest untill it is called uppond
 
  Serial.begin(9600);
}
 
void loop(){
  /*Here we are calling the rotate function to turn the stepper motor*/
  /*One revolution of this motor is 1600 steps*/
  /*driver is 8 microstep/step operation*/
  rotate(3200, 0.5); //The motor rotates 3200 steps (2 revolutions) clockwise with a speed of 0.5 (medium)
  delay(1000);
  rotate(-3200, 0.25); //The motor rotates 3200 steps (2 revolutions) counter clockwise with a speed of 0.25 (slow)
  delay(1000);
}
 
/*The rotate function turns the stepper motor. Tt accepts two arguments: 'steps' and 'speed'*/
void rotate(int steps, float speed){
  digitalWrite(smEnablePin, LOW); //Enabling the motor, so it will move when asked to
 
  /*This section looks at the 'steps' argument and stores 'HIGH' in the 'direction' variable if */
  /*'steps' contains a positive number and 'LOW' if it contains a negative.*/
  int direction;
 
  if (steps > 0){
    direction = HIGH;
  }else{
    direction = LOW;
  }
 
  speed = 1/speed * 70; //Calculating speed
  steps = abs(steps); //Stores the absolute value of the content in 'steps' back into the 'steps' variable
 
  digitalWrite(smDirectionPin, direction); //Writes the direction (from our if statement above), to the EasyDriver DIR pin
 
  /*Steppin'*/
  for (int i = 0; i < steps; i++){
    digitalWrite(smStepPin, HIGH);
    delayMicroseconds(speed);
    digitalWrite(smStepPin, LOW);
    delayMicroseconds(speed);
  }
 
  digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest untill the next time it is called uppond
}

To make it easy for people to help you please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum

Your code is too long for me to study quickly without copying to a text editor.

Also please use the AutoFormat tool to indent your code for easier reading.

I have not looked at your code but there seems no reason why both tasks can't be done with one Arduino.

If you really do want to communicate between two Arduinos and just need ArduinoA to let ArduinoB know that the light level is HIGH then all you need to do is connect a digital pin on each Arduino and also GND. The sending Arduin can output a HIGH on the pin when the light level is high, or a LOW otherwise.

...R

I think this is what your code should do:

  1. Check the value of the light sensor.
  2. If there is a significant drop in light, stop the step motor moving.
  3. Move the step motor a bit.
  4. Repeat.

I think one Arduino should be okay. It's complicated to send data over I2C or SPI or serial and sort what to do from all the commands and stuff.

I apologize about posting the code. Since it is reasonable to achieve this on one arduino, can you help with modifying the codes into one?

With the code below, how can I signal the stepper motor to turn off when there is a significant drop in lux. The code below integrates the interrupt function from the sensor. I thought that could possibly be used to turn the motor off too.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include "Adafruit_TSL2591.h"

// connect SCL to I2C Clock
// connect SDA to I2C Data
// connect Vin to 3.3-5V DC
// connect GROUND to common ground

// Interrupt thresholds and persistance
#define TLS2591_INT_THRESHOLD_LOWER  (100)
#define TLS2591_INT_THRESHOLD_UPPER  (1500)
//#define TLS2591_INT_PERSIST        (TSL2591_PERSIST_ANY) // Fire on any valid change
#define TLS2591_INT_PERSIST          (TSL2591_PERSIST_60)  // Require at least 60 samples to fire

int smDirectionPin = 2; //Direction pin
int smStepPin = 3; //Stepper pin
int smEnablePin = 7; //Motor enable pin

Adafruit_TSL2591 tsl = Adafruit_TSL2591(2591); // pass in a number for the sensor identifier (for your use later)

/**************************************************************************/
/*
    Displays some basic information on this sensor from the unified
    sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void)
{
  sensor_t sensor;
  tsl.getSensor(&sensor);
  Serial.println("------------------------------------");
  Serial.print  ("Sensor:       "); Serial.println(sensor.name);
  Serial.print  ("Driver Ver:   "); Serial.println(sensor.version);
  Serial.print  ("Unique ID:    "); Serial.println(sensor.sensor_id);
  Serial.print  ("Max Value:    "); Serial.print(sensor.max_value); Serial.println(" lux");
  Serial.print  ("Min Value:    "); Serial.print(sensor.min_value); Serial.println(" lux");
  Serial.print  ("Resolution:   "); Serial.print(sensor.resolution, 4); Serial.println(" lux");
  Serial.println("------------------------------------");
  Serial.println("");
  delay(500);
}

/**************************************************************************/
/*
    Configures the gain and integration time for the TSL2591
*/
/**************************************************************************/
void configureSensor(void)
{
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  //tsl.setGain(TSL2591_GAIN_LOW);    // 1x gain (bright light)
  tsl.setGain(TSL2591_GAIN_MED);      // 25x gain
  // tsl.setGain(TSL2591_GAIN_HIGH);   // 428x gain

  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(TSL2591_INTEGRATIONTIME_100MS);  // shortest integration time (bright light)
  // tsl.setTiming(TSL2591_INTEGRATIONTIME_200MS);
  // tsl.setTiming(TSL2591_INTEGRATIONTIME_300MS);
  // tsl.setTiming(TSL2591_INTEGRATIONTIME_400MS);
  // tsl.setTiming(TSL2591_INTEGRATIONTIME_500MS);
  // tsl.setTiming(TSL2591_INTEGRATIONTIME_600MS);  // longest integration time (dim light)

  /* Display the gain and integration time for reference sake */
  Serial.println("------------------------------------");
  Serial.print  ("Gain:         ");
  tsl2591Gain_t gain = tsl.getGain();
  switch (gain)
  {
    case TSL2591_GAIN_LOW:
      Serial.println("1x (Low)");
      break;
    case TSL2591_GAIN_MED:
      Serial.println("25x (Medium)");
      break;
    case TSL2591_GAIN_HIGH:
      Serial.println("428x (High)");
      break;
    case TSL2591_GAIN_MAX:
      Serial.println("9876x (Max)");
      break;
  }
  Serial.print  ("Timing:       ");
  Serial.print((tsl.getTiming() + 1) * 100, DEC);
  Serial.println(" ms");
  Serial.println("------------------------------------");
  Serial.println("");

  /* Setup the SW interrupt to trigger between 100 and 1500 lux */
  /* Threshold values are defined at the top of this sketch */
  tsl.clearInterrupt();
  tsl.registerInterrupt(TLS2591_INT_THRESHOLD_LOWER,
                        TLS2591_INT_THRESHOLD_UPPER,
                        TLS2591_INT_PERSIST);

  /* Display the interrupt threshold window */
  Serial.print("Interrupt Threshold Window: ");
  Serial.print(TLS2591_INT_THRESHOLD_LOWER, DEC);
  Serial.print(" to ");
  Serial.println(TLS2591_INT_THRESHOLD_UPPER, DEC);  
  Serial.println("");
}


/**************************************************************************/
/*
    Program entry point for the Arduino sketch
*/
/**************************************************************************/
void setup(void)
{
  /*Sets all pin to output; the microcontroller will send them(the pins) bits, it will not expect to receive any bits from these pins.*/
  pinMode(smDirectionPin, OUTPUT);
  pinMode(smStepPin, OUTPUT);
  pinMode(smEnablePin, OUTPUT);
 
  digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest untill it is called uppond
  
  Serial.begin(9600);

  // Enable this line for Flora, Zero and Feather boards with no FTDI chip
  // Waits for the serial port to connect before sending data out
  // while (!Serial) { delay(1); }

  Serial.println("Starting Adafruit TSL2591 interrupt Test!");

  if (tsl.begin())
  {
    Serial.println("Found a TSL2591 sensor");
  }
  else
  {
    Serial.println("No sensor found ... check your wiring?");
    while (1);
  }

  /* Display some basic information on this sensor */
  displaySensorDetails();

  /* Configure the sensor (including the interrupt threshold) */
  configureSensor();

  // Now we're ready to get readings ... move on to loop()!
}

/**************************************************************************/
/*
    Show how to read IR and Full Spectrum at once and convert to lux
*/
/**************************************************************************/
void advancedRead(void)
{
  // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
  // That way you can do whatever math and comparisons you want!
  uint32_t lum = tsl.getFullLuminosity();
  uint16_t ir, full;
  ir = lum >> 16;
  full = lum & 0xFFFF;
  Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
  Serial.print("IR: "); Serial.print(ir);  Serial.print("  ");
  Serial.print("Full: "); Serial.print(full); Serial.print("  ");
  Serial.print("Visible: "); Serial.print(full - ir); Serial.print("  ");
  Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
}


void getStatus(void)
{
  uint8_t x = tsl.getStatus();
  // bit 4: ALS Interrupt occured
  // bit 5: No-persist Interrupt occurence
  if (x & 0x10) {
    Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
    Serial.println("ALS Interrupt occured");
  }
  if (x & 0x20) {
    Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
    Serial.println("No-persist Interrupt occured");
  }

  // Serial.print("[ "); Serial.print(millis()); Serial.print(" ms ] ");
  Serial.print("Status: ");
  Serial.println(x, BIN);
  tsl.clearInterrupt();
}


/**************************************************************************/
/*
    Arduino loop function, called once 'setup' is complete (your own code
    should go here)
*/
/**************************************************************************/
void loop(void)
{
  advancedRead();
  getStatus();
  delay(500);
  
  /*Here we are calling the rotate function to turn the stepper motor*/
  /*One revolution of this motor is 1600 steps*/
  /*driver is 8 microstep/step operation*/
  rotate(3200, 0.5); //The motor rotates 3200 steps (2 revolutions) clockwise with a speed of 0.5 (medium)
  delay(1000);
  rotate(-3200, 0.25); //The motor rotates 3200 steps (2 revolutions) counter clockwise with a speed of 0.25 (slow)
  delay(1000);
}
 
/*The rotate function turns the stepper motor. Tt accepts two arguments: 'steps' and 'speed'*/
void rotate(int steps, float speed){
  digitalWrite(smEnablePin, LOW); //Enabling the motor, so it will move when asked to
 
  int direction;
 
  if (steps > 0){
    direction = HIGH;
  }else{
    direction = LOW;
  }
 
  speed = 1/speed * 70;
  steps = abs(steps); //Stores the absolute value of the content in 'steps' back into the 'steps' variable
 
  digitalWrite(smDirectionPin, direction); //Writes the direction (from our if statement above), to the EasyDriver DIR pin
 
  for (int i = 0; i < steps; i++){
    digitalWrite(smStepPin, HIGH);
    delayMicroseconds(speed);
    digitalWrite(smStepPin, LOW);
    delayMicroseconds(speed);
  }
 
  digitalWrite(smEnablePin, HIGH); //Disbales the motor, so it can rest until the next time it is called upon
  
}

Threads merged.

You should include a testing statement that reads a variable that contains the lux value and test to see if there is a great significant drop in the variable. If the drop is great, than use the return; statement and the loop will never reach the code that moves the step motor.. (It's something to do with an "if()")

kylemanning14:
With the code below, how can I signal the stepper motor to turn off when there is a significant drop in lux.

Do you want the motor to stop in the middle of a movement if the light changes?

If so your code needs to check the sensor between steps - something like this pseudo code

void loop() {
   checkSensor();
   if (lux == HIGH and stepCount <= stepMax) {
       moveOneStep();
       stepCount ++;
   }
}

I am not sure when the step count should be reset to 0 so I have not included that,

...R