Мониторинг нескольких аналоговых портов с датчиками тока ACS712

Делаю автоматические взрывные ворота для сбора пыли в моем деревообрабатывающем цехе. Arduino Nano использует ACS712 для определения того, когда используется инструмент. Использование DRV8825 для привода одного шагового двигателя, который будет вращать диск, чтобы выровнять затвор для используемого инструмента. Код работает, как и ожидалось, с одним закодированным датчиком, но я не могу понять, как заставить его работать с дополнительным закодированным датчиком. Не уверен, что именно так возникает вопрос, спасибо

/*Этот человек начинает работать.   Когда инструмент включен, ACS712 обнаруживает его, и шаговый механизм перемещается на 90 градусов/шагов. 

Когда инструмент выключен, он остается в желаемом положении, так как я бы использовал один и тот же инструмент несколько раз подряд. Нужно добавить датчик A1 и назначить ему различные шаги. Могу ли я объявить значения каждого датчика 1 раз, которые будут использоваться всякий раз, когда этот аналоговый порт считывает > текущий порог? Могу ли я получить инструкцию, которая проверит все аналоги и будет действовать в соответствии с тем, который >текущий порог? Нужно, чтобы шаговый двигатель перемещался только в том случае, если другой датчик (чем предыдущий аналоговый#) > текущий порог? ЕСЛИ/Иначе */

#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

, 👍1

Обсуждение

Ваш текущий код работает только один раз, потому что код никогда не может покинуть последний цикл while в функции loop (). analogValue не изменяется в цикле while, поэтому условие всегда будет истинным., @chrisl


1 ответ


1

Во-первых: Как написано в комментариях, ваш текущий код будет работать только один раз. После первого достижения порогового значения он навсегда останется в последнем цикле while, так как значение analogValue никогда не может там измениться (вы не присваиваете ему новое значение). Таким образом, эта часть должна быть удалена.


Чтобы расширить свой код для нескольких датчиков, вы можете организовать все соответствующие данные в массивы, чтобы можно было перебирать их. Сначала мы определяем массив используемых выводов аналогового ввода (вместе с определением размера массива, чтобы позже мы могли легко перебирать массив и по-прежнему могли легко добавлять дополнительные датчики):

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

Затем мы определяем аналогичные массивы для пороговых значений и позиций шага:

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

Теперь в функции loop() мы можем окружить измерение и шаговый код циклом по массивам. Там, где вы использовали определения раньше, теперь мы используем элементы массива соответствующего индекса:

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 ()
    }
}

Теперь вам все еще нужно учитывать 2 вещи:

  • В зависимости от количества датчиков, ваш код в настоящее время может занять довольно много времени. С помощью, скажем, 6 датчиков вы измеряете в общей сложности 3 секунды в худшем случае (когда последняя машина включена). Возможно, вам захочется сократить продолжительность измерения (500 мс-это довольно долго).

  • Вам нужно добавить код для определения того, что происходит, когда вы включаете несколько машин одновременно. В настоящее время это привело бы к тому, что шаговый двигатель двигался бы взад и вперед; конечно, это не то, что вы хотите. Проще всего было бы рассмотреть только первый датчик, который достигает порога, который затем устанавливает позицию ("первый" не в хронологическом смысле, а в порядке вывода в массиве sensor_pins). Вы можете достичь этого с помощью команды break; в конце порогового значения, если условие.


Примечания:

  • Массивы сохраняют то, что они говорят. sensor_thresholds содержит все пороговые значения. В моем примере 570 - это порог первого датчика, а 400-порог второго датчика. 90 в stepper_positions-это положение шагового устройства для первого датчика. 180-это положение второго датчика.

  • В своем примере я использовал 2 датчика. Вы можете расширить это самостоятельно, установив значение define SENSOR_N на количество датчиков и добавив элементы для каждого датчика в массивы.

  • uint8_t и uint16_t являются целочисленными типами без знака с указанным количеством битов: uint8_t имеет 8 бит (1 байт), uint16_t имеет 16 бит (2 байта). uint8_t - это то же самое, что unsigned char или байт. uint16_t-это то же самое, что и unsigned int в Uno/Nano. Я использовал эти типы, потому что это хорошая практика-использовать типы, которые имеют одинаковый размер на каждой платформе. При переходе на другую платформу такие типы, как unsigned int, могут иметь другой размер, например, 32-разрядное целое число без знака вместо 16-разрядного. Поскольку это может привести к нарушению кода, зависящего от конкретного размера типа, я стараюсь всегда использовать типы одинакового размера на всех платформах. Эти типы всегда имеют один и тот же шаблон. Существуют также: uint32_t, int16_t (целое число со знаком) или int8_t.

  • Я выбрал размеры типов в соответствии с ожидаемыми значениями. Выводы обычно составляют 8 бит/1 байт. Этого достаточно. Пороговые значения превышают 255, поэтому 8 бит недостаточно, поэтому я выбрал 16-битное целое число. В зависимости от необходимых вам положений шагового режима вы можете также изменить его тип на uint16_t.

,

Большое спасибо за ваш вклад. У вас есть несколько вопросов, которые я не понимаю., @Greg

Большое спасибо за ваш вклад. У меня есть несколько вопросов, которые я не понимаю. SENSOR_N 2 // это говорит о том, что есть 2 датчика, я бы изменил 2 на=num датчиков. uint8_t sensor_pins[SENSOR_N] = {A0, A1}; Не знаком с uint (я посмотрю) что такое 8? Далее, все мои датчики будут иметь один и тот же порог, так что ниже 570-это порог, а 400-это шаги? uint16_t sensor_thresholds[SENSOR_N] = {570, 400}; Единица измерения "16/8"? Я буду работать над этим. Спасибо, что нашли время помочь мне, @Greg

@Greg Я добавил несколько заметок в свой ответ, чтобы ответить на ваши вопросы, @chrisl

крисл, еще раз спасибо. Это многое объясняло. Я еще не решил, буду ли я использовать ступени или градусы. Если я это понимаю, то использование градусов 360 было бы самым большим числом, так что я мог бы использовать 16. Есть ли проблема с использованием 16, даже если вам это не нужно? Я буду работать над этим. Большое спасибо. Ничего, если я отправлю вам свой заполненный код? Просто привыкаю к переполнению стека, @Greg

Нет проблем использовать 16-битный тип, когда вам нужно только 8 бит. Это скорее лучшая практика-использовать только ту память, которая вам нужна, так как большинство Arduino на базе AVR (например, Nano) имеют относительно мало памяти. Хотя это важно только тогда, когда вы достигаете предела своей программы., @chrisl

О публикации завершенного кода: Если завершенный код работает правильно и вы хотите поделиться им с другими, чтобы помочь им решить ту же проблему, вы можете опубликовать готовый код в качестве ответа. Если вы хотите, чтобы мы проверили его на наличие ошибок, то это совсем другое дело. Если ваш код все еще не работает из-за проблемы, непосредственно связанной с этим вопросом, вы можете добавить новый код в конце вашего вопроса. Если это не тесно связано, то вы можете задать новый вопрос о нем. Если вы не проверили его до этого момента, вы должны сначала проверить его, прежде чем просить нас проверить наличие ошибок (поиск иголки в стоге сена-это не фонд)., @chrisl

крисл, твой код работает как описано! Я добавил дополнительные аналоговые входы и протестировал их. Я не могу исправить 2 проблемы (могут быть одинаковыми), нужно отключить степпер после его перемещения. Если я этого не сделаю, то водитель перегреется, и мне не нужно будет удерживать позицию. Если я использую Disable (), он вращается каждый раз, когда цикл завершен, или если ни один инструмент не включен, он импульсирует шаговый двигатель (думаю, это включить/отключить каждый цикл. Также нужно игнорировать один и тот же датчик, если он был обнаружен последним. Много раз я буду использовать один и тот же инструмент повторно, нужно, чтобы он оставался отключенным, пока не увидит другой датчик. Спасибо, как всегда., @Greg

Если я пойду к кодировщику для степпера, это может решить мои проблемы. Насколько я понимаю, кодировщик знает и помнит, где он находится. Поэтому, если я использую один и тот же инструмент несколько раз, он должен оставаться в одном и том же положении. Следует повернуть в новое положение. Правильно ли я думаю и нужно ли добавлять код для кодировщика? В качестве альтернативы я мог бы добавить сеньоров, чтобы обнаружить, что датчик находится в правильном положении., @Greg

крисл, как и большинство других, в 2020 году было много препятствий, но я вернулся к этому и добился прогресса., @Greg