1

Making a Auto Blast Gate for dust collection in my wood shop. Arduino Nano using ACS712's to detect when tool is in use. Using DRV8825 to drive a single Stepper motor that will spin a disk to line up blast gate for the tool in use. Code works as expected with one sensor coded but I can't figure out how to make it work with additional sensor coded in. Not sure if this is the way the question shows up, Thanks

enter image description here

/*This one is atarting to work.   When tool is turn on the ACS712 detects it and the stepper moves 90 deg/steps. 

When the tool is turned off it remains in position which is desireable as I would use the same tool multiable times in a row. Need to add sensor A1 and assign different steps to it. Can I declare the values of each sensor 1 time to be used whenever that analog port read > current Threshold? Can I have a statement that will check all the analogs and act on the one that is >current Threshold? Need for the stepper to only move if a different sensor (than the previous analog#) is > current Threshold? IF/Else */

#include <Arduino.h>
#include "BasicStepperDriver.h"
#include "DRV8825.h"

#define MOTOR_STEPS 360 // Motor steps per revolution. Most steppers are 200 steps or 1.8 degrees/step
#define RPM 200
#define MICROSTEPS 1    // Since microstepping is set externally, make sure this matches the selected mode
                        // If it doesn't, the motor will move at a different RPM than chosen
                        // 1=full step, 2=half step etc.
#define DIR 2           // All the wires needed for full functionality
#define STEP 3
#define ENABLE 4        // 2-wire basic config, microstepping is hardwired on the driver
BasicStepperDriver stepper(MOTOR_STEPS, DIR, STEP, ENABLE);


#define CURRENT_SENSOR_PIN A0 // Current sensor is connected to analog pin A0

#define CURRENT_THRESHOLD 570 // The analog value above which the relay shall be triggered
#define CURRENT_SAMPLE_PERIOD 500 // The number of milliseconds to sample the current reading

int analogValue = 0; // Stores ADC values read in from the current sensor
unsigned long stopwatch = 0; // Used to keep track of elapsed time


void setup() {
  Serial.begin(9600);
  pinMode(DIR, OUTPUT);
  pinMode(STEP, OUTPUT);
  pinMode(ENABLE, OUTPUT);
 // pinMode (A0, INPUT);

    stepper.begin(RPM, MICROSTEPS);
    stepper.setEnableActiveState(LOW);  
  }

void loop() {
    analogValue = 0; // Initialize analogValue to a known state
    stopwatch = millis(); // Store a snapshot of the current time since the program started executing

    // Collect the max ADC value from the current sensor for the predetermined sample period
    while (millis() - stopwatch < CURRENT_SAMPLE_PERIOD) {
      analogValue = max(analogValue, analogRead(CURRENT_SENSOR_PIN));
      Serial.println(analogValue);
    }

    // If the max ADC value from the current sensor exceeds the threshold, set the state to LOW
    if (analogValue > CURRENT_THRESHOLD) {
      stepper.enable();  //  energize coils - the motor will hold position
      stepper.rotate(90);  //Moving motor using the degree notation in ()

   }
    while(analogValue > CURRENT_THRESHOLD) 
      stepper.disable();  // pause and allow the motor to be moved by hand
}
// need to return to top of loop
Delta_G
  • 3,270
  • 2
  • 10
  • 24
Greg
  • 39
  • 7
  • Your current code only works exactly one time, because the code can never leave the last while loop in the loop() function. analogValue doesn't change in the while loop, so the condition will always be true. – chrisl Apr 14 '20 at 03:48

1 Answers1

1

First: As written in the comments, your current code will only work once. After the first reaching of the threshold it will permanently stay in the last while loop, since analogValue can never change in there (you don't assign a new value to it). Thus this part should be removed.


To extend your code for multiple sensors, you can organize all the relevant data into arrays, so that you can loop over them. First we define an array of the used analog input pins (together with a define for the array size, so that we can later easily loop over the array and still be able to easily add further sensors):

#define SENSOR_N    2
uint8_t sensor_pins[SENSOR_N] = {A0, A1};

Then we are defining similar arrays for the thresholds and stepper positions:

uint16_t sensor_thresholds[SENSOR_N] = {570, 400};
uint8_t stepper_positions[SENSOR_N] = {90, 180};

Now in the loop() function we can surround the measurement and stepper code into a loop over the arrays. Where you used defines before, we are now using the array elements of the corresponding index:

for(uint8_t i=0;i<SENSOR_N;i++){
    analogValue = 0; // Initialize analogValue to a known state
    stopwatch = millis(); // Store a snapshot of the current time since the program started executing

    // Collect the max ADC value from the current sensor for the predetermined sample period
    while (millis() - stopwatch < CURRENT_SAMPLE_PERIOD) {
        analogValue = max(analogValue, analogRead(sensor_pins[i]));
        Serial.println(analogValue);
    }

    // If the max ADC value from the current sensor exceeds the threshold, set the state to LOW
    if (analogValue > sensor_thresholds[i]) {
        stepper.enable();  //  energize coils - the motor will hold position
        stepper.rotate(stepper_positions[i]);  //Moving motor using the degree notation in ()
    }
}

Now you still have 2 things to consider:

  • Depending of the number of sensors, your code currently can take rather long. With lets say 6 sensor, you are measuring for 3s in total at the worst case (when the last machine is turned on). You might want to reduce your measurement duration (500ms is rather long).

  • You need to add code for defining, what happens, when you turn multiple machines on at the same time. Currently that would lead to the stepper motor going back and forth; surely not what you want. The easiest thing would be to only consider the first sensor, that reaches the threshold, which then gets to set the position ("first" not in chronological sense, but in the order of the pin in the sensor_pins array). You can reach that with a break; command at the end of the threshold if condition.


Notes:

  • The arrays hold, what they say. sensor_thresholds holds all the thresholds. In my example 570 is the threshold of the first sensor and 400 is the threshold of the second sensor. 90 in stepper_positions is the position of the stepper for the first sensor. 180 is the position for the second sensor.

  • I used 2 sensors in my example. You can extend that yourself by setting the define SENSOR_N to the number of sensors and adding elements for every sensor into the arrays.

  • uint8_t and uint16_t are unsigned integer types with the mentioned number of bits: uint8_t has 8 bits (1 byte), uint16_t has 16 bits (2 bytes). uint8_t is the same as unsigned char or byte. uint16_t is the same as unsigned int on the Uno/Nano. I used these types, because it is a good practice to use types, that have the same size on every platform. When changing to a different platform, types like unsigned int might have a different size, like being a 32 bit unsigned integer instead of a 16 bit one. As that might break code, that relies on the specific size of the type, I try to always use types with the same size on all platforms. These types have always the same pattern. There are also: uint32_t, int16_t (signed integer) or int8_t.

  • I've chosen the type sizes according to the expected values. Pin numbers are typically 8bit/1 byte. That is sufficient. The thresholds are above 255, thus 8 bits are not enough, so I chose a 16 bit integer. Depending on the stepper positions, that you need, you might want to change it's type also to uint16_t.

chrisl
  • 16,257
  • 2
  • 17
  • 27
  • Thanks very much for your input. Have a few questions that I don't understand.T – Greg Apr 14 '20 at 21:40
  • Thanks very much for your input. Have a few questions that I don't understand. SENSOR_N 2 // this is stating there are 2 sensors I would change the 2 to=num of sensors. uint8_t sensor_pins[SENSOR_N] = {A0, A1}; Not familiar with the uint (I will look up) what is the 8? Next, all my sensors would have the same threshold, so below the 570 is the threshold and 400 is the steps? uint16_t sensor_thresholds[SENSOR_N] = {570, 400}; The unit "16/8"? I will work on this. Thanks for taking the time to help me – Greg Apr 14 '20 at 22:46
  • @Greg I added some notes in my answer to address your questions – chrisl Apr 15 '20 at 09:27
  • chrisl, Thanks again. That explained much. I haven't decided yet if I will be using steps or degrees. If I understand this, using degrees 360 would be the largest number so I could use 16. Is there a problem with using 16 even if you don't need that much? I will go to work on this. Thanks so much. Is it OK if I post or send my completed code to you. Just getting use to Stack overflow – Greg Apr 15 '20 at 13:45
  • It no problem to use a 16 bit type, when you only need 8 bits. That's more of a best practice; to use only the memory, that you need, as most AVR based Arduinos (like the Nano) have relatively little memory. Though that is only important, when you are reaching the limit with your program. – chrisl Apr 15 '20 at 14:27
  • About posting the completed code: If the completed code works correctly and you want to share with others to help them with the same problem, you can post the finished code as an answer. If you want us check it for errors it is different. If your code still doesn't work because of a problem directly related to this question, you can add the new code at the end of your question. If it is not closely related, then you can ask a new question about it. If you didn't test it to that point, you should test it first, before asking us to check for errors (searching a needle in a haystack is no fund) – chrisl Apr 15 '20 at 14:31
  • chrisl, Your code works as describe! I added additional Analog inputs and tested them. I can't fix 2 issues (may be the same) Need to disable stepper after it moves. If I don't it will overheat the driver, I don't need to hold position. If I use the Disable() it rotates every time the loop is done, or if no tool is turned on it pulses the stepper, (think this is enable/disable every loop. Also need to ignore the same sensor if it was the last one detected. Many times I will use the same tool repeatedly, need it to remain Disabled until it see a different sensor. Thanks as always. – Greg Apr 15 '20 at 18:50
  • If i go to a encoder for the stepper might solve my problems. As i understand a encoder it knows and remembers where its at. So if I use the same tool repeatedly it should stay in the same position. Should rotate to the new position. Am I thinking right and do I need to add code for the encoder. As a alternate I could add senors to detect that the sensor is in correct position. – Greg Apr 19 '20 at 23:00
  • chrisl, like most, 2020 has had many obstacles, but I'm back at it and have made progress. – Greg Mar 31 '21 at 21:41