Вход

Просмотр полной версии : Система перемещения монитора


skanch
08.02.2015, 00:46
Хочу поделиться одним из вариантов изготовления СИСТЕМЫ ПЕРЕМЕЩЕНИЯ (https://youtu.be/4mXBo98DKAo) 39591 (https://youtu.be/97YyrZYBzcA) монитора в машине. Сразу скажу- не бюджетно. Цель - попытаться сделать достаточно надежную и качественную систему. В варианте, который буду описывать, использована реечная передача для перемещения каретки и коническая передача для подъема монитора в вертикальное положение. Компоненты системы: рейка (http://www.pccar.ru/attachment.php?attachmentid=38513&stc=1&d=1423339217) модуль 1. Шестерни пока еще нет- где-то в пути. Конические шестерни (http://www.pccar.ru/attachment.php?attachmentid=38514&stc=1&d=1423339292) . Сервомашинка SM-S4315R (http://www.pccar.ru/attachment.php?attachmentid=38515&stc=1&d=1423339368) непрерывного вращения для перемещения каретки по горизонтали. Сервомашинка SM-S8166M (http://www.pccar.ru/attachment.php?attachmentid=38516&stc=1&d=1423339433) для подъема монитора.
Линейные подшипники серии MGN 15.
Контроллер Arduino Nano. DC_DC преобразователи (http://www.pccar.ru/attachment.php?attachmentid=38518&stc=1&d=1423339780) для питания сервомашинок.
Оптические прерыватели (http://www.pccar.ru/attachment.php?attachmentid=38519&stc=1&d=1423339831) (концевики). Вся конструкция выполнена из алюминиевого профиля.
Для начала сделаем основу-раму. Размеры всех заготовок и деталей должны быть максимально точны. Сотки миллиметров можно игнорировать, даже десятки можно не брать в расчет, но в миллиметрах все должно быть точно. Итак делаем раму. Используем тяговые заклепки. Углы проверяем- 90° (http://www.pccar.ru/attachment.php?attachmentid=38520&stc=1&d=1423340073) обязательное условие. Крепим линейные подшипники (http://www.pccar.ru/attachment.php?attachmentid=38521&stc=1&d=1423340170). Я использовал заклепки - гайки из алюминия для снижения веса. Но крайние крепления (http://www.pccar.ru/attachment.php?attachmentid=38533&stc=1&d=1423341855) направляющих подшипника сделал на соединении винт-гайка (http://www.pccar.ru/attachment.php?attachmentid=38522&stc=1&d=1423340298) для большей надежности. Все резьбовые соединения ставлю на вот такой фиксатор (http://www.pccar.ru/attachment.php?attachmentid=38523&stc=1&d=1423340389) - защита от вибрации и все такое... Ставим одну коническую шестерню на большую серву (http://www.pccar.ru/attachment.php?attachmentid=38524&stc=1&d=1423340441). Использую все тот же фиксатор для резьбы. Делаем каретку (http://www.pccar.ru/attachment.php?attachmentid=38525&stc=1&d=1423340736). Уголок из алюминия использовал толщиной 3 мм. Он должен нести основную нагрузку. Делаем разметку под большую серву и боковые кронштейны. Боковые кронштейны (http://www.pccar.ru/attachment.php?attachmentid=38526&stc=1&d=1423340827) сделал по такому принципу: в прямоугольную трубу 30х15х1.5 мм вставил квадрат 12х12 мм и все обжал винтами. Весь алюминий, который использую в работе конструкционный и размеры ГОСТ-овские, поэтому можно подобрать все по размеру. Итак внутренний размер прямоугольной трубы идеально совпал с наружным размером квадрата. Высверливаем отверстия под радиальные миниатюрные подшипники (http://www.pccar.ru/attachment.php?attachmentid=38527&stc=1&d=1423340910). Здесь я использую такие размером 6 x 10 x 3 мм.
Хочу обратить внимание на такой момент-сначала сверлим глухое отверстие Ø6 и глубиной не более 10 мм. Затем расширяем отверстие до Ø10 и глубиной max 5 мм. Объясню для чего это нужно. У подшипника, который я использую есть реборда-она не даст ему провалиться в отверстие и в дальнейшем позволит удобно зафиксировать. А в углубление Ø6 кладем шарик (http://www.pccar.ru/attachment.php?attachmentid=38529&stc=1&d=1423341111) от подшипника Ø 5-5,5 мм для того, чтобы в дальнейшем наша ось не «клинила», упираясь торцом. Теперь изготовим саму площадку для монитора. Хочу добавить, что описанный вариант делается под планшет размером 190х112х10. Прикинув размеры вырезал такой «подиум» (http://www.pccar.ru/attachment.php?attachmentid=38530&stc=1&d=1423341270). «Ноги» (http://www.pccar.ru/attachment.php?attachmentid=38531&stc=1&d=1423341339)сделаны по принципу вышеописанных кронштейнов. Ось из латунного прутка Ø6 мм. «Ноги» прикручены и приклеены намертво вот таким клеем (http://www.pccar.ru/attachment.php?attachmentid=38532&stc=1&d=1423341479). Оказался очень достойный клей . Удобно работать. Сразу не «встает». После отверждения становиться очень прочным.

skanch
08.02.2015, 01:01
Примерил (http://www.pccar.ru/attachment.php?attachmentid=38536&stc=1&d=1423343178) "узел (http://www.pccar.ru/attachment.php?attachmentid=38536&stc=1&d=1423343178)"

skanch
08.02.2015, 02:36
Так выглядит первый вариант каретки (http://www.pccar.ru/attachment.php?attachmentid=38539&stc=1&d=1423348489) с "навеской".

skanch
08.02.2015, 02:46
Чтобы закрыть узел с шестеренками была изготовлена такая деталь (http://www.pccar.ru/attachment.php?attachmentid=38541&stc=1&d=1423348813).
Сделал ее (http://www.pccar.ru/attachment.php?attachmentid=38542&stc=1&d=1423348927)из трубы и двух уголков. Сначала приклеил клеем, а потом залил полости эпоксидкой. Затем вырезал (http://www.pccar.ru/attachment.php?attachmentid=38543&stc=1&d=1423349086) все лишнее и получил такое (http://www.pccar.ru/attachment.php?attachmentid=38544&stc=1&d=1423349162).

skanch
08.02.2015, 02:53
Напрягают эти зияющие дыры (http://www.pccar.ru/attachment.php?attachmentid=38546&stc=1&d=1423349559).

skanch
08.02.2015, 10:53
Сделал вставки (http://www.pccar.ru/attachment.php?attachmentid=38551&stc=1&d=1423378275).
Стало получше. После полной покраски думаю будет выглядеть хорошо.

skanch
08.02.2015, 22:38
Очередная примерка.

http://www.pccar.ru/attachment.php?attachmentid=38644&stc=1&d=1423506867

http://www.pccar.ru/attachment.php?attachmentid=38645&stc=1&d=1423506910

http://www.pccar.ru/attachment.php?attachmentid=38646&stc=1&d=1423506915

http://www.pccar.ru/attachment.php?attachmentid=38647&stc=1&d=1423506919

skanch
09.02.2015, 18:22
Продолжаем процесс. Разметил и вырезал посадочное место под серву горизонтального перемещения.
http://www.pccar.ru/attachment.php?attachmentid=38665&stc=1&d=1423509561
http://www.pccar.ru/attachment.php?attachmentid=38666&stc=1&d=1423509568

Закрепить пока нельзя- жду зубчатую шестерню.

Решил установить оптические прерыватели (концевики). Из-за не хватки места выбрал другие-меньшего размера.


http://www.pccar.ru/attachment.php?attachmentid=38667&stc=1&d=1423509625

Место для установки нашлось только одно.

http://www.pccar.ru/attachment.php?attachmentid=38668&stc=1&d=1423509658
Поскольку отверстие под крепление только одно и нужно исключить смещение- сделал вот такие штуки.
http://www.pccar.ru/attachment.php?attachmentid=38669&stc=1&d=1423509689
http://www.pccar.ru/attachment.php?attachmentid=38670&stc=1&d=1423509695
http://www.pccar.ru/attachment.php?attachmentid=38671&stc=1&d=1423509701
http://www.pccar.ru/attachment.php?attachmentid=38672&stc=1&d=1423509713
Одной стороной плата прижата к рейке, а вторую сторону фиксирует борт этого, если можно назвать -короба. Еще и функции диэлектрика. Но на всякий случай поставил изоляторы.

http://www.pccar.ru/attachment.php?attachmentid=38673&stc=1&d=1423509803


Прерыватель луча сделал из подходящей по размеру стойки для печатных плат.

http://www.pccar.ru/attachment.php?attachmentid=38674&stc=1&d=1423509836
http://www.pccar.ru/attachment.php?attachmentid=38675&stc=1&d=1423509842
http://www.pccar.ru/attachment.php?attachmentid=38676&stc=1&d=1423509851

skanch
09.02.2015, 21:30
Вот схемка оптического прерывателя, который я установил. В отличии от большего по габаритам-этот модуль имеет выводы, как высокого уровня, так и низкого. Может кому пригодится.

http://www.pccar.ru/attachment.php?attachmentid=38664&stc=1&d=1423509489

skanch
09.02.2015, 22:58
сколько приблизительно нужно оборотов в минуту на горизонталь,так средне.
У меня серва крутит примерно 60 об.мин.. Каретка проходит расстояние в 13 см. примерно за 3,5 оборота вала. Но все зависит от количества зубьев на шестерне. У меня пара Модуль 1. Шестерня 12 зубов. Расчет такой 3,1415Х12=37,698
130мм/37,698=3,44 оборота.
Исправил. Тут (http://www.pccar.ru/attachment.php?attachmentid=38677&stc=1&d=1423513132) параметры шага.

skanch
15.02.2015, 21:54
Продолжаем сборку. Вчера получил шестерни (http://www.pccar.ru/attachment.php?attachmentid=38788&stc=1&d=1424019963).
Вал на серве диаметром 6 мм , а посадочный диаметр шестерни 5 мм- рассверлил до нужного размера и посадил (http://www.pccar.ru/attachment.php?attachmentid=38789&stc=1&d=1424020203) на супер клей, о котором упоминал выше. Сегодня обрезал лишнее и смонтировал (http://www.pccar.ru/attachment.php?attachmentid=38790&stc=1&d=1424021515) на каретку (http://www.pccar.ru/attachment.php?attachmentid=38791&stc=1&d=1424021596).
Серву установил через штатные резиновые втулки. Причем верхние крепления еще и с металлическими гильзами, которые шли в комплекте с сервомотором. На нижние ставить их не стал- серва (http://www.pccar.ru/attachment.php?attachmentid=38792&stc=1&d=1424021890) стала с небольшим наклоном в сторону зубчатой рейки. Это создает нужный прижим.
Вчера окончательно подогнал и собрал крышку для монитора-планшета (новая ось,опорный подшипник). Намертво приклеил (http://www.pccar.ru/attachment.php?attachmentid=38793&stc=1&d=1424022186)саму крышку к оси (http://www.pccar.ru/attachment.php?attachmentid=38794&stc=1&d=1424022233)-теперь узел этот не разборный. Осталось сделать замки крепления планшета, лицевую панель и все отдать в покраску.
Смонтировал электрическую (http://www.pccar.ru/attachment.php?attachmentid=38795&stc=1&d=1424022344) часть. Собрал по временной схеме питание сервомоторов, чтобы посмотреть в работе. Вот ролик (https://yadi.sk/i/P2gGcac8egwrm) работы механизма.
http://www.pccar.ru/attachment.php?attachmentid=38800&stc=1&d=1424030475 (http://youtu.be/0GhfixFmAWQ)

skanch
16.02.2015, 22:33
Красиво!Серьезный подход!
P.S. Не доверяю я этим моментальным клеям–отвалятся со временем. Эпоксидка еще куда ни шло...Штифт лучше/надежнее!:)

На фото видно, что и винт прижимной присутствует, и супер клей (http://www.art-object.ru/?razdel_saita=cat&category=4&pos=23)-это EPOXY metal (http://www.pccar.ru/attachment.php?attachmentid=38532&stc=1&d=1423341479), проверенный в работе.

skanch
19.02.2015, 22:15
Чтобы сервомоторы не дергались в момент подачи питания, а такое встречается очень часто и мой случай не исключение, использовал готовый IRF520 MOSFET (http://www.pccar.ru/attachment.php?attachmentid=38869&stc=1&d=1424368741)-модуль для Arduino. Немного его подправил (http://www.pccar.ru/attachment.php?attachmentid=38870&stc=1&d=1424368833) для экономии (http://www.pccar.ru/attachment.php?attachmentid=38871&stc=1&d=1424370508) места. Управление модулем (http://www.pccar.ru/attachment.php?attachmentid=38896&stc=1&d=1424424466) через ШИМ. Плавное включение питания полностью решило проблему "дергания" сервоприводов. Обязательное условие- плавно включать нужно то питание, которое идет после DC-DC преобразователя (http://www.pccar.ru/attachment.php?attachmentid=38518&stc=1&d=1423339780). Мои сервы питаются 6,5 V.

skanch
21.02.2015, 00:50
Делаем кабель-канал (http://www.pccar.ru/attachment.php?attachmentid=38899&stc=1&d=1424463952) для прокладки проводов от электрооборудования, установленного на каретке (сервы, модуль MOSFET, DC-DC преобразователь, а также для вывода с планшета необходимых проводов). Для этой цели я использую гибкую пружину-трубогиб с наружным диаметром 12 мм. Больший диаметр менее гибок. Пружина имеет антикоррозийное покрытие.
Один конец пружины крепим на каркасе (http://www.pccar.ru/attachment.php?attachmentid=38901&stc=1&d=1424463972) с линейными направляющими, второй на самой каретке (http://www.pccar.ru/attachment.php?attachmentid=38904&stc=1&d=1424463998).
Провода внутри пружины нужно скрутить (http://www.pccar.ru/attachment.php?attachmentid=38902&stc=1&d=1424463981) в сторону изгиба кабель-канала, для того, чтобы создать дополнительную разгрузку жгута при изгибании пружины и максимально исключить продольное движение проводов внутри. Когда все соберу-будет выглядеть примерно так (http://www.pccar.ru/attachment.php?attachmentid=38905&stc=1&d=1424464004).

skanch
01.03.2015, 16:05
Как, окончательный результат не созрел?

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

skanch
15.03.2015, 14:16
Готовый вариант системы.

skanch
15.03.2015, 14:21
Здесь небольшое видео:
https://youtu.be/97YyrZYBzcA
97YyrZYBzcA

skanch
06.04.2015, 16:30
...новый проект делаем?

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

#include <Servo.h>
#include <EEPROM.h>

int value = 0; // переменная для хранения значения ШИМ ( модуль MOSFET управления питанием сервомоторов)
int Mosfet1 = 11; // контакт, к которому подключен модуль MOSFET управления питанием сервомоторов

int pos = 0;
// Создадим класс управления серво-приводом горизонтального перемещения
Servo Horizontal_Motor; // Класс управления серво-приводом горизонтального перемещения
int HM_Pin = 10; // Контакт, к которому подключен серво-привод горизонтального перемещения

// Создадим класс управления серво-приводом вертикального перемещения
Servo Vertical_Motor; // Класс управления серво-приводом вертикального перемещения
int VM_Pin = 9; // Контакт, к которому подключен серво-привод вертикального перемещения
int Mosfet2 = 14; // Контакт, к которому подключен MOSFET управления питанием планшета
int VM_Max_Angle_Position = 95; // Максимальный угол открытия монитора
int VM_Min_Angle_Position = 0; // Минимальный угол открытия монитора
long VM_Timer = 0; // Задержка перед сменой направления
int VM_Working_Mode = 0; // Режим работы вертикального привода: 0 - постоянное кручение, 1 - поправка

// Команды для серво-приводов
int Servo_Stop_Command = 90; // Команда остановки серво-привода
int Servo_Close_Command = 0; // Команда закрытия серво-привода (движение каретки назад)
int Servo_Open_Command = 180; // Команда открытия серво-привода (движение каретки вперед)


// Оптические датчики
int Opt_Sensor_Fwd_Ctrl_Pin = 7; // Оптический прерыватель «вперед» управляющий PIN7, питание PIN8
int Opt_Sensor_Fwd_ACC_Pin = 8; // Оптический прерыватель «вперед» управляющий PIN7, питание PIN8
int Opt_Sensor_Bwd_Ctrl_Pin = 5; // Оптический прерыватель «назад» управляющий PIN5, питание PIN6
int Opt_Sensor_Bwd_ACC_Pin = 6; // Оптический прерыватель «назад» управляющий PIN5, питание PIN6

// Диагностический светодиод
int Led_Pin = 13; // Контакт, к которому подключен диагностический светодиод

// Кнопки управления системой
int Btn_Open_Close_Pin = 2; // Контакт, к которому подключена кнопка управления открытия/закрытия монитора
int Btn_Adjust_Position_Pin = 3; // Контакт, к которому подключена кнопка управления настройкой вертикальной позиции монитора

// Переменные для хранения состояния кнопкок управления системой
int Btn_Open_Close_State; // Переменная состояния кнопки управления открытия/закрытия монитора
int Btn_Adjust_Position_State; // Переменная состояния кнопки управления настройкой вертикальной позиции монитора
int Btn_Adjust_Position_Course; // Переменная, в которой хранится вертикальное направление движения позиции монитора
long Btn_Open_Close_Last_Time; // Переменная, в которой хранится последнее время мажатия кнопки управления открытия/закрытия монитора
long Btn_Adjust_Position_Last_Time; // Переменная, в которой хранится последнее время мажатия кнопки управления настройкой вертикальной позиции монитора

// Значения для обработки кнопок
int Btn_Pressed = LOW;
int Btn_Released = HIGH;
int Btn_Direction_Up = 0;
int Btn_Direction_Down = 1;
long Btn_Open_Close_Debounce = 200; // Временная константа дребезга клавиши (миллисекунды) открытия/закрытия
long Btn_Adjust_Debounce = 8; // Временная константа дребезга клавиши (миллисекунды) угла наклона монитора
long Btn_Adjust_Debounce_Sleep = 7; // Задержка перед обработкой клавиши угла....


// Сохранение состояния системы в EEPROM
int HM_State_Offset = 0;
int VM_State_Offset = 4;
int VM_Working_Angle_Offset = 8;
int VM_Temp_Angle_Offset = 16;
long Check_Sum_Offset = 32;

// Значения состояния системы
int SM_Opened_State = 0;
int SM_Opening_State = 1;
int SM_Closing_State = 2;
int SM_Closed_State = 3;

// Переменные хранения состояния системы
int HM_State; // Переменная хранения текущего состояния горизонтального серво-привода
int VM_State; // Переменная хранения текущего состояния вертикального серво-привода
int VM_Working_Angle_Position; // Переменная хранения рабочей позиции монитора
int VM_Temp_Angle_Position; // Переменная для хранения угла монитора при открывании/складывании
long CheckSum;




void setup()
{
// !!! Наверное надо проверять на запуск с зажатой кнопкой "Открыть"
// !!! и при таком состоянии нам пользователь сообщает, что
// !!! система закрыта и необходимо просто обновить ее состояние в EEPROM


// Подаем питание на модуль MOSFET управления питанием сервомоторов
for(value = 0 ; value <= 255; value+=5) // напряжение постепенно увеличивается (от 0V до 5V)
{
analogWrite(Mosfet1, value);
delay(5); // ждём 5 миллисекунд (время подбираем опытным путем)
// Сконфигурируем контакт питания модуля MOSFET управления питанием планшета
pinMode(Mosfet2, OUTPUT);
}


// Отладка
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}


//----------------------//
// Настроим всю систему //
//----------------------//

// Обнулим переменную, в которой хранится последнее время мажатия кнопки управления открытия/закрытия монитора
Btn_Open_Close_Last_Time = 0;
// Обнулим переменную, в которой хранится последнее время мажатия кнопки управления настройкой вертикальной позиции монитора
Btn_Adjust_Position_Last_Time = 0;

// Установим переменную, в которой хранится вертикальное направление движения позиции монитора на движение "вниз"
Btn_Adjust_Position_Course = Btn_Direction_Down;

// Сконфигурируем контакт кнопки управления открытием/закрытием как "Вход" и подключим к контакту внутренний резистор
pinMode(Btn_Open_Close_Pin, INPUT);

// Сконфигурируем контакт кнопки управления настройкой вертикальной позиции монитора как "Вход" и подключим к контакту внутренний резистор
pinMode(Btn_Adjust_Position_Pin, INPUT);


// Сконфигурируем контакт диагностического светодиода как "Выход" (будем зажигать/гасить)
//pinMode(Led_Pin, OUTPUT);

// Подключим контакт управления серво-приводом горизонтального перемещения
Horizontal_Motor.attach(HM_Pin);

// Остановим и удержим серво-привод горизонтального перемещения в положении "Стоп"
Horizontal_Motor.write(Servo_Stop_Command);






// Инициализируем оптические датчики
pinMode(Opt_Sensor_Fwd_Ctrl_Pin, INPUT);
pinMode(Opt_Sensor_Fwd_ACC_Pin, OUTPUT);

pinMode(Opt_Sensor_Bwd_Ctrl_Pin, INPUT);
pinMode(Opt_Sensor_Bwd_ACC_Pin, OUTPUT);

// Подадим питание на оптические датчики
//digitalWrite(Opt_Sensor_Fwd_ACC_Pin, HIGH);
//digitalWrite(Opt_Sensor_Bwd_ACC_Pin, HIGH);


//---------------------------------------//
// Проверим предыдущее состояние системы //
//---------------------------------------//

// Считаем предыдущее состояние системы
HM_State = EEPROM.read(HM_State_Offset);
VM_State = EEPROM.read(VM_State_Offset);
VM_Working_Angle_Position = EEPROM.read(VM_Working_Angle_Offset);
VM_Temp_Angle_Position = EEPROM.read(VM_Temp_Angle_Offset);

// Проверим угол наклона монитора на максимальный и минимальный
if (VM_Working_Angle_Position > VM_Max_Angle_Position | VM_Working_Angle_Position < 0) {
VM_Working_Angle_Position = VM_Max_Angle_Position;

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Working_Angle_Offset, VM_Working_Angle_Position);
}

// Считаем контрольную сумму из EEPROM
CheckSum = EEPROM.read(Check_Sum_Offset);

// Проверим контрольную сумму - совпала и состояние серво-приводов = SM_Closed_State легко продолжаем работу
if ( (CheckSum == (HM_State * 256) + VM_State) & (HM_State == SM_Closed_State) & (VM_State == SM_Closed_State) ) {
return;
}

//--------------------------------------------------------------//
// Надо сначала все механизмы привести в стартовое состояние //
//--------------------------------------------------------------//


delay(2000);

Serial.print("VM_Temp_Angle_Position");
Serial.print("\t = \t");
Serial.print(VM_Temp_Angle_Position, DEC);
Serial.println();


if (VM_Temp_Angle_Position > 0) {

// Выпрямим монитор с сохраненной временной позиции до 0
VM_Working_Angle_Position = VM_Temp_Angle_Position;
Start_Vertical_Motor(Servo_Close_Command);
} else {

// Выпрямим монитор для страховки в 0
Vertical_Motor.write(0);
}
// Теперь сохраним правильное значение временной позиции
VM_Temp_Angle_Position = 0;
EEPROM.write(VM_Temp_Angle_Offset, VM_Temp_Angle_Position);

// Считаем реальное рабочее положение монитора
VM_Working_Angle_Position = EEPROM.read(VM_Working_Angle_Offset);

// Сохраним вертикальное положение монитора в EEPROM
VM_State = SM_Closed_State;
EEPROM.write(VM_State_Offset, SM_Closed_State);

// Затем затянем его обратно
Start_Horizontal_Motor(Servo_Close_Command, 10000);

// Теперь сохраним состояние системы в "хорошем" состоянии
HM_State = SM_Closed_State;

// Сохраним положение монитора в EEPROM
EEPROM.write(HM_State_Offset, HM_State);

// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);
}


//
// Поворот на один градус вертикального привода в зависимсоти от переменной Btn_Adjust_Position_Course
//
void VM_Move()
{
// Проверим переменную, в которой хранится вертикальное направление движения позиции монитора
if (Btn_Adjust_Position_Course == Btn_Direction_Down) {


Serial.print("Direction = DOWN. Angle ");
Serial.print("\t = \t");
Serial.print(VM_Working_Angle_Position, DEC);
Serial.println();

// Теперь сохраним состояние системы в "не очень хорошем" состоянии
VM_State = SM_Closing_State;
// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);

//
// Необходимо наклонить монитор на один градус "вниз"
//

// Проверим на достижение "критического угла наклона"
if (VM_Working_Angle_Position == VM_Min_Angle_Position) {
// Угу. Встали в крайнюю позицию. Надо начинать движение "вверх".
Btn_Adjust_Position_Course = Btn_Direction_Up;
return;

} else {
// Нам еще есть куда двигаться "вниз" - значит подвинемся
VM_Working_Angle_Position = VM_Working_Angle_Position - 1;

// Теперь надо сам монитор выставить на нужный угол
Vertical_Motor.write(VM_Working_Angle_Position);

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Working_Angle_Offset, VM_Working_Angle_Position);
EEPROM.write(VM_Temp_Angle_Offset, VM_Working_Angle_Position);

}
} else {

Serial.print("Direction = UP. Angle = ");
Serial.print("\t = \t");
Serial.print(VM_Working_Angle_Position, DEC);
Serial.println();

// Теперь сохраним состояние системы в "не очень хорошем" состоянии
VM_State = SM_Opening_State;
// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);

//
// Необходимо поднять монитор на один градус "вверх"
//

// Проверим на достижение "критического угла наклона"
if (VM_Working_Angle_Position == VM_Max_Angle_Position) {
// Угу. Встали в крайнюю позицию. Надо начинать движение "вниз".
Btn_Adjust_Position_Course = Btn_Direction_Down;
return;

} else {
// Нам еще есть куда двигаться "вверх" - значит подвинемся
VM_Working_Angle_Position = VM_Working_Angle_Position + 1;

// Теперь надо сам монитор выставить на нужный угол
Vertical_Motor.write(VM_Working_Angle_Position);

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Working_Angle_Offset, VM_Working_Angle_Position);
EEPROM.write(VM_Temp_Angle_Offset, VM_Working_Angle_Position);

}
}

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Working_Angle_Offset, VM_Working_Angle_Position);
EEPROM.write(VM_Temp_Angle_Offset, VM_Working_Angle_Position);
}


void loop()
{
// Проверим режим работы вертикального привода
if (VM_Working_Mode == 1) {
// Режим поправки
// Проверим на окончание времени действия режима поправки
if (millis() - VM_Timer > 1000) {
// Время вышло сменим режим и угол наклона
VM_Working_Mode = 0;

// Время закончилось. И нам надо сменить направление движения монитора
if (Btn_Adjust_Position_Course == Btn_Direction_Up) {
Btn_Adjust_Position_Course = Btn_Direction_Down;
} else {
Btn_Adjust_Position_Course = Btn_Direction_Up;
}
}
}




//
// Проверим на нажатие контрольных кнопок
//

// Сначала проверим на одновременное нажатие двух кнопок.
// Есть возможность одновременного нажатия двух кнопок - мы такое отсекаем.
if (digitalRead(Btn_Open_Close_Pin) == Btn_Pressed && digitalRead(Btn_Adjust_Position_Pin) == Btn_Pressed) {
// Нажаты одновременно две кнопки. Тупо запомним время их нажатия и ничего делать не будем
Btn_Open_Close_Last_Time = millis();
Btn_Adjust_Position_Last_Time = millis();
} else {

//
// Теперь проверим в каком состоянии находится система (открыта/закрыта)
//

if (HM_State == SM_Opened_State) {
// Система находится в открытом состоянии. Значит можно сделать два действия
// - закрыть монитор через кнопку Btn_Open_Close_Pin;
// - изменить угол наклона монитора через кнопку Btn_Adjust_Position_Pin

// Начнем проверять кнопки отдельно.

//
// Проверим текущее состояние кнопки Btn_Open_Close_Pin
//
Btn_Open_Close_State = digitalRead(Btn_Open_Close_Pin);

// Проверим на нажатие кнопки и исключим "дребезг" кнопки
if (Btn_Open_Close_State == Btn_Pressed && millis() - Btn_Open_Close_Last_Time > Btn_Open_Close_Debounce) {
// Запомним время нажатия кнопки
Btn_Open_Close_Last_Time = millis();

// Начнем действия по закрытию всей системы.

// Отправим команду вертикальному серво-приводу на движение "Вниз"
Start_Vertical_Motor(Servo_Close_Command);

// Отправим команду горизонтальному серво-приводу на движение "Назад"
Start_Horizontal_Motor(Servo_Close_Command, 10000);

return;
}


//
// Проверим текущее состояние кнопки Btn_Adjust_Position_Pin
// Надо учитывать, что при отпускании кнопки должно переключаться
// направление наклона монитора.
// Т.е. как только мы поняли, что кнопку нажали - заходим в цикл
// до отжатия кнопки и начинаем изменять угол монитора. Причем
// если угол наклона достиг критической точки (0 или VM_Max_Position)
// автоматически сменим направление!
//

//Проверим на нажатие и начнем цикл
Btn_Adjust_Position_State = digitalRead(Btn_Adjust_Position_Pin);

// Проверим на нажатие кнопки только для того, чтобы потом сменить направление движения
if (Btn_Adjust_Position_State == Btn_Pressed && millis() - Btn_Adjust_Position_Last_Time > Btn_Adjust_Debounce) {

// Подключим контакт управления серво-приводом вертикального перемещения
Vertical_Motor.attach(VM_Pin);


// Проверим режим работы вертикального привода
if (VM_Working_Mode == 1) {
// Режим поправки

Serial.print(" VM_Mode ");
Serial.print("\t = \t");
Serial.print(VM_Working_Mode, DEC);
Serial.println();

// Запомним время нажатия кнопки
Btn_Adjust_Position_Last_Time = millis();

// Время есть можно править угол
VM_Move();

// Начнем новый отсчет 3-х секунд
VM_Timer = millis();

// Сделаем задержку во избежание дребезга клавиш
delay(Btn_Adjust_Debounce_Sleep);

} else {
// Режим кручения

Serial.print(" VM_Mode ");
Serial.print("\t = \t");
Serial.print(VM_Working_Mode, DEC);
Serial.println();

// Проверим на нажатие кнопки и исключим "дребезг" кнопки
while (Btn_Adjust_Position_State == Btn_Pressed && millis() - Btn_Adjust_Position_Last_Time > Btn_Adjust_Debounce) {

// Запомним время нажатия кнопки
Btn_Adjust_Position_Last_Time = millis();

// И так... кнопка нажата - значит надо наклонить монитор на 1 градус в заданном направлении
VM_Move();

// Сделаем задержку во избежание дребезга клавиш
delay(Btn_Adjust_Debounce_Sleep);

// Снова считаем состояние кнопки
Btn_Adjust_Position_State = digitalRead(Btn_Adjust_Position_Pin);
}

// Цикл закончился. Значит кнопарь отпустили и нам надо дать задержку на 3 секунды для поправки угла монитора

// Начнем отсчет 3-х секунд
VM_Timer = millis();
VM_Working_Mode = 1;

}

// Теперь сохраним состояние системы в "не очень хорошем" состоянии
VM_State = SM_Opened_State;
// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);

// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);



// Отключим контакт управления серво-приводом вертикального перемещения, чтобы не жужжала бестолку
Vertical_Motor.detach();


}
} else {
// Система находится в закрытом состоянии. Ее можно только открыть через кнопку Btn_Open_Close_Pin

// Проверим текущее состояние кнопки Btn_Open_Close_Pin
Btn_Open_Close_State = digitalRead(Btn_Open_Close_Pin);

// Проверим на нажатие кнопки и исключим "дребезг" кнопки
if (Btn_Open_Close_State == Btn_Pressed && millis() - Btn_Open_Close_Last_Time > Btn_Open_Close_Debounce) {
// Запомним время нажатия кнопки
Btn_Open_Close_Last_Time = millis();

// Начнем действия по открытию всей системы.
// Подключим питание модуля MOSFET управления питанием планшета
digitalWrite(Mosfet2, HIGH);
// Отправим команду горизонтальному серво-приводу на движение "Вперед"
if (Start_Horizontal_Motor(Servo_Open_Command, 10000))

{
// Отправим команду вертикальному серво-приводу на движение "Вверх"
Start_Vertical_Motor(Servo_Open_Command);
}
}
}
}

delay(100);

}


bool Start_Horizontal_Motor(int HM_Direction, long MaxTimeOut)
{
int Sensor_Pin;
int Sensor_ACC;

// Теперь сохраним состояние системы
if (HM_Direction == Servo_Close_Command) {
// Теперь сохраним состояние системы в "хорошем" состоянии
HM_State = SM_Closing_State;
// Сохраним положение монитора в EEPROM
EEPROM.write(HM_State_Offset, HM_State);
// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);

HM_State = SM_Closed_State;
} else {
// Теперь сохраним состояние системы в "хорошем" состоянии
HM_State = SM_Opening_State;
// Сохраним положение монитора в EEPROM
EEPROM.write(HM_State_Offset, HM_State);
// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);

HM_State = SM_Opened_State;
}


// Выберем соответствующий контрольный датчик
if (HM_Direction == Servo_Close_Command) {
// Выберем ногу для контрольного датчика
Sensor_Pin = Opt_Sensor_Bwd_Ctrl_Pin;
Sensor_ACC = Opt_Sensor_Bwd_ACC_Pin;
} else {
// Выберем ногу для контрольного датчика
Sensor_Pin = Opt_Sensor_Fwd_Ctrl_Pin;
Sensor_ACC = Opt_Sensor_Fwd_ACC_Pin;
}
// Подадим питание на оптический датчик
digitalWrite(Sensor_ACC, HIGH);

// Задержка для сработки датчика, если стоим у края
delay(15);

// Проверим на наличие сигнала с оптического датчика
if (digitalRead(Sensor_Pin) == HIGH) {

// Снимем питание с оптического датчика
digitalWrite(Sensor_ACC, LOW);
return true;
}

// Теперь начнем горизонтальное движение серво-приводом
Horizontal_Motor.write(HM_Direction);

// Запомним время начала движения
long StartTime = millis();

// Начнем цикл ожидания сигнала от оптических датчиков или прервемся по таймауту
while (millis() <= StartTime + MaxTimeOut) {
// Проверим на наличие сигнала с оптического датчика
if (digitalRead(Sensor_Pin) == HIGH) {
// Сигнал пришел - тормознем серво-привод
Horizontal_Motor.write(Servo_Stop_Command);

// Теперь сохраним состояние системы в "хорошем" состоянии
// Сохраним положение монитора в EEPROM
EEPROM.write(HM_State_Offset, HM_State);
// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);

// Снимем питание с оптического датчика
digitalWrite(Sensor_ACC, LOW);

// Возвращаемся из функции с разрешением на дальнейшие действия
return true;
}

// Подождем 15 миллисекунд
delay(15);
}

// Тормознем серво-привод
Horizontal_Motor.write(Servo_Stop_Command);



// Снимем питание с оптического датчика
digitalWrite(Sensor_ACC, LOW);
return false;
}



void Start_Vertical_Motor(int VM_Direction)
{
int StartPos;

// Теперь сохраним состояние системы
if (VM_Direction == Servo_Close_Command) {
// Теперь сохраним состояние системы в "хорошем" состоянии
VM_State = SM_Closing_State;

// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);
// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);

VM_State = SM_Closed_State;
} else {
// Теперь сохраним состояние системы в "хорошем" состоянии
VM_State = SM_Opening_State;

// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);
// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);

VM_State = SM_Opened_State;
}

// Подключим контакт управления серво-приводом вертикального перемещения
Vertical_Motor.attach(VM_Pin);

delay(25);



Serial.print("Start_Vertical_Motor(");
if (VM_Direction == Servo_Close_Command) {
Serial.print("Servo_Close_Command)");
} else {
Serial.print("Servo_Open_Command)");
}
Serial.println();

Serial.print("VM_Working_Angle_Position\t = \t");
Serial.print(VM_Working_Angle_Position, DEC);
Serial.println();


// Проверим в каком направлении нам необходимо двигаться
if (VM_Direction == Servo_Close_Command)
{
// Проверка для избежания дерганья сервы
if (VM_Working_Angle_Position != 0 ) {

// Включим диагностический светодиод
//digitalWrite(Led_Pin, HIGH);

Serial.print("Close_Down!\t = \t");
Serial.print(VM_Working_Angle_Position, DEC);
Serial.println();

for (StartPos = VM_Working_Angle_Position; StartPos > 0; StartPos -= 3) {
Vertical_Motor.write(StartPos);
delay(15);

Serial.print("CurrentPos\t = \t");
Serial.print(StartPos, DEC);
Serial.println();

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Temp_Angle_Offset, StartPos);
}
}

Vertical_Motor.write(0);
delay(15);

// Отключим питание модуля MOSFET управления питанием планшета
digitalWrite(Mosfet2, LOW);

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Temp_Angle_Offset, 0);

} else {
delay(15);

// Проверка для избежания дерганья сервы
Serial.print("Open_Up\t = \t");
Serial.print(VM_Working_Angle_Position, DEC);
Serial.println();

if (VM_Working_Angle_Position != 0 ) {
for (StartPos = 1; StartPos < VM_Working_Angle_Position; StartPos += 3) {
Vertical_Motor.write(StartPos);
delay(15);

Serial.print("CurrentPos\t = \t");
Serial.print(StartPos, DEC);
Serial.println();

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Temp_Angle_Offset, StartPos);
}
}

Vertical_Motor.write(VM_Working_Angle_Position);
delay(15);

// Сохраним угол наклона монитора в EEPROM
EEPROM.write(VM_Temp_Angle_Offset, VM_Working_Angle_Position);
}

// Отключим контакт управления серво-приводом вертикального перемещения, чтобы не жужжала бестолку
Vertical_Motor.detach();



// Теперь сохраним состояние системы в "хорошем" состоянии
// Сохраним положение монитора в EEPROM
EEPROM.write(VM_State_Offset, VM_State);

// Пересчитаем контрольную сумму в EEPROM
EEPROM.write(Check_Sum_Offset, (HM_State * 256) + VM_State);
}

На мой взгляд-нормальная программа. Все работает, все шевелится...

skanch
11.10.2015, 13:04
[/URL]Вариант крепления планшета для системы перемещения. Возможно кому-нибудь будет интересно.
Требования к конструкции:съемный планшет (в данном случае Samsung Galaxy Tab S2),постоянная подзарядка планшета.
Реализовано с применением комплекта [URL="http://ru.aliexpress.com/item/High-Efficieny-3-Coils-Qi-Wireless-Charger-Transmitter-Mat-Charging-Pad-for-Nokia-Lumia-920-Nexus/32330902276.html"]беспроводной подзарядки (http://www.pccar.ru/attachment.php?attachmentid=41247&stc=1&d=1444553817), чехла для планшета (http://ru.aliexpress.com/item/For-tab-S2-8-0-smart-Case-ROCK-Touch-Series-Triple-Folding-Intelligent-Flip-PU-Case/32434826778.html), магнитов (http://ru.aliexpress.com/item/Hot-Magnet-360-Degrees-Mini-Holder-Magnetic-Car-Phone-Holder-Dashboard-Mobile-Mount-Car-Kit-Mobile/32392696888.html?spm=2114.03020208.3.29.081fL1&ws_ab_test=201556_1,201527_2_48_71_72_73_74_61_75, 201560_9) от держателя в авто.
Конструкция "подиума" (http://www.pccar.ru/attachment.php?attachmentid=38530&stc=1&d=1423341270) для планшета практически ничем не отличается от описанного выше. За исключением крепления самого планшета.
Вот фото такой конструкции.
В алюминиевой площадке просверлены отверстия под диаметр магнитов, которые приклеены на тыльной стороне пластикового "чехла" для планшета. Сзади к алюминиевой площадке приклеены полоски жести толщиной 0.8мм. К ним и "цепляются" магниты. Все держится хорошо и при надобности планшет вместе с "чехлом" можно легко снять.

skanch
09.12.2015, 22:45
Еще одна подобная система.

skanch
10.12.2015, 21:18
Это ролик https://youtu.be/waMT_I0s6vY
waMT_I0s6vY

skanch
11.12.2015, 02:29
Это "пациент".

skanch
08.02.2016, 21:43
При разработке механизма размера 1DIN столкнулся с проблемой подбора моторов для перемещения каретки и подъема монитора. Большинство не подходят по размерам - нужны приводы с габаритами, которые можно "вписать" в окно 34мм шириной. Еще немаловажный момент - усилие, которое развивает такой привод (мотор-редуктор). Если для перемещения по горизонтали достаточно 15 кг/см, то для подъема монитора необходимо уже не менее 30 кг/см и больше. Не так давно попались мне такие сервомоторы для роботов.
http://www.pccar.ru/attachment.php?attachmentid=42490&stc=1&d=1454963201
Технические характеристики:
Рабочее напряжение: 6.0~7.4в
Скорость работы: 0.18сек/60° / 0.16сек/60°
Макс. момент: 25.8кгс∙см /32.4кгс∙см
Ход: 0~280°
Размер: 43X32X32.5мм
Вес: 73г
Шлиц: 25T
Подшипник: 2 шарикоподшипника
Редуктор: металл
Длина кабеля: 50см
Отверстия крепления: 2.5x21.5мм
Частота работы: 1520мкс/333Hz, 900~2100мкс

Опробовал их на нескольких механизмах в узлах подъема монитора. Усилие с запасом, угол отрабатывают точно (для подъема нужен в пределах 0-110 градусов), ток при нагрузке и напряжении +/-7в не превышает 2,0А. Размер, вес и крепление - можно сказать идеальные.
Но для перемещения каретки по горизонтали нужен сервомотор с постоянным вращением, не ограниченный углом поворота (у этих 0-280 градусов). Решил немного переделать серву под свои "хотелки".

skanch
08.02.2016, 22:14
Разбираем мотор.

http://www.pccar.ru/attachment.php?attachmentid=42514&stc=1&d=1454963415

Выпаиваем драйвер и потенциометр ограничения угла поворота.Зачищаем место крепления потенциометра

http://www.pccar.ru/attachment.php?attachmentid=42515&stc=1&d=1454963443

Для управления мотором буду использовать драйвер TB6612FNG (http://www.dessy.ru/include/images/ware/pdf/r/rob_09457.pdf).

http://www.pccar.ru/attachment.php?attachmentid=42494&stc=1&d=1454954573

При своем размере имеет очень достойные параметры (http://arduinos.com.ua/driver-tb6612fng).

"Модуль драйвер на основании чипа TB6612FNG производства компании Toshiba. В отличие от наиболее распространенных на сегодняшний день драйверов на основе чипа L298N,L293D,LB1836M имеет ряд преимуществ таких как : минимальный размер, максимальный выход на канал до 3А, частота ШИМ 100 кГц, температурный контроль. Все это выделяет данный модуль драйвер TB6612FNG из всех имеющихся на сегодняшний день.

Характеристики:

- входное напряжение для двигателей от 4.5 до 13.5 Вольт DC;

- напряжение логики от 2.7 до 5.5 Вольт DC;

- максимальный ток на канал 3А (при длительном использовании рекомендуется установка радиатора), до 2А без радиатора;

- частота ШИМ 100 кГц ;

- встроенная тепловая схема отключения;

- фильтрующий конденсатор питания;

- защита от обратного тока;

- рабочая температура от (-20) до 80 градусов Цельсия;

Размер:20 x 17 мм.

Вес: до 20 гр."

Впаиваем "гребенку" с пинами.

http://www.pccar.ru/attachment.php?attachmentid=42495&stc=1&d=1454954654
http://www.pccar.ru/attachment.php?attachmentid=42530&stc=1&d=1455031795
http://www.pccar.ru/attachment.php?attachmentid=42531&stc=1&d=1455031795


Примерка в корпусе мотора.

http://www.pccar.ru/attachment.php?attachmentid=42518&stc=1&d=1454963694

Это с крышкой.

http://www.pccar.ru/attachment.php?attachmentid=42519&stc=1&d=1454963750

Остается припаять нужные провода и подключить к Ардуино. Ну это еще в процессе...

"Питаться" сервы будут от общеизвестных DC-DC преобразователей (http://www.ebay.com/itm/161270935218?_trksid=p2057872.m2749.l2648&ssPageName=STRK%3AMEBIDX%3AIT)

http://www.pccar.ru/attachment.php?attachmentid=42500&stc=1&d=1454955223

http://www.pccar.ru/attachment.php?attachmentid=42501&stc=1&d=1454955252

skanch
08.02.2016, 22:54
Это предварительная примерка на плате управления.

http://www.pccar.ru/attachment.php?attachmentid=42520&stc=1&d=1454963908
http://www.pccar.ru/attachment.php?attachmentid=42522&stc=1&d=1454964048
http://www.pccar.ru/attachment.php?attachmentid=42511&stc=1&d=1454957725
http://www.pccar.ru/attachment.php?attachmentid=42512&stc=1&d=1454957725

skanch
10.02.2016, 22:42
Заготовка для каретки.

http://www.pccar.ru/attachment.php?attachmentid=42555&stc=1&d=1455129611
http://www.pccar.ru/attachment.php?attachmentid=42556&stc=1&d=1455129611
http://www.pccar.ru/attachment.php?attachmentid=42557&stc=1&d=1455129611
http://www.pccar.ru/attachment.php?attachmentid=42558&stc=1&d=1455129668
http://www.pccar.ru/attachment.php?attachmentid=42559&stc=1&d=1455129668

skanch
06.03.2016, 11:42
неплохо было бы добавить библиотеку irremote...
Я совсем не программист. "Нажал-поехало-открыл" еще смогу написать. Все, что связано с Eeprom, прерываниями и прочим для меня сложно. Но по существу вопроса- есть вот такой скетч в свободном доступе. В шапке ссылка на первоисточник. Возможно это то, что нужно?
Скопировано без изменений.
/* v.01 Arduino servo IR EEPROM speed ИК пультом
****************************
урок от Дмитрия Осипова. http://www.youtube.com/user/d36073?feature=watch
v.01 Arduino servo IR EEPROM speed ИК пультом
Version 0.1-2013/08/19
-----------------------------
изменения; в Version 0.1-2013/
1.
2.
------------------------------
идеология;
управление двумя servo любым (ИК) инфракрасным пультом,для управления задействуем 5 кнопок ИК пульта,
4 кнопки для плавного поворота вправо или влево, а одну кнопку для регулировки скорости поворота.
Также задействуем ОЗУ EEPROM (энергонезависимая память): (данные сохраняются при отключении питания).
То бишь после включения питания, градус поворота servo, и установленная скорость поворота, будут теми же
какие были на момент отключения.

внимание, при первой заливки sketch, Arduino будет читать значение скорости из ячейки №3 ОЗУ.
ОЗУ скорей всего у вас девственный, поэтому нужно сначала нажать на кнопку ИК пульта управления скоростью,
чтоб в ячейке №3 появились данные. В следующих заливках sketch это делать не нужно.

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


Также рекомендую отключать servo от Arduino в момент заливки sketch, USB компьютера может не потянуть нагрузку,
servo потребляют много тока.

------------------------------------------
скетч sketch: v.01 Arduino servo IR EEPROM speed ИК пультом

================================
что нам понадобиться.
Аппаратное:
1.servo
2. любая Arduino
3. ИК инфракрасный приёмник
4. Светодиоды нужны только для визуального контроля за процессом.
5. конденсаторы
--------------------------------
программное:
Библиотеки.

1.IRremote, библиотека для работы с ИК сигналом.
Скачать библиотеку IRremote для ИК пульта
https://disk.yandex.ru/public/?hash=yNz1au3lm3/yyMHOYtnZ2UGSf19wTvYBZnkxmhW4Xt0%3D

IRremote эта библиотека кажется по новее будет
http://yadi.sk/d/0jIS1tfw6tbb7

https://github.com/shirriff/Arduino-IRremote

================================================== =====
подробную видео инструкцию выложу здесь

++++++++++++++++++++++++++++++
Вспомогательные видео обзоры, скетчи.....

скетч arduino чтобы узнать код кнопки ИК пульта
sketch arduino buttons on the remote to learn the code
https://disk.yandex.ru/public/?hash=KzLtuC1ljISPaCoXw03D6mbiKea8spktcWL5QKJHGRQ% 3D

4/6 как ? узнать код - кнопки своего ИК пульта
http://www.youtube.com/watch?v=InZuGntH_wk


v.01 Arduino IR Управление с ИК пульта в режиме удержания кнопки
https://www.youtube.com/watch?v=AjIASUNiWkY


Самый дешевый Arduino Uno 5$ Minimal Atmega328 without Arduino Board
http://www.youtube.com/watch?v=joSc-AT8o5k

v.01 Arduino управление servo любым ИК пультом Control IR + speed
http://www.youtube.com/watch?v=KYNoWX4yG8s&feature=c4-overview&list=UU7aH7HVqDvwB1xNHfSl-fDw


*/


#include <EEPROM.h> // подключаем библиотеку EEPROM
#include <Servo.h> // подключаем библиотеку для Servo
#include <IRremote.h> // подключаем СКАЧЕННУЮ библиотеку IRremote для ИК пульта


int RECV_PIN = 2; //вход ИК инфракрасного приемника
IRrecv irrecv(RECV_PIN);
decode_results results;

Servo dimkaservo_1; //даём имена servo
Servo dimkaservo_2;

//Pin для светодиодов,светодиоды для визуального контроля за процессом
int ledPin_1 = 15; //PIN 15, на Arduino Uno, Atmega328 (A1)
int ledPin_2 = 16;
int ledPin_3 = 17;
int ledPin_4 = 18;

// 1. для сглаживания пульсирующего ИК сигнала.
// 2. для отключения светодиодов ledPin после пропадания ИК сигнала, без использования delay.
int timer_ledPIN = 14; //индикация таймера //PIN 14, на Arduino Uno, Atmega328 (A0)

// (спидометр)для визуального контроля яркостью светодиода, за изменением (увеличения или уменьшения) скорости работы servo.
int speed_PWM_ledPin = 5;

// переменные для плавного вращения servo,чтоб не использовать delay.
// промежуточная переменная для хранения (увеличенного диапазона от 0 до 30000)значений (увеличения или уменьшения)PWM,
// с последующей конвертации в переменную(val) диапазон градусов поворота доступных для servo.
int a_1;
int a_2;

// переменные для экономии ресурсов ОЗУ EEPROM
int e_1;
int e_2;

//переменные для конвертации (увеличенного диапазона значений от 0 до 30000) (a_1;),(a_2;),в значения требуемые для поворота servo.
int val_1;
int val_2;

//переменная для (увеличения или уменьшения)скорости поворота servo.
int speed_PWM;

//переменная eventTime, для паузы, вместо delay,будем использовать функцию millis.
unsigned long eventTime=0;

void setup() {
// Serial.begin(9600);
irrecv.enableIRIn(); // включить ИК приёмник

dimkaservo_1.attach(9); // серво подключён на цифровой вход (pin 9)
dimkaservo_2.attach(10); // серво подключён на цифровой вход (pin 10)

pinMode(ledPin_1, OUTPUT);
pinMode(ledPin_2, OUTPUT);
pinMode(ledPin_3, OUTPUT);
pinMode(ledPin_4, OUTPUT);


pinMode(timer_ledPIN, OUTPUT);

pinMode(speed_PWM_ledPin, OUTPUT);

// после подключения питания или перезагрузки, читаем значение из ячейки №1 ОЗУ
// умножаем это значение на *118 и записываем его в переменную a_1
// делаем это в void setup то бишь только один раз в момент подключения питания
a_1=EEPROM.read(1)*118;
a_2=EEPROM.read(2)*118;

// также записываем значение из ячейки №3 ОЗУ, в переменную speed_PWM отвечающую за скорость поворота servo
speed_PWM=EEPROM.read(3);
}

void loop() {
// По приёму и обработки сигнала от ИК инфракрасного пульта.
//Мой опыт работы с ИК пультами выявил разные принципы отправки ИК сигналов кодов у разных производителей техники (пультов)
//мне нужно, чтоб система могла работать и в режиме удержания кнопки, для этого нужно постоянно слать ИК код с пульта
// пока кнопка на пульте нажата.
//Увы, есть пульты которые шлют код только один раз, в момент нажатия кнопки.
// послав 1 код, пульт далее продолжает, слать (в момент удержания кнопки), (назовем его (пустой инфракрасный сигнал).
// после отпускания кнопки (пустой инфракрасный сигнал) исчезает.
// Задача такая, после приёма определённого кода кнопки,сразу перехватывать идущий за ним (кодом), (пустой инфракрасный сигнал)
// и считать его, (пустой инфракрасный сигнал), за код кнопки.
//после пропадания (пустого инфракрасного сигнала), будем считать, что код перестал слаться

// Эта конструкция нужна чтобы.
//1.после приёма определённого кода кнопки,перехватывать (пустой инфракрасный сигнал)
//2.конвертировать пульсирующий (-) с (ИК) преемника сигнал в постоянный.
//После появления и пропадания сигнала, состояние сразу не меняется! а ждет 100 миллисекунд.
//Если 100 миллисекунд не прошло, и поступил еще один ИК сигнал с пульта, тогда таймер заново запускается на 100 миллисекунд.

//Проще говоря, пока кнопка на ИК пульте нажата timer_ledPIN остается HIGH
//если кнопка на пульте отпущена, LOW.



// Читаем состояние ноги у (ИК) преемника. В момент приема данных, у (ИК)
//приемника на выходе появляется пульсирующий (-)отрицательный сигнал


if (digitalRead(RECV_PIN) == LOW)
eventTime=millis(),digitalWrite(timer_ledPIN, HIGH);
if(millis()-eventTime>100) digitalWrite(timer_ledPIN, LOW),digitalWrite(ledPin_1, LOW),digitalWrite(ledPin_2, LOW),
digitalWrite(ledPin_3, LOW),digitalWrite(ledPin_4, LOW);


//если ledPin_1) ==, выставляем ограничение для переменной(a_1) до (&& a_1<30000).и Начинаем увеличивать
// значения переменной(a_1) прибавляем на значение переменной speed_PWM,
//и также выставляем ограничение при убывании (&& a_1>0)
if(digitalRead(ledPin_1) == HIGH && a_1<30000 ) a_1=a_1+speed_PWM;
if(digitalRead(ledPin_2) == HIGH && a_1>0 ) a_1=a_1-speed_PWM;


//читаем значение (a_1) и конвертируем его в значение val_1, то бишь в значение поворота в градусов доступных для servo.
// правильно было бы конвертировать в, (от 0, до 180) градусов, но мои дешёвые servo доходя до краёв,
//начинают дребезжать,поэтому я кастрировал их (края) по 10 градусов (10, 170);)
val_1 = a_1;
val_1 = map(val_1, 0, 30000, 10, 170); // scale it to use it with the servo (val_1ue between 10 and 170)
dimkaservo_1.write(val_1); // sets the servo position according

//делаем тоже самое и для dimkaservo_2
if(digitalRead(ledPin_3) == HIGH && a_2<30000 ) a_2=a_2+speed_PWM;
if(digitalRead(ledPin_4) == HIGH && a_2>0 ) a_2=a_2-speed_PWM;

val_2 = a_2;
val_2 = map(val_2, 0, 30000, 10, 170);
dimkaservo_2.write(val_2); //записываем значения val_2 в dimkaservo_2


// эта конструкция отвечает за запись положения градусов servo в ОЗУ EEPROM.
// Можно было бы сделать так if(digitalRead(ledPin_1) == HIGH || digitalRead(ledPin_2)== HIGH)EEPROM.write(1, a_1/118);.
// В документации на ATMEGA328P-PU указано, количество записи и чтения в ячейку ОЗУ гарантировано не более 100.000 раз,
// поэтому будем экономить ОЗУ, то бишь записывать не постоянно в (момент движения) изменения градусов servo,
//а только тогда, когда servo остановилась.
//когда кнопка №1 или №2 на ИК пульте нажата if(digitalRead(ledPin_1) == HIGH || digitalRead(ledPin_2)== HIGH)
// фиксируем это событие в переменную e_1 и записываем в неё =1; (e_1=1;)
// когда кнопку №1 И №2 отпустили, то бишь servo остановилась //(ledPin_1) == LOW && digitalRead(ledPin_2)== LOW//
// и && e_1==1 то бишь перед тем как servo остановилась она была включена,
//записываем в ячейку №1 EEPROM значение переменной a_1.
// Так как ячейка EEPROM может хранить значения от (0 до 255), а диапазон значений переменной a_1
//от (1 до 30.000), то перед записью в ячейку №1, делим значение переменной a_1 на 118 //(1, a_1/118)//
// и меняем значение переменной e_1 на 0 // ,e_1=0;//

if(digitalRead(ledPin_1) == HIGH || digitalRead(ledPin_2)== HIGH)e_1=1;
if(digitalRead(ledPin_1) == LOW && digitalRead(ledPin_2)== LOW && e_1==1)EEPROM.write(1, a_1/118),e_1=0;

if(digitalRead(ledPin_3) == HIGH || digitalRead(ledPin_4)== HIGH)e_2=1;
if(digitalRead(ledPin_3) == LOW && digitalRead(ledPin_4)== LOW && e_2==1)EEPROM.write(2, a_2/118),e_2=0;

//Serial.println(EEPROM.read(1));




// Эта часть отвечает за приём и обработку ИК кодов
// здесь считываем коды от ИК пульта



// У моего пульта при нажатии на одну и ту же кнопку, могут отсылаться два разных (КОДА) сигнала, чтобы обойти эту проблему
//я использовал Логический оператор "или" (||) if (results.value == 0x1000809 || results.value == 0xF7283C77
// Теперь неважно какой код отправлен с кнопки пульта, первый или второй
// Если ваша кнопка пульта не страдает раздвоением личности, можете написать так if (results.value == 0x1000809
//также мною замечено при использовании разных ИК приемников, частотой 36,или 38, кГц, библиотека IRremote
// выдает Разные коды.
//можно сделать 4 "или" (||), чтобы можно было управлять с двух разных ИК пультов

//ВАЖНО !!! (1000809) это код кнопки №1 - моего (ИК)! (инфракрасного пульта)!, -
//-у вашего пульта будет другой код, замените на свой!

if (irrecv.decode(&results)) {
if(digitalRead(timer_ledPIN) == HIGH && (results.value == 0x1000809 || results.value == 0xF7283C77))digitalWrite(ledPin_1, HIGH);
if(digitalRead(timer_ledPIN) == HIGH && (results.value == 0x1008889 || results.value == 0x757FB4DF))digitalWrite(ledPin_2, HIGH);

if(digitalRead(timer_ledPIN) == HIGH && (results.value == 0x1004849 || results.value == 0xB33B4597))digitalWrite(ledPin_3, HIGH);
if(digitalRead(timer_ledPIN) == HIGH && (results.value == 0x100C8C9 || results.value == 0x3C03E507))digitalWrite(ledPin_4, HIGH);



//эта кнопка пульта для (увеличения или уменьшения)скорости поворота servo.
// начинаем увеличивать скорость на одну позицию speed_PWM++;
// и ставим ограничение на количество скоростей if (speed_PWM > 51)
// дойдя до 51 скорости,сбрасываемся на первую скорость > 51)speed_PWM=1;
// записываем в ячейку №3 EEPROM значение speed_PWM



if(digitalRead(timer_ledPIN) == HIGH && (results.value == 0x1002829 || results.value == 0xE705551F))
speed_PWM=speed_PWM+1,EEPROM.write(3,speed_PWM);
if (speed_PWM > 51)speed_PWM=1;
//Serial.println(EEPROM.read(3));

//для визуального контроля за состоянием скоростной коробки передач (спидометр),используем светодиод speed_PWM_ledPin
//(увеличивая или уменьшая)PWM сигнал (analogWrite) "записываем в светодиод" значения от переменной speed_PWM,
// для контрастности изменений в яркости, умножаем speed_PWM на 5 (speed_PWM*5)

analogWrite(speed_PWM_ledPin,speed_PWM*5);
//Serial.println(speed_PWM);

irrecv.resume();
}
}

// уникальность этого sketch в том, что не используется ни одного delay();.
// Благодаря этому, значение (плавность поворота servo) высокое.
// Есть возможность параллельно выполнять в постоянном режиме другие процессы.

skanch
27.03.2016, 21:30
Проект получил продолжение - пришли компоненты для планшета ipad mini (https://www.ryanscomputers.com/Apple-Tablet-PC-7012).
Чехол -ZAGG rugged book (http://www.zagg.com/eu/en_eu/keyboards/rugged-book-ipad-air).
Беспроводная подзарядка PLESON-C180 (http://maxi-sale.ru/amazon/us/Industrial/AdditiveManufacturing/asin-B015CJCW5E.html).
Приемник беспроводной подзарядки.
Комплект магнитов.

Чехол оказался достаточно массивным - толстая мягкая резина, а в середине жесткий пластик.

Блок подзарядки я сразу "препарировал". Внешнее кольцо на выброс-бесполезная деталь и вес не маленький. Конструкция корпуса удачная для моих целей - внедрение в платформу будет не сложным.

Магниты обычные - тонкие и мощные.

skanch
27.03.2016, 21:44
В этом механизме управление наклоном планшета в открытом состоянии планирую сделать от потенциометра. Но столкнулся с небольшой проблемой - после выставления угла потенциометром серва некоторое время "дрожит" (у серв это бывает и называется "jitter"). Сначала использовал обычный "переменник", купленный на рынке . С ним "jitter" был очень существенный. Поменял на "импортный" и взял шнурок от USB кабеля с фильтром - "дрожание" есть, но совсем небольшое и по времени пару секунд. Оба "переменника" с угольным напылением резистивного слоя. Решил попробовать кермет. Сегодня приобрел такой, но еще не экспериментировал. Надеюсь это он...

skanch
28.03.2016, 22:52
Потенциометр кермет решил проблему- дрожание полностью исчезло.
jtN_3Dbk2UQ

skanch
03.04.2016, 11:40
"Слепил" скетч управления сервомашинкой с помощью механического энкодера. Энкодер использовал первый попавшийся- выпаял из платы управления магнитолой. За основу взял скетч с этого ресурса (http://forum.amperka.ru/threads/%D0%A3%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D 0%B8%D0%B5-%D0%BF%D0%BE%D0%B2%D0%BE%D1%80%D0%BE%D1%82%D0%B0-%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE%D0%BA%D0%B0%D0%BC%D 0%B5%D1%80%D1%8B-%D0%B8%D0%BB%D0%B8-%D0%BD%D0%B5%D1%87%D1%82%D0%BE-%D0%BF%D0%BE%D0%B4%D0%BE%D0%B1%D0%BD%D1%8B%D0%BC.1 184/). Алгоритм такой:
1.Нажали кнопку один раз-серва повернулась на максимальный угол (сохраненный в памяти).
1.1.Зашли в режим настройки угла сервы (энкодер).
2.Нажали еще раз-серва вернулась в начальную точку.
Угол сохраняется в памяти (Eeprom) и при следующем включении серва повернется на выставленный угол.
Удивительно, но работает...

#define pinA 3 //Первый PIN Сигнала с энкодера
#define pinB 4 //Второй PIN Сигнала с энкодера
#define pinC 10 //PIN кнопки запуска системы
#include <Servo.h>
#include <EEPROM.h>
Servo myservo; //Название сервомашины
int servoPin = 8; //Сервомотор подключен на PIN 8

int angle; //Текущий угол поворота (при запуске программы будет автоматический вставать в указаное положение)
int maxAngle = 90; //Максимальный угол поворота сервомотора (градусов)
int minAngle = 6; //Минимальный угол поворота сервомотора (градусов)
int angleStep = 2; //Угол единичного шага (градусов)
int stepSpeed = 3; //Скорость шага (Время задержки шага)
boolean valA=0; //Текущее переменное значение энкодера на выходе энкодера А
boolean valB=0; //Текущее переменное значение энкодера на выходе энкодера В
boolean valC=0; //Переменная функции запуска системы
boolean Estate=0; //Вспомогательная переменная необходимая для определения направления вращения
boolean pulse = 0; //Импульс шага в любом направлении, не стабилизированный
boolean Dir =0; //Переменная направления вращения (Если=1 то влево, если=0 то вправо)
boolean zapret=HIGH; //Вспомогательная переменная необходимая для стабилизации импульса шага
boolean outsig=HIGH; //Импульс шага в любом направлении, стабилизированный
long time; //Переменная таймера задержки в функции стабилизации
int flag = 0; // Флаг состояния
int regim = 0; // Переключалка

void setup()
{
angle = EEPROM.read(0);//Считываем из памяти угол поворота сервы
pinMode(pinC,INPUT_PULLUP); //Цифровой вход С кнопки запуска системы
pinMode(pinA,INPUT_PULLUP); //Цифровой вход A c энкодера
pinMode(pinB,INPUT_PULLUP); //Цифровой вход В c энкодера
}

void loop()
{
if(digitalRead(pinC) == LOW && flag == 0)//Если кнопка нажата
// и перемення flag равна 0 , то ...
{
regim ++;
flag = 1;//Это нужно для того что бы с каждым нажатием кнопки
//происходило только одно действие

if(regim > 4) // Если номер режима превышает требуемого
{ // то отсчет начинается с 1
regim = 1;
}
}
if(digitalRead(pinC) == HIGH && flag == 1)//если кнопка НЕ нажата
//и переменная flag равна - 1 ,то ...
{
flag = 0;
}

// РЕЖИМ 1:

if(regim == 1)// Нажали кнопку один раз...
{
myservo.attach(servoPin);
myservo.write(angle); // Серва повернулась на сохраненный в Eeprom угол
delay(stepSpeed);// Скорость поворота сервы
}
// РЕЖИМ 2:
if(regim ==2 )// Нажали кнопку второй раз...
{
change_ugol(); // Режим установки наклона с помощью энкодера
}
// РЕЖИМ 3:
if(regim == 3)// Нажали кнопку в третий раз...
{
}// ничего не происходит...

// РЕЖИМ 4:
if(regim == 4)// Нажали кнопку в четвертый раз...
{
myservo.write(maxAngle); // Серва вернулась в исходное состояние
delay(stepSpeed);// Скорость поворота сервы
}
}

// РЕЖИМ УСТАНОВКИ УГЛА НАКЛОНА С ПОМОЩЬЮ ЭНКОДЕРА
void change_ugol()
{
valA=digitalRead(pinA); //Читает и запоминает текущее состояние на выходе энкодера (Выход А)
valB=digitalRead(pinB); //Читает и запоминает текущее состояние на выходе энкодера (Выход В)
valC=digitalRead(pinC); //Читает и запоминает текущее состояние кнопки быстрой центровки

//РАСПОЗНАНИЕ ШАГА
if(valA+valB==HIGH){pulse=1;} //Определяет шаг и дает не стабилизированный импульс шага
else{pulse=0;}

//СТАБИЛИЗАТОР ИМПУЛЬСА ШАГА
if((pulse==HIGH)&&(zapret==LOW))//Условие работы стабилизатора выходного импульса
{
time = millis(); //Запуск таймера
outsig = HIGH; //Стабилизированый выходной импульс шага
}
zapret=HIGH;
if(outsig && (millis() - time) > 1) //(2)-Временная длинна выходного импульса
{
outsig = LOW;//Остановка таймера
}

if(pulse==LOW)
{
zapret=LOW; //Антидребезг
}
//ОПРЕДЕЛЕНИЕ ВСПОМОГАТЕЛЬНОЙ ПЕРЕМЕННОЙ
//ДЛЯ ОПРЕДЕЛЕНИЯ НАПРАВЛЕНИЯ ВРАЩЕНИЯ
if((valA==LOW)&&(valB==LOW)&&(valA<1)&&(valB<1))
{
Estate=1;//Вспомогательная переменная для определения направления вращения энкодера на (+)
}
if((valA==HIGH)&&(valB==HIGH)&&(valA>0)&&(valB>0))
{
Estate=0;//Вспомогательная переменная для определения направления вращения энкодера на (-)
}

//ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ ВРАЩЕНИЯ
if(((Estate==1)&&(valA==LOW)&&(valB==HIGH))||((Estate==0)&&(valA==HIGH)&&(valB==LOW))) //Условия направления вращения(+)
{
Dir=1;//Направление вращения (+)
}
if(((Estate==1)&&(valA==HIGH)&&(valB==LOW))||((Estate==0)&&(valA==LOW)&&(valB==HIGH))) //Условия направления вращения(-)
{
Dir=0;//Направление вращения(-)
}

//ВЫХОДНОЙ СИГНАЛ
if((Dir==1)&&(outsig==HIGH)) //Условие поворота в одну из строн (Направление + стабилизированый сигнал шага)
{
angle=angle+angleStep; //угол поворота сервомотора меняется по шагово на заданную величину шага
if (angle > maxAngle)
{
angle=maxAngle;//Ограничитель угла поворота исполнительного устройства (Рабочий диапозон)
}
}
if((Dir==0)&&(outsig==HIGH)) //Все тоже самое как для предидущей функции но с !инверсией
{
angle=angle-angleStep; //угол поворота сервомотора меняется по шагово на заданную величину шага
if (angle < minAngle)
{
angle = minAngle; //Ограничитель угла поворота исполнительного устройства (Рабочий диапозон)
}
}
{
myservo.write(angle); //Входной сигнал на сервомотор
delay(stepSpeed);//Скорость шага (время задержки шага)
}
EEPROM.write(0, angle); //Сохраним в памяти угол поворота
}

skanch
03.04.2016, 19:10
Нашел интересную библиотеку (https://code.google.com/archive/p/clickbutton/downloads) для обработки нажатий кнопок в Ардуино. Попробовал "привязать" к своему энкодеру - получилось не плохо. Можно назначить сколько угодно нажатий (одно нажатие, два, короткие, длинные) кнопки энкодера для запуска чего-либо... Это пример скетча для управления одной сервой (немного подправил).

#define pinA 3 //Первый PIN Сигнала с энкодера
#define pinB 4 //Второй PIN Сигнала с энкодера
#include "ClickButton.h"
#include <Servo.h>
#include <EEPROM.h>
Servo myservo; //Название сервомашины
int servoPin = 8; //Сервомотор подключен на PIN 8
int angle; //Текущий угол поворота (при запуске программы будет автоматический вставать в указаное положение)
int maxAngle = 90; //Максимальный угол поворота сервомотора (градусов)
int minAngle =45; //Минимальный угол поворота сервомотора (градусов)
int angleStep = 2; //Угол единичного шага (градусов)
int stepSpeed = 2; //Скорость шага (Время задержки шага)
boolean valA=0; //Текущее переменное значение энкодера на выходе энкодера А
boolean valB=0; //Текущее переменное значение энкодера на выходе энкодера В
boolean Estate=0; //Вспомогательная переменная необходимая для определения направления вращения
boolean pulse = 0; //Импульс шага в любом направлении, не стабилизированный
boolean Dir =0; //Переменная направления вращения (Если=1 то влево, если=0 то вправо)
boolean zapret=HIGH; //Вспомогательная переменная необходимая для стабилизации импульса шага
boolean outsig=HIGH; //Импульс шага в любом направлении, стабилизированный
long time; //Переменная таймера задержки в функции стабилизации
// Светодиод
const int ledPin = 13;
int ledState = 0;
// Кнопка
const int buttonPin1 = 10;
ClickButton button1(buttonPin1, LOW, CLICKBTN_PULLUP);
// Назначаем функцию переключателя
int LEDfunction = 0;

void setup()
{
angle = EEPROM.read(0);//Считываем из памяти угол поворота сервы
pinMode(ledPin,OUTPUT);
button1.maxPresses = 9; // Количество программируемых нажатий для кнопок
button1.debounceTime = 20; // Таймер дребезга в мс
button1.multiclickTime = 350; // Пауза между нажатиями кнопки
button1.heldDownTime = 1000; // длительность нажатия и удержания кнопки
pinMode(pinA,INPUT_PULLUP); //Цифровой вход A c энкодера
pinMode(pinB,INPUT_PULLUP); //Цифровой вход В c энкодера
}
void loop()
{
// Обновлям состояние кнопки
button1.Update();

if (button1.click != 0)

LEDfunction = button1.click;
if(button1.click == 1)
ledState = !ledState;

//Два коротких нажатия
if(LEDfunction == 2)
{
myservo.attach(servoPin);
myservo.write(maxAngle); // Серва вернулась в исходное состояние
delay(stepSpeed);// Скорость поворота сервы
}


// три коротких нажатия
if(LEDfunction == 3)
{
myservo.attach(servoPin);
change_ugol(); // Режим установки наклона с помощью энкодера
}



// длительное однократное нажатие (более 1 секунды)
if(LEDfunction == -1)
{
myservo.attach(servoPin);
myservo.write(angle); // Серва повернулась на сохраненный в Eeprom угол
delay(stepSpeed);// Скорость поворота сервы
}



// одно короткое + одно длительное нажатие (более 1 секунды)
if(LEDfunction == -2)
{}//можно что-то вставить


// два коротких + одно длительное нажатие (более 1 секунды)
if(LEDfunction == -3)
{}//можно что-то вставить
// update the LED
digitalWrite(ledPin,ledState);
}


//*********** РЕЖИМ УСТАНОВКИ УГЛА НАКЛОНА С ПОМОЩЬЮ ЭНКОДЕРА **************//

void change_ugol()
{
valA=digitalRead(pinA); //Читает и запоминает текущее состояние на выходе энкодера (Выход А)
valB=digitalRead(pinB); //Читает и запоминает текущее состояние на выходе энкодера (Выход В)

//РАСПОЗНАНИЕ ШАГА
if(valA+valB==HIGH){pulse=1;} //Определяет шаг и дает не стабилизированный импульс шага
else{pulse=0;}

//СТАБИЛИЗАТОР ИМПУЛЬСА ШАГА
if((pulse==HIGH)&&(zapret==LOW))//Условие работы стабилизатора выходного импульса
{
time = millis(); //Запуск таймера
outsig = HIGH; //Стабилизированый выходной импульс шага
}
zapret=HIGH;
if(outsig && (millis() - time) > 1) //(2)-Временная длинна выходного импульса
{
outsig = LOW;//Остановка таймера
}
if(pulse==LOW)
{
zapret=LOW; //Антидребезг
}
//ОПРЕДЕЛЕНИЕ ВСПОМОГАТЕЛЬНОЙ ПЕРЕМЕННОЙ
//ДЛЯ ОПРЕДЕЛЕНИЯ НАПРАВЛЕНИЯ ВРАЩЕНИЯ
if((valA==LOW)&&(valB==LOW)&&(valA<1)&&(valB<1))
{
Estate=1;//Вспомогательная переменная для определения направления вращения энкодера на (+)
}
if((valA==HIGH)&&(valB==HIGH)&&(valA>0)&&(valB>0))
{
Estate=0;//Вспомогательная переменная для определения направления вращения энкодера на (-)
}
//ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ ВРАЩЕНИЯ
if(((Estate==1)&&(valA==LOW)&&(valB==HIGH))||((Estate==0)&&(valA==HIGH)&&(valB==LOW))) //Условия направления вращения(+)
{
Dir=1;//Направление вращения (+)
}
if(((Estate==1)&&(valA==HIGH)&&(valB==LOW))||((Estate==0)&&(valA==LOW)&&(valB==HIGH))) //Условия направления вращения(-)
{
Dir=0;//Направление вращения(-)
}
//ВЫХОДНОЙ СИГНАЛ
if((Dir==1)&&(outsig==HIGH)) //Условие поворота в одну из строн (Направление + стабилизированый сигнал шага)
{
angle=angle+angleStep; //угол поворота сервомотора меняется по шагово на заданную величину шага
if (angle > maxAngle)
{
angle=maxAngle;//Ограничитель угла поворота исполнительного устройства (Рабочий диапозон)
}
}
if((Dir==0)&&(outsig==HIGH)) //Все тоже самое как для предидущей функции но с !инверсией
{
angle=angle-angleStep; //угол поворота сервомотора меняется по шагово на заданную величину шага
if (angle < minAngle)
{
angle = minAngle; //Ограничитель угла поворота исполнительного устройства (Рабочий диапозон)
}
}
{
myservo.write(angle); //Входной сигнал на сервомотор
delay(stepSpeed);//Скорость шага (время задержки шага)
}
EEPROM.write(0, angle); //Сохраним в памяти угол поворота
}

skanch
03.05.2016, 13:09
Спрошу в своей теме...
Нужен компактный осевой мотор-редуктор . Диаметр корпуса не должен превышать 10 мм. Редуктор желателен планетарный.
Скорость: 4-10 оборотов в минуту. Усилие на валу: от 1500 г/см. Длинна всего мотора до 100 мм. Нужен для изготовления электропривода декоративной крышки механизма перемещения монитора (принцип, как на видео (https://youtu.be/97YyrZYBzcA)). Все время пользовался Shayang Ye IG-12GM DC (http://util.oem.se/pdf/shayang_ye_ig-12gm_dc_motor_with_planetary_gear_1159529-528563.pdf) с диаметром корпуса 12 мм. Но сейчас нужен именно не более 10 мм и со схожими параметрами с IG-12GM. Возможно, кто-то из заглянувших в мою тему сможет подсказать - где приобрести такой.

skanch
08.05.2016, 23:55
Ломаем (модернизируем) дальше сервомотор...
Из-за того, что оси валов пересекаются под углом в 90 градусов я в своих механизмах использую коническую передачу. Коническая шестерня, та что на серве, располагается консольно. При этом, вследствие повышенной деформации консольного вала (один из побочных эффектов конической передачи), увеличивается неравномерность распределения нагрузки по ширине зубчатого венца и как следствие - выход одного подшипника сервомотора из строя - того, что ближе и меньше по размеру на фото. Появляется значительный люфт у "подиума" в открытом состоянии. Подшипник, прямо скажу - слабоват для заявленного усилия в 53кг/см. Подобрать что-то более надежное для замены вряд ли получится. Думаю сделать небольшой промежуточный редуктор с более мощными подшипниками и перенести осевую нагрузку с подшипника сервы.
Позже поделюсь результатом.

skanch
20.05.2016, 21:30
Вот собственно и редуктор...

skanch
25.05.2016, 18:39
Нашел миниатюрный мотор с редуктором. Правда не с планетарным... и немного не те размеры, но думаю, что подойдет.
Практически бесшумный. При питании от 5 вольт скорость примерно 6-7 оборотов в минуту и ток при нагрузке в 2 кг./см. - 18-20 мА. Заявленное усилие на валу - 3 кг./см.(похоже на правду). Габариты 12 мм. Х 10 мм. Х 40 мм. Диаметр вала - 3 мм. Ну и до кучи прикупил подшипники... Буду пытаться сделать "управляемую" крышку для корпуса механизма.

skanch
25.05.2016, 19:39
Сделал новую плату управления под размер нового редуктора. Весь механизм увеличился в ширину - это не критично, место установки позволяет. Главное размер в высоту остается 50 мм.

skanch
25.05.2016, 20:12
Очередная примерка на заготовке каретки.

skanch
31.05.2016, 18:18
Купил неплохой, на мой взгляд, мотор с червячным редуктором (http://ru.aliexpress.com/item/Wholesale-JGY-370B-12v-DC-Motor-with-Encoder-Disk-High-Torque-Low-Speed-Gear-box-Worm/32383572773.html) и с энкодером. Енкодер построен на датчике Холла (http://docs-europe.electrocomponents.com/webdocs/106a/0900766b8106a141.pdf).
Буду пытаться программно "прикрутить" к своим поделкам.

skanch
26.06.2016, 19:58
Это "пациент".
Так выглядит сейчас.

skanch
26.06.2016, 23:22
Этот (http://www.pccar.ru/showpost.php?p=345990&postcount=59) механизм (http://www.pccar.ru/showpost.php?p=345987&postcount=58) из "старых (http://www.pccar.ru/showpost.php?p=345868&postcount=55)". В нем, по желанию заказчика фиксированный угол в открытом положении (реализован на двух датчиках Холла). В последних конструкциях пока пользуюсь сервомоторами, но ищу варианты использования простых DC мотор-редукторов с управлением положением по датчику Холла и регулировкой угла наклона или потенциометром, или энкодером . Пока все в процессе поиска решения...

skanch
05.08.2016, 17:03
Нашел контроллер управления DC-моторами. С помощью этой платки мотор-редуктор можно превратить в мощную серву и управлять стандартными способами. Нагрузка до 10А! Надеюсь, что это - то, что надо... Заказал... Жду...

skanch
22.08.2016, 15:28
Пришел, вышеупомянутый контроллер - работает отлично! Теперь можно "прикручивать" мощные мотор-редукторы для подъема тяжелых мониторов. От управления простой сервой практически не отличается - можно управлять углом с помощью энкодера или потенциометра с помощью стандартной библиотеки для Ардуино.
Ограничение по скорости вала редуктора: max 130 об./мин. (как правило для подъема монитора из горизонтального положения достаточно примерно 4-30 об./мин.)

skanch
22.08.2016, 15:57
В плате использованы мощные MOSFET N-транзисторы IR2905 (http://lib.chipdip.ru/292/DOC000292808.pdf).

skanch
22.08.2016, 16:26
Хочу попробовать многооборотный потенциометр (http://www.platan.ru/cgi-bin/qwery.pl/id=202605591) посадить на вал. И считывать с него угол. По идее должно получиться, что-то типа шаговика, только мерить не количество шагов, а сопротивление/угол. Если получиться-смогу позиционировать перемещение каретки (актуально для вертикально выезжающих механизмов-в них нужны мощные мотор-редукторы).

skanch
08.09.2016, 09:01
Для одного из вариантов механизма пытался найти готовый гибкий шлейф с шагом 2.54мм, но не смог. Решил сделать самодельный. На просторах интернет-рынка случайно приобрел фольгированный стеклотекстолит ФТС-2-20Б толщиной 0.08 мм. Качество листов, размером 250х250мм просто плачевное - царапины, вмятины, местами пятна патины... Если правильно прочитал на бирке - произведено в 1984 г. Но это все же лучше, чем ничего! Платы делаю с использованием фоторезиста. Метод описывать не буду - в инете полно информации. Шаблон печатаю на струйном принтере на пленке Lomond. Печатаю два негатива и затем накладываю друг на друга - для более плотного цвета. Травлю в хлорном железе.

skanch
08.09.2016, 09:03
Это результат. Вполне приемлемая гибкость. Осталось залудить дорожки и заламинировать шлейф.

skanch
21.09.2016, 19:33
И опять гибкий шлейф... Теперь из стеклотекстолита NAN YA FR-4 18 /0,15мм (http://absolutstore.ru/catalog/nan_ya_1/steklotekstolit_nan_ya_fr_4_18_18_0_15mm_1240kh108 0/). Этот вариант мне больше понравился. Во-первых - доступность материала, во-вторых - немного пожестче, чем ФТС-2-20Б 0.08 мм, а для моих поделок это критично. В-третьих - легче в изготовлении (фоторезист у меня пленочный и на тонкий, и к тому же "битый" ФТС-2-20Б нанести его -та еще заморочка).Радиус изгиба готового шлейфа примерно 8-10мм.

skanch
08.10.2016, 18:20
Шлейф в механизме.
https://youtu.be/oANjfwoNhEg
oANjfwoNhEg

skanch
27.12.2016, 22:06
Все таки серва, отвечающая за подъем монитора подвела... Не выдержал опорный подшипник (на переднем плане маленький)
http://pccar.ru/picture.php?albumid=307&pictureid=2066http://pccar.ru/attachment.php?attachmentid=43680&stc=1&thumb=1&d=1462734631.


Его заклинило и как следствие - сгорел драйвер сервопривода. Подшипник слабоват для заявленных нагрузок. Буду переделывать на мотор-редуктор (http://pccar.ru/attachment.php?attachmentid=43911&stc=1&thumb=1&d=1464703941) с червячной передачей. Управление мотором через такой контроллер http://pccar.ru/attachment.php?attachmentid=44446&stc=1&thumb=1&d=1470402162.

skanch
16.02.2017, 18:31
Многие в своих работах используют DC-DC преобразователь на микросхеме MP1584 (http://www.haoyuelectronics.com/Attachment/MP1584/MP1584.pdf). Я не исключение... Для моих поделок он подходит, как нельзя лучше - маленький (помещается в корпуса миниатюрных сервомоторов для отдельного питания), достаточно мощный - нагрузка до 1,5 А без радиатора. Использую и для питания контроллеров, и для питания обвязки управления ... Очень экономичный - в режиме покоя потребление всего 20 μA (микроампер!)- это возможно, если использовать управляющий вход (нога №2) на микросхеме MP1584. По даташиту, если ногу притянуть к "земле", то микросхема переходит в ждущий режим, если на ногу подать напряжение в пределах от 1,6V до 3,0V- микросхема включится. На готовой плате он не выведен и хочу поделиться, как это делаю я. Модуль очень маленький и подпаяться прямо на плате достаточно сложно (возможно, но провода торчащие из платы в моем случае допустимы, если модуль "прячу" в корпус сервы ). Итак: сдуваем с платы два резистора (http://pccar.ru/attachment.php?attachmentid=46794&stc=1&d=1487252508). Затем сверлом 0.8мм сверлим отверстие вот здесь (http://pccar.ru/attachment.php?attachmentid=46795&stc=1&d=1487252508). Оно должно быть как можно плотнее прижато к контактной площадке отпаянного резистора, но не заходить на неё. Далее с обратной стороны в поле GND вокруг просверленного отверстия формируем контактную плошадку (http://pccar.ru/attachment.php?attachmentid=46797&stc=1&d=1487252534) (я использую гравер). Счищаем слой маски для пайки. Если гравера нет, то можно зенкануть (http://pccar.ru/attachment.php?attachmentid=46796&stc=1&d=1487252508) отверстие (сделать небольшую лунку на половину толщины платы) простым сверлом диаметром 3.5-4.5 мм. Далее в отверстие вставляем штырь от гребенки PLS (https://www.chipdip.ru/product/pls-10) и аккуратно припаиваем (http://pccar.ru/attachment.php?attachmentid=46798&stc=1&d=1487252534) со стороны деталей к контактной площадке. Можно паяльником с жалом "игла"(флюса побольше и немного припоя-использую нейтральный флюс ЛТИ120 (http://anytech.narod.ru/flux.htm)). Или термофеном от паяльной станции с паяльной пастой. С обратной стороны, если сделана площадка под пайку тоже припаиваем (http://pccar.ru/attachment.php?attachmentid=46799&stc=1&d=1487252534). Если площадки нет, а есть лунка, то ее надо залить эпоксидкой (процесс немного затянется...). Все эти манипуляции для более жесткой фиксации штыря в плате ( площадка от резистора абсолютно не надежная ).
После того, как контакт более или менее прочно зафиксирован в плате подключаем плату к источнику питания, а к штырю резистивный делитель напряжения по такой схеме (http://pccar.ru/attachment.php?attachmentid=46802&stc=1&d=1487254306). Способ, о котором я рассказал позволяет подключаться напрямую к впаянному контакту ("...гибкий проводок типа МГТФ припаять", как ниже заметил YAM1966) или при таком (http://pccar.ru/attachment.php?attachmentid=46204&d=1483696292) монтаже сделать разводку делителя на основной плате (http://pccar.ru/attachment.php?attachmentid=46199&d=1483696267) (для меня этот вариант предпочтительнее ).

skanch
15.03.2017, 18:41
В очередном проекте пришлось заняться "препарированием" Lenovo TAB3 8 для организации адекватной работы в составе механизма. Поскольку крепление планшета жесткое (не съемное) стоит задача протащить через механизм шлейф с проводами для подключения к распределителю питания (http://www.pccar.ru/showthread.php?t=25628).
Подпаялся к разъему USB.
http://www.pccar.ru/attachment.php?attachmentid=47028&stc=1&d=1489691553

http://www.pccar.ru/attachment.php?attachmentid=47029&stc=1&d=1489691553

и к кнопке включения планшета

http://www.pccar.ru/attachment.php?attachmentid=47030&stc=1&d=1489691553

Батарею решил убрать. Без контроллера батареии планшет отказался включаться (напрямую подпаяны провода от блока питания к контактным площадкам у разъема батареи).

http://www.pccar.ru/attachment.php?attachmentid=47036&stc=1&d=1489692068
http://www.pccar.ru/attachment.php?attachmentid=47037&stc=1&d=1489692068

Сделал по следующей схеме, контакт "+" от батареи на контроллере соединил с "+" питания на разъеме USB.

http://www.pccar.ru/attachment.php?attachmentid=47038&stc=1&d=1489692068

и через самопальный шлейф планирую вывести уже наружу.

http://www.pccar.ru/attachment.php?attachmentid=47039&stc=1&d=1489692097

http://www.pccar.ru/attachment.php?attachmentid=47040&stc=1&d=1489692097


Напряжение питания планшета 4.7В (при напряжении 4.5В иконка статуса батареии показывает 93%). При 4.7В иконка батареи показывает 100%. Сам планшет работает без нареканий.
При проведении некоторых тестов заметил, что при подключенном режиме OTG и если планшет находится во сне потребление планшета выше нежили при выключенном режиме OTG. На видео это видно.

https://youtu.be/0oUYXH9iyG8
0oUYXH9iyG8

https://youtu.be/b3LKbw2WIys
b3LKbw2WIys

skanch
15.03.2017, 19:50
Для нового проекта был разработан и изготовлен металический корпус (выражаю благодарность Alex-L за отличную работу- корпус это его заслуга).

http://www.pccar.ru/attachment.php?attachmentid=47041&stc=1&d=1489724550
http://www.pccar.ru/attachment.php?attachmentid=47042&stc=1&d=1489724550


Сейчас проект начал понемногу развиваться (в Китае закончились праздники-стали приходить комплектухи).

http://www.pccar.ru/attachment.php?attachmentid=46983&stc=1&d=1489592978

http://www.pccar.ru/attachment.php?attachmentid=46984&stc=1&d=1489592978

skanch
16.03.2017, 19:40
В качестве концентратора для планшета будет использоваться ORICO A3H7 (http://orico-russia.ru/orico-a3h7-sv)
Сегодня пробовал подключать-определился в режиме OTG (пока подключаю через шнурок) без перерезания питающего провода.Флешки определяются, жесткий от ноутбука тоже, но попросил форматнуть...

Пробовал несколько режимов: HUB включен,флешка определена-увожу планшет в "сон". Через некоторое время "пробуждаю" планшет (шнурок OTG не передергиваю) - HUB определяется.
Перезагрузка, выключение, "жесткое" выключение (резко рублю питание)- после включения HUB определяется! Не важно в какой последовательности - планшнт сначала или питание HUB-а. OTG не передергиваю!
На корпусе ORICO кнопка включения питания без фиксации - чтобы коммутировать питание на HUB средствами "умного" блока питания придется ее зафиксировать в нажтом состоянии.

skanch
16.03.2017, 21:01
Это "потроха". Поставил перемычку на кнопку - теперь при подаче питания сразу включается.

skanch
21.03.2017, 21:40
Простое решение для включения системы в машине по достижению определенной температуры. Пользуюсь такими (https://ru.aliexpress.com/item/1PCS-W1209-DC-12V-heat-cool-temp-thermostat-temperature-control-switch-temperature-controller-thermometer-thermo-controller/32668879552.html?spm=2114.13010608.0.0.m3JsKa) готовыми модулями. Настройки очень простые - есть все необходимое (подстройка реальной температуры,установка гистерезиса температуры, отложенный старт до 10 минут по достижению заданной температуры...). Провод датчика по желанию можно удлиннить ( попадаются с разной длинной- от 30см до 1м).
Размер платы небольшой. Поскольку реле зимой работают не совсем адекватно и коммутирую в основном линию "АСС" релюшку заменил твердотельным реле AQY212SX (http://www.farnell.com/datasheets/1736855.pdf)
Потребление при выключенном канале 18 мА.


https://youtu.be/YKvTJjlUa5w
YKvTJjlUa5w

Alex-L
24.03.2017, 00:16
Для нового проекта был разработан и изготовлен металический корпус (выражаю благодарность Alex-L за отличную работу- корпус это его заслуга).
Да не за что :)
Спасибо :)
А в боковых стенках зачем отверстия?
По проекту - круто! Выглядит очень солидно!
Одно из требований было - жесткость стыковки встык верхней крышки с отгибом передней панели. Вроде там никакой физической нагрузки не должно быть - судя по фото.

p.s. Все-таки красиво выглядят красивые вещи! А точная механика, точно сделанная - в особенности! :)

ВладимирC
24.03.2017, 00:54
Тоже получаю эстетическое удовольствие , заглядывая в эту тему

skanch
24.03.2017, 04:37
А в боковых стенках зачем отверстия?


В другом проекте линейные подшипники стоят на боковых стенках - используется съемный планшет в жестком кофре + беспроводная подзарядка и толщина увелилилась.

Корпус получился очень прочный! Передняя декаративная панель с откидывающейся крышкой добавит еще жесткости для верхнего стыка. Alex-L - твой вариант со стыковочной планкой работает отлично!
Благодарю за оценку рукотворчества!

http://www.pccar.ru/attachment.php?attachmentid=43208&d=1459098560

http://www.pccar.ru/attachment.php?attachmentid=43207&d=1459098560

https://cdn.media.zagg.com/media/zagg/images/products/keyboards/rugged-folio/apple-ipad-air/specs-zagg-rugged-folio-ipad-air-protection-construction-layers.png

skanch
24.03.2017, 19:14
Питание планшета организовано через распределитель (http://www.pccar.ru/showthread.php?t=25628).
Это доработанная версия - добавил керамику в обвязку смарт-ключей (http://www.pccar.ru/showthread.php?t=25468) и стабиллизатора +5В, изменил немного схему модуля (http://www.pccar.ru/showthread.php?t=25712) отслеживания напряжения на АКБ (по этой схеме работает гораздо стабильнее ).
Включение/выключение планшета по нажатию кнопки (после "жесткого" отключения или если выключился по причине разряда АКБ - программно реализовано длительное нажатие кнопки для включения планшета). Пока тестирую...

skanch
27.03.2017, 10:40
Если кто знает подскажите, пожалуйста, где на контроллере батареи в Lenovo TAB2 8 терморезистор?

basurman
27.03.2017, 11:34
TH, однако.

skanch
27.03.2017, 11:45
TH, однако.
Благодарю!

Роман Языков
29.03.2017, 09:42
Благодарю!
Таким людям памятники ставить нужно.