Электрическая фокусировочная схема для дешевого телескопа 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 - не знаю как здесь к ней относятся, но для меня - это золото ацтеков, невероятно удобно использовать, особенно с дабл кликами и быстрым вращением энкодера

001#define CLK 4 //(S2)
002#define DT 5 //(S1)
003#include "GyverEncoder.h"
004#include <Servo.h> //рекомендуется использовать другие библиотеки servo, так как эта ломает ШИМ на 9 и 10 пине если вы работаете НЕ на Arduino Mega
005Servo myservo;
006Encoder enc1(CLK, DT);
007 
008int plusButton = 11; //Кнопка увеличения значения переменной a
009int minusButton = 12; //Кнопка уменьшения значения переменной a
010int SwitchButt = 13; //Физическая кнопка переключения режимов (В данном коде это кнопка энкодера), можно использовать функции библиотеки GyverEncoder.h и расширить функционал кнопки на ваше усмотрение, такие как isSingle() или isDouble()
011int ServoPin = 3; //Сервопривод
012int EncLED = 0; //Светодиод состояния
013int ColourRP = 8; //Пины подключения анодов RGB-светодиода с общим катодом, при работе с ШИМ НЕ на Arduino Mega и использовании Servo.h 9 и 10 пины использовать не получится
014int ColourGP = 9; //^
015int ColourBP = 10;//|
016bool plusB = 0; //переменная состояния кнопки +
017bool minusB = 0; //переменная состояния кнопки -
018int a = 90; //начальный угол a
019int Mode = 0; //Переменная режима работы по умолчанию (0-2) 0-сенсорными кнопками, 1-энкодер, 2-Слайдер-потенциометр
020int ModeLED = 5; //Дополнительная контрольная переменная для предотвращения бессмысленных прокрутов IF в строках 52-69. Указывать любое значение, переменная будет автоматически установлена на необходимое программе значение
021int slideValue = 500; //Начальное значение инвертированной переменной положения слайдера. Не имеет смысла, но лучше поставить 500 для минимизации рывков сервопривода при включении
022int ModeCount = 3; //Количество режимов (3 = режимы 0,1,2; 4 = режимы 0,1,2,3; и тд)
023bool SliderMode = true; //Инвертирование ползункового потенциометра (Слайдера) - false-без инверсии, true-инверсия включена
024bool EncoderMode = false; //Инвертирование направления вращения энкодера для изменения направления вращения. Также можно поменять значения местами в 1 и 2 строках
025bool SwitchButtInv = false; //Если кнопка SwitchButt при нажатии выдает сигнал 0-пишем false, если при нажатии выдаёт сигнал 1-пишем true
026void setup() {
027   
028  ModeCount = ModeCount-1;
029  myservo.attach(ServoPin);
030  Serial.begin(9600);
031  myservo.write(a);
032  pinMode(plusButton, INPUT); //кнопки 4-Плюс, 2-Минус
033  pinMode(minusButton, INPUT);
034  pinMode(SwitchButt, INPUT_PULLUP); //Подтягиваем для избежания дребезга на кнопке. При использовании логических 1/0 сенсорных и тд кнопок можно оставить просто INPUT
035  pinMode(EncLED, OUTPUT);
036  pinMode(ColourRP, OUTPUT);
037  pinMode(ColourGP, OUTPUT);
038  pinMode(ColourBP, OUTPUT);
039  digitalWrite(ColourRP, HIGH); //задаём высокий сигнал на аноды светодиодов для предотвращения беспорядочного включения всевозможных цветов
040  digitalWrite(ColourGP, HIGH);
041  digitalWrite(ColourBP, HIGH);
042  digitalWrite(EncLED, HIGH);
043  enc1.setType(TYPE2); //Тип энкодера. При некорректной работе энкодера поменять TYPE2 на TYPE1 и наоборот
044}
045 
046void loop() {
047  digitalRead(SwitchButt); //Считываем значения кнопки переключения режимов, можно добавить и сконфигурировать любое количество режимов
048  if (digitalRead(SwitchButt) == SwitchButtInv && Mode < ModeCount) {  //При нажатой кнопке SwitchButt и режиме от 0 до 1 в оригинале или от 0 до (ModeCount-2) повышаем режим на 1
049    Mode = Mode + 1;
050    delay(200); //время убрать палец с кнопки, не влияет на скорость выполнения программы при отжатой кнопке
051  }
052  else if (digitalRead(SwitchButt) == SwitchButtInv && Mode == ModeCount) { //При нажатой кнопке SwitchButt и максимальном режиме перескакиваем на режим 0
053    Mode = 0;
054    delay(200); //время убрать палец с кнопки, не влияет на скорость выполнения программы при отжатой кнопке
055  }
056 
057  if (Mode == 0 && ModeLED != Mode) { //Цветовые отображения режимов. Можно использовать analogWrite, на 9 и 10 пинах Леонардо это не сработало. Спасибо нашей любимой Servo.h, рекомендуется использовать другие пины для ШИМ RGB.
058    digitalWrite(ColourRP, LOW); // При использовании RGB светодиода с общим АНОДОМ можно получить необходимый цвет указав только один выход как HIGH, а остальные указать как LOW
059    digitalWrite(ColourGP, HIGH);
060    digitalWrite(ColourBP, HIGH);
061    ModeLED = Mode;
062  }
063  if (Mode == 1 && ModeLED != Mode) { //Алгоритм проверяет значения Mode и ModeLed, и если переменная ModeLED не равна Mode, прогоняет изменение цвета
064    digitalWrite(ColourRP, HIGH); //После изменения цвета и смены ModeLED на необходимый, алгоритм игнорируется полностью до следующего расхождения в значениях Mode и ModeLED т.е до смены режима работы
065    digitalWrite(ColourGP, LOW);
066    digitalWrite(ColourBP, HIGH);
067    ModeLED = Mode;
068  }
069  if (Mode == 2 && ModeLED != Mode) { //Можно добавить множество вариантов светового отображения режимов работы при их количестве > 3 комбинируя цвета или используя analogWrite
070    digitalWrite(ColourRP, HIGH);
071    digitalWrite(ColourGP, HIGH);
072    digitalWrite(ColourBP, LOW);
073    ModeLED = Mode;
074  }
075   
076  Serial.println(Mode); //Дебаг информация для проверки работы режимов
077  if (Mode == 0) { //режим сенсорных кнопок + и -
078    digitalRead(plusButton);
079    if (digitalRead(plusButton) == 1) { //Если Нажата кнопка + и значение угла < 180 добавляем 2 градуса, отправляем на сервомашинку
080      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
081      delay(5);
082      digitalWrite(EncLED, HIGH);
083      delay(60);
084      if (a < 180) {
085        a = a + 2;
086      }
087      myservo.write(a);
088    }
089    else if (digitalRead(minusButton) == 1) { //Если Нажата кнопка - и значение угла > 0 добавляем 2 градуса, отправляем на сервомашинку
090      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
091      delay(5);
092      digitalWrite(EncLED, HIGH);
093      delay(60);
094      if (a > 0) {
095        a = a - 2;
096        myservo.write(a);
097      }
098    }
099 
100  }
101 
102  if (Mode == 1) { //Режим управления энкодером. При вращении на 1 шаг переменная увеличивается/уменьшается на 1. Направление вращения настраивается переменной EncoderMode
103    if(EncoderMode == 0){ //Инверсия отключена
104    enc1.tick(); //Опрашиваем энкодер
105    if (enc1.isRight() && a < 180) { //При повороте по часовой стрелке прибавляем +1 к переменной если она не равна 180
106      a++;
107      myservo.write(a);
108      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
109      delay(5);
110      digitalWrite(EncLED, HIGH);
111    }
112    else if (enc1.isLeft() && a > 0) { //При повороте против часовой стрелки вычитаем 1 от переменной если она не равна 0
113      a--;
114      myservo.write(a);
115      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
116      delay(5);
117      digitalWrite(EncLED, HIGH);
118    }
119 
120  }
121   
122  else if(EncoderMode == 1){ //Инверсия включена
123    enc1.tick(); //Опрашиваем энкодер
124    if (enc1.isRight() && a > 0) { //При повороте по часовой стрелке вычитаем 1 от переменной если она не равна 0
125      a = a - 1;
126      myservo.write(a);
127      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
128      delay(5);
129      digitalWrite(EncLED, HIGH);
130      delay(10);
131    }
132    if (enc1.isLeft() && a < 180) { //При повороте против часовой стрелки прибавляем +1 к переменной если она не равна 180
133      a = a + 1;
134      myservo.write(a);
135      digitalWrite(EncLED, LOW); //Мигаем светодиодом состояния
136      delay(5);
137      digitalWrite(EncLED, HIGH);
138      delay(10);
139    }
140 
141  }
142  }
143  if (Mode == 2) { //Режим слайдера
144    analogRead(A5); //Считываем значение потенциометра
145    if (SliderMode == 1) { //Инверсия включена
146    slideValue = 1023 - analogRead(A5); //Инвертируем значение и записываем в переменную
147    }
148    else if (SliderMode == 0) { //Инверсия выключена
149      slideValue = analogRead(A5); //оставляем значение как есть и записываем в переменную
150    }
151    Serial.println(slideValue); //Выводим дебаг информацию
152    a=map(slideValue,0,1023,0,180); //Преобразуем значения 0-1023 в понятные сервоприводу 0-180
153    myservo.write(a);
154  }
155  Serial.println(a);
156  
157}

Удивительно, но добавление любого 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

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