Электрическая фокусировочная схема для дешевого телескопа TAPOK

La1m1e
Offline
Зарегистрирован: 30.12.2021

1. Идея

Есть у меня значит телескоп, дешевый и достаточно ущербный. При наведении на обожаемое тело (Небесное естественно) и попытке сфокусироваться вручную, при любом касании и приложении силы жутко начинает вибрировать на штативе, и вибрация эта очень раздражает. И пришла мне в голову идея сделать полностью электрически управляемый телескоп. Хотел я купить шаговые двигатели и винтовые направляющие. Изначально хотел сделать на NRF24, чтобы даже провод не мешал столь "нежной" аппаратуре, но узнал что одна из нрфок в кз и от идеи пришлось отказаться. Затем пришла идея сделать приложение и связь по wi-fi с ESP 8266, но после подключения в ней застрял мой видавший всякое ЮСБ кабель и при попытке его вытащить была допущена фатальная ошибка - я коснулся чего-то на плате своими красными и потными от праведного гнева руками. ESP этого не пережила. Да здравствует ESP!

После всех этих неудач я понял:

1. Сейчас у меня нет инструмента для этого, даже банальной дрели для крепления шаговиков не говоря о сварочном аппарате для приваривания того что необходимо приварить.

2. Покупка трёх шаговиков и направляющих со всем необходимым обвесом обойдется минимум в 30-40 Баксов, что является половиной цены такого нового телескопа, при том что сам телескоп в бородатые времена обошелся мне в 15 вечнозеленых, да ещё и доставку ждать под НГ придется до марта.

После этих размышлений решил действовать. Не так масштабно, ведь это мой первый проект доведенный до конца в принципе. Максимальных колхоз, не щадя ничего на своём пути. Поэтому проект и называется TAPOK, ведь он собран в корпусе роутера TP-LINK и дыры под энкодер и светодиод пришлись прямо на символы -LIN. Так и образовалось культовое название этого ужасного и одновременно прекрасного проекта - TPOK (В режиссерской версии - гордый ТАПОК)

2. Реализация 

На этом пункте хочется плакать. Нет, я серьезно. Мне пришлось ездить за двумя метрами медной проволоки для полуторасантиметровой тяги сервопривода, так как вырывать её из электрощитка мне запретили родственники. Корпус, как я уже сказал - обломки древнего роутера. Сердце - Arduino Leonardo (хотел micro, pro micro, nano, esp8266, но все они оказались мертвыми, возможно в том месте где их держал соплеклей им не понравилось, а может быть они даже не проработали и 1 дня, хотя не помню чтоб они вообще работали). Мышца - невероятно мощная дребезжащая синяя сервомашинка на пластиковых шестернях - невероятный зверь.

При разработке проекта, сидя с паяльником и полусгоревшим, оставленным судьбой на вырезку пластика жалом, я решил сделать коробку со световой индикацией и тремя режимами (три устройства ввода которые были у меня), а именно:

1. Красные, знакомые всем, сенсорные кнопки

2. Энкодер на круглой плате

3. Ползунковый потенциометр (далее в моей терминологии слайдер)

После вырезки получилось то, что я даже постеснялся сфотографировать.

После мучений с пайкой ножек элементов и моих обрезков проводов, к которым не лип припой я поставил всё на свои места, залил суперклеем и вывел наружу три контакта под сервопривод. Получилось что-то подобное:

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

3. Схема

Собирать всё в моих кустарных условиях без схемы было невозможно, поэтому набросал вот это

4. Код

С кодом были сложности, так как первый ардуино проект - ответственнее и сложнее чем первый раз с девушкой, но как и во втором случае всё вышло комом. Я не знаю где, но уверен что этот код можно было написать в 10 раз компактнее и производительней, но как сумел так и написал, главное что работает без перебоев. Использовал библиотеку GyverEncoder - не знаю как здесь к ней относятся, но для меня - это золото ацтеков, невероятно удобно использовать, особенно с дабл кликами и быстрым вращением энкодера

#define CLK 4 //(S2)
#define DT 5 //(S1)
#include "GyverEncoder.h"
#include <Servo.h> //рекомендуется использовать другие библиотеки servo, так как эта ломает ШИМ на 9 и 10 пине если вы работаете НЕ на Arduino Mega
Servo myservo; 
Encoder enc1(CLK, DT);

int plusButton = 11; //Кнопка увеличения значения переменной a
int minusButton = 12; //Кнопка уменьшения значения переменной a
int SwitchButt = 13; //Физическая кнопка переключения режимов (В данном коде это кнопка энкодера), можно использовать функции библиотеки GyverEncoder.h и расширить функционал кнопки на ваше усмотрение, такие как isSingle() или isDouble()
int ServoPin = 3; //Сервопривод
int EncLED = 0; //Светодиод состояния
int ColourRP = 8; //Пины подключения анодов RGB-светодиода с общим катодом, при работе с ШИМ НЕ на Arduino Mega и использовании Servo.h 9 и 10 пины использовать не получится
int ColourGP = 9; //^
int ColourBP = 10;//|
bool plusB = 0; //переменная состояния кнопки +
bool minusB = 0; //переменная состояния кнопки -
int a = 90; //начальный угол a
int Mode = 0; //Переменная режима работы по умолчанию (0-2) 0-сенсорными кнопками, 1-энкодер, 2-Слайдер-потенциометр
int ModeLED = 5; //Дополнительная контрольная переменная для предотвращения бессмысленных прокрутов IF в строках 52-69. Указывать любое значение, переменная будет автоматически установлена на необходимое программе значение
int slideValue = 500; //Начальное значение инвертированной переменной положения слайдера. Не имеет смысла, но лучше поставить 500 для минимизации рывков сервопривода при включении
int ModeCount = 3; //Количество режимов (3 = режимы 0,1,2; 4 = режимы 0,1,2,3; и тд)
bool SliderMode = true; //Инвертирование ползункового потенциометра (Слайдера) - false-без инверсии, true-инверсия включена
bool EncoderMode = false; //Инвертирование направления вращения энкодера для изменения направления вращения. Также можно поменять значения местами в 1 и 2 строках 
bool SwitchButtInv = false; //Если кнопка SwitchButt при нажатии выдает сигнал 0-пишем false, если при нажатии выдаёт сигнал 1-пишем true
void setup() {
  
  ModeCount = ModeCount-1;
  myservo.attach(ServoPin);
  Serial.begin(9600);
  myservo.write(a);
  pinMode(plusButton, INPUT); //кнопки 4-Плюс, 2-Минус
  pinMode(minusButton, INPUT);
  pinMode(SwitchButt, INPUT_PULLUP); //Подтягиваем для избежания дребезга на кнопке. При использовании логических 1/0 сенсорных и тд кнопок можно оставить просто INPUT
  pinMode(EncLED, OUTPUT);
  pinMode(ColourRP, OUTPUT);
  pinMode(ColourGP, OUTPUT);
  pinMode(ColourBP, OUTPUT);
  digitalWrite(ColourRP, HIGH); //задаём высокий сигнал на аноды светодиодов для предотвращения беспорядочного включения всевозможных цветов
  digitalWrite(ColourGP, HIGH);
  digitalWrite(ColourBP, HIGH);
  digitalWrite(EncLED, HIGH);
  enc1.setType(TYPE2); //Тип энкодера. При некорректной работе энкодера поменять TYPE2 на TYPE1 и наоборот
}

void loop() {
  digitalRead(SwitchButt); //Считываем значения кнопки переключения режимов, можно добавить и сконфигурировать любое количество режимов
  if (digitalRead(SwitchButt) == SwitchButtInv && Mode < ModeCount) {  //При нажатой кнопке SwitchButt и режиме от 0 до 1 в оригинале или от 0 до (ModeCount-2) повышаем режим на 1
    Mode = Mode + 1;
    delay(200); //время убрать палец с кнопки, не влияет на скорость выполнения программы при отжатой кнопке
  }
  else if (digitalRead(SwitchButt) == SwitchButtInv && Mode == ModeCount) { //При нажатой кнопке SwitchButt и максимальном режиме перескакиваем на режим 0
    Mode = 0;
    delay(200); //время убрать палец с кнопки, не влияет на скорость выполнения программы при отжатой кнопке
  }

  if (Mode == 0 && ModeLED != Mode) { //Цветовые отображения режимов. Можно использовать analogWrite, на 9 и 10 пинах Леонардо это не сработало. Спасибо нашей любимой Servo.h, рекомендуется использовать другие пины для ШИМ RGB.
    digitalWrite(ColourRP, LOW); // При использовании RGB светодиода с общим АНОДОМ можно получить необходимый цвет указав только один выход как HIGH, а остальные указать как LOW
    digitalWrite(ColourGP, HIGH);
    digitalWrite(ColourBP, HIGH);
    ModeLED = Mode;
  }
  if (Mode == 1 && ModeLED != Mode) { //Алгоритм проверяет значения Mode и ModeLed, и если переменная ModeLED не равна Mode, прогоняет изменение цвета
    digitalWrite(ColourRP, HIGH); //После изменения цвета и смены ModeLED на необходимый, алгоритм игнорируется полностью до следующего расхождения в значениях Mode и ModeLED т.е до смены режима работы
    digitalWrite(ColourGP, LOW); 
    digitalWrite(ColourBP, HIGH);
    ModeLED = Mode;
  }
  if (Mode == 2 && ModeLED != Mode) { //Можно добавить множество вариантов светового отображения режимов работы при их количестве > 3 комбинируя цвета или используя analogWrite
    digitalWrite(ColourRP, HIGH);
    digitalWrite(ColourGP, HIGH);
    digitalWrite(ColourBP, LOW);
    ModeLED = Mode;
  }
  
  Serial.println(Mode); //Дебаг информация для проверки работы режимов
  if (Mode == 0) { //режим сенсорных кнопок + и -
    digitalRead(plusButton);
    if (digitalRead(plusButton) == 1) { //Если Нажата кнопка + и значение угла < 180 добавляем 2 градуса, отправляем на сервомашинку
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
      delay(60);
      if (a < 180) {
        a = a + 2;
      }
      myservo.write(a);
    }
    else if (digitalRead(minusButton) == 1) { //Если Нажата кнопка - и значение угла > 0 добавляем 2 градуса, отправляем на сервомашинку
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
      delay(60);
      if (a > 0) {
        a = a - 2;
        myservo.write(a);
      }
    }

  }

  if (Mode == 1) { //Режим управления энкодером. При вращении на 1 шаг переменная увеличивается/уменьшается на 1. Направление вращения настраивается переменной EncoderMode
    if(EncoderMode == 0){ //Инверсия отключена
    enc1.tick(); //Опрашиваем энкодер
    if (enc1.isRight() && a < 180) { //При повороте по часовой стрелке прибавляем +1 к переменной если она не равна 180
      a++;
      myservo.write(a);
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
    }
    else if (enc1.isLeft() && a > 0) { //При повороте против часовой стрелки вычитаем 1 от переменной если она не равна 0
      a--;
      myservo.write(a);
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
    }

  }
  
  else if(EncoderMode == 1){ //Инверсия включена
    enc1.tick(); //Опрашиваем энкодер
    if (enc1.isRight() && a > 0) { //При повороте по часовой стрелке вычитаем 1 от переменной если она не равна 0
      a = a - 1;
      myservo.write(a);
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
      delay(10);
    }
    if (enc1.isLeft() && a < 180) { //При повороте против часовой стрелки прибавляем +1 к переменной если она не равна 180
      a = a + 1;
      myservo.write(a);
      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
      delay(5);
      digitalWrite(EncLED, HIGH);
      delay(10);
    }

  }
  }
  if (Mode == 2) { //Режим слайдера
    analogRead(A5); //Считываем значение потенциометра
    if (SliderMode == 1) { //Инверсия включена
    slideValue = 1023 - analogRead(A5); //Инвертируем значение и записываем в переменную
    }
    else if (SliderMode == 0) { //Инверсия выключена
      slideValue = analogRead(A5); //оставляем значение как есть и записываем в переменную
    }
    Serial.println(slideValue); //Выводим дебаг информацию
    a=map(slideValue,0,1023,0,180); //Преобразуем значения 0-1023 в понятные сервоприводу 0-180
    myservo.write(a);
  }
  Serial.println(a);
 
}

Удивительно, но добавление любого 10мс delay для стабильности в конец или середину void loop приводит к полной дисфункции энкодера. Возможно кто-то знает с чем связано?

5. Итог

Получилось скомкано, возникали фантомные отвалы энкодера, которые решались перебором кода (сами по себе), ну а никто и не говорил что первый раз будет приятно, пришлось серьезно порвать заднее технологическое отверстие что-бы добиться желаемого результата - бесперебойной работы

b707
Offline
Зарегистрирован: 26.05.2017

Шедеврально.
Отправлено в 00.45, то есть ТС писал это под бой курантов, бросив жену и детей у праздничного стола.

Лучше б шампусика выпил:)

La1m1e
Offline
Зарегистрирован: 30.12.2021

b707 пишет:
Шедеврально. Отправлено в 00.45, то есть ТС писал это под бой курантов, бросив жену и детей у праздничного стола. Лучше б шампусика выпил:)

По моему часовому поясу это было 23:45, да и молод я ещё для жены, да и с мелкой сестрой не особо попразднуешь) 10 минут посидели и спать

La1m1e
Offline
Зарегистрирован: 30.12.2021

Спустя несколько попыток использования я сломал клей, крепивший качалку к оси фокусировочного механизма, теперь можно настроить фокус вручную, а сервомашинка всё ещё позволяет делать точную подгонку без вибраций, так мне даже больше нравится, так как ручной "черновой" фокус также важен