сделать/доделать скетч для слайдера видеокамеры

Нет ответов
Denis Ivanov
Offline
Зарегистрирован: 28.03.2017

Здравствуйте господа,

Cобственно есть наполовину написанный скетч для слайдера с шаговым мотором NEMA17. Исполнитель не смог продолжить проект по личным обстоятельствам, поэтому мне надо довести его до конца или переделать.

Сам не разбираюсь совсем, знаний хватило собрать механическую часть самому и электроннику по схеме от исполнителя.

В наличии вот этот Кит Ардуино и Мотор.

 

Требования:

Включение/выключения движения длинным нажатием на энкодер. Смена направления коротким. Регулировка скорости вращением. Должно работать как до запуска так и на ходу, с отображением на дисплее направления движения, текущей скорости, ну и точного положения раз уж все равно шаги считаем.

Автоматическая смена направления при достижении конечных пунктов слайдера.

Как ручные, так и автоматические остановки/смены направления с плавным торможением-разгоном.

Конечные остановки без датчиков, высчитываются по количеству шагов мотора, что требует калибровку при старте.

алгоритм калибровки: при заранее измеренном количестве шагов, при старте системы дисплей выдает слово Calibration? и стрелку направления домой (в крайнее положение в сторону мотора). вручную сдвигаю каретку в домашнее положение, и нажимаю на энкодер, подтверждая что каретка находится в домашнем положении. режим движения автоматически переключается в обратное направление. При нажатии на старт едет заданное количество шагов, там останавливается и едет назад, до домашнего крайнего положения, и так далее.

 

Что имеем:

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

собрано вот по такой схеме

 

 

Скетч:

/************************************
  Проект:   слайдер для видеокамеры
  Заказчик: Денис Иванов
  E-mail:   
*************************************/

#include <U8glib.h>
#define pinE  10
#define pinRW 9
#define pinDI 8
U8GLIB_ST7920_128X64 u8g(pinE, pinRW, pinDI, U8G_PIN_NONE);
//U8GLIB_KS0108_128 u8g(8, 9, 10, 11, 4, 5, 6, 7, 18, 14, 15, 17, 16);     // 8Bit Com: D0..D7: 8,9,10,11,4,5,6,7 en=18, cs1=14, cs2=15,di=17,rw=16

/* Вывод, который будет измерять напряжение батареи. Напряжение на вывод подаётся
   через резистивный делитель. Верхнее плечо - 510 кОм, нижнее плечо - 33 кОм.
   Максимальное напряжение, подаваемое на делитель - 18.1В. При этом с делителя на 
   вход микроконтроллера будет поступать 1.1В, т.е. максимальное опорное. */
#define pinU  A0

/* Номера выврдов, к которым подключен энкодер */
#define pinEncoderA       2
#define pinEncoderB       3
#define pinEncoderButton  12

/* Номера выводов, к которым подключен драйвер A4988 шагового двигателя NEMA17 */
#define pinStep       22
#define pinDirection  23

#include <AccelStepper.h>
AccelStepper mystepper(1, pinStep, pinDirection); // Инициализация ШД для управления внешним драйвером


/* Функция измерения напряжения батареи */
float getBattaryU(void) {
  float U = 0.0;
  uint16_t adc = 0;
  for(uint8_t i=0; i<10; i++) adc += analogRead(pinU);  // Считываем показания АЦП 10 раз для повышения точности
  adc /= 10;                                            // Вычисляем среднее значение АЦП
  U = float(adc) * 18.1 / 1023.0;                       // Вычисляем реальное значение напряжения батареи
  return U;                                             // Возвращаем усреднённое значение напряжения
}

volatile int stepperSpeed = 10;  // Скорость ШД
volatile long steps = 0;
volatile bool calibration = false;


void setup() {
  analogReference(INTERNAL1V1);             // Включаем внутренний ИОН на 1.1В
  
  attachInterrupt(0, encoder, RISING);      // Внешнее прерывание для обработки 1-го вывода энкодера
  pinMode(pinEncoderB, INPUT_PULLUP);       // Настройка на вход второго вывода энкодера
  pinMode(pinEncoderButton, INPUT_PULLUP);  // Настройка на вход вывода для кнопки энкодера

  /* Настройка параметров ШД */
  pinMode(pinStep, OUTPUT);
  pinMode(pinDirection, OUTPUT);
  mystepper.setMaxSpeed(400);               // Максимальная скорость, шагов в секунду (для NEMA17 - 2 оборота в секунду)
  mystepper.setAcceleration(10.0);          // Ускорение ШД, шагов в секунду
  mystepper.setSpeed(0);                    // Начальная скорость равна 0

  // Настройка таймера Т2 для опроса кнопки энкодера в прерывании
  TCCR2A = 0x00; TCCR2B = 0x07; TCNT2 = 0x00; TIMSK2 = 0x01;
  sei();
  Serial.begin(9600);
}

volatile uint8_t menuFlag = 0;

/* Прерывание для обработки вращения энкодера */
void encoder() {
    if(digitalRead(pinEncoderB) == HIGH) {
      stepperSpeed++;
      if(stepperSpeed > 400) stepperSpeed = 0;
    }
    else {  
      stepperSpeed--;
      if(stepperSpeed < 0) stepperSpeed = 400;
    }
}

/* Функция обработки нажатия кнопки энкодера */
volatile bool flagPress = false;
volatile bool longPress = false;
volatile unsigned long timePress = 0;

volatile uint8_t button() {
  /* Определение момента нажатия кнопки */
  if((!flagPress) && (!longPress) && (digitalRead(pinEncoderButton) == LOW)) {
    delay(50);
    if(digitalRead(pinEncoderButton) == LOW) {
      flagPress = true;
      timePress = millis();
    }
  }

  /* Определение момента удержания кнопки */
  if((flagPress) && (!longPress) && (millis() - timePress > 1500)) {
    longPress = true;
    timePress = millis();
    return 2;
  }

  /* Определение момента отпускания кнопки */
  if((digitalRead(pinEncoderButton) == HIGH) && (flagPress)) {
    delay(50);
    if(digitalRead(pinEncoderButton) == HIGH) {
      if(longPress) { flagPress = false; longPress = false; return 0; }
      else if(!longPress) { flagPress = false; longPress = false; return 1; }
    }
  }
  return 0;
}
volatile bool stepperDirection = false;
/* Прерывание для обработки нажатия кнопки энкодера */
ISR(TIMER2_OVF_vect) {
  switch(button()) {
    case 1:
      stepperDirection = !stepperDirection;
     // return;
    break;

    case 2:
      calibration = !calibration;
     // return;
    break;
  }
}

/* Функция отображения меню */
void menu() {
  u8g.firstPage();
  do 
  {
    u8g.setFont(u8g_font_6x12);
   // u8g.drawBox(0, 13, 128, 1);
    u8g.setPrintPos(0, 12); u8g.print("U_battary="); u8g.print(getBattaryU()); u8g.print("V    ");
   
    u8g.setPrintPos(0, 24); u8g.print(stepperSpeed); u8g.print("step/s; "); u8g.print(float(stepperSpeed) / 200.0); u8g.print("turn/s");

    if(!stepperDirection) {u8g.setPrintPos(0, 36); u8g.print("Direction: --->");}
    else {u8g.setPrintPos(0, 36); u8g.print("Direction: <---");}
    
    if(!calibration) {u8g.setPrintPos(0, 48); u8g.print("Push encoder to start");}
    else {u8g.setPrintPos(0, 48); u8g.print("Push encoder to stop ");}

    u8g.setPrintPos(0, 60); u8g.print("STEPS:"); u8g.print(steps);
    
    switch(menuFlag) {
      case 0:
        
      break;
    }
  } while(u8g.nextPage());
}

int dir = 0; long CP=mystepper.currentPosition();
void loop() {
  menu();
  
  if(!stepperDirection) dir = 1;
  else dir = -1;
  
  if(calibration) {
    mystepper.setSpeed(stepperSpeed);
    mystepper.runSpeed();
    steps = mystepper.currentPosition() - CP;
  }  
}