Как обхитрить тайм трекер при помощи Arduino

от автора

Здравствуйте!
Вся моя семья работает удалённо. Супруга работает в крупной организации, в которой осуществляется мониторинг рабочего времени. Мониторинг реагирует на нажатие кнопок клавиатуры и колесо прокрутки мыши, с таймаутом 5 минут. Жена переболела COVID-19 и после болезни стала сильно уставать во время работы, поэтому позволяет себе небольшие перерывчики. На время этих перерывчиков она просит меня покрутить колесико мыши, но я бывает так увлекусь работой, что забываю это сделать. В связи с этим у меня возникло желание автоматизировать этот процесс.


Я вспомнил что у меня валяется Arduino Leonardo, а его легко запрограммировать на имитацию клавиатуры и мыши. Покопавшись в ящиках нашел его и запрограммировал на имитацию колесика мыши. Но жена меня раскритиковала, так как у них запрещается пользоваться не зарегистрированными USB устройствами (а Arduino обязательно вызовет вопросы). Поэтому было решено крутить колесико мыши механически, для чего был заказан шаговый двигатель 28BYJ-48 в комплекте с драйвером двигателя на микросхеме ULN2003 и взят из другого «пыльного» ящика Arduino Nano.

Рисунок 1. Шаговый двигатель 28BYJ-48 с драйвером на микросхеме ULN2003.
Рисунок 1. Шаговый двигатель 28BYJ-48 с драйвером на микросхеме ULN2003.

Подключил двигатель и кнопку к Arduno, двигатель запитывал как напрямую через Arduino, так и через внешний источник питания. Сейчас двигатель запитывается через Arduino (так меньше проводов висит, а Аrduino это терпит). Написал скетч (как смог) имитирующий прокрутку документа человеком при изучении сложного документа. Прокрутка осуществляется группами то в одну, то в другую сторону через разные промежутки времени. Запустить/остановить процесс скроллинга можно нажатием на кнопку или командами «START», «STOP» переданными по последовательному порту.

Рисунок 2. Схема подключения шагового двигателя (через драйвер) с питанием от Arduino.
Рисунок 2. Схема подключения шагового двигателя (через драйвер) с питанием от Arduino.
Рисунок 3. Схема подключения шагового двигателя (через драйвер) с внешним  питанием.
Рисунок 3. Схема подключения шагового двигателя (через драйвер) с внешним питанием.
#include<AccelStepper.h> #include <SoftwareSerial.h>  #define HALFSTEP 8      // Определение пинов для управления двигателем #define motorPin1  2 // IN1 на 1-м драйвере ULN2003 #define motorPin2  3 // IN2 на 1-м драйвере ULN2003 #define motorPin3  4 // IN3 на 1-м драйвере ULN2003 #define motorPin4  5 // IN4 на 1-м драйвере ULN2003  // Инициализируемся с последовательностью выводов IN1-IN3-IN2-IN4  // для использования AccelStepper с 28BYJ-48 AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4); String str = "START";  const int buttonPin = 12;     // Номер пина кнопки  const int minMaxSpeed = 800; const int maxMaxSpeed = 1300; const int minAcceleration = 500; const int maxAcceleration = 700; const int minSpeed = 700; const int maxSpeed = 1000; const int move = 600; // примерная длина одного перемещения const int minPause = 1; // Минимальная пауза между группами прокруток (секунды) const int maxPause = 3*60; // Максимальная пауза между группами прокруток (секунды)  long pos = 0; int smove = move; int sMaxSpeed = maxMaxSpeed; int sAcceleration = maxAcceleration; int sSpeed = maxSpeed; unsigned msec = 1000; bool PREV = false; int dir = 50; int count = 5;   void setup(){   pinMode(LED_BUILTIN, OUTPUT); // Светодиод (красный) для сигнализации (светит - стоп, не светит - работа)      Serial.begin(9600);   Serial.println("start");     stepper1.setMaxSpeed(sMaxSpeed);   stepper1.setAcceleration(sAcceleration);   stepper1.setSpeed(sSpeed);    pinMode(buttonPin, INPUT_PULLUP); // Настройка кнопки   stepper1.move(move); }  int inputHandler(){ // Чтение команд из порта и отслеживание нажатия кнопки   int res = 0;     if (Serial.available() > 0) {       str=Serial.readString();       str.trim();       Serial.println(">>>>>>>>>>>>>>>>>");       Serial.println(str);       res = 1;     }      buttonState = digitalRead(buttonPin);     if (buttonState == LOW && PREV == HIGH ) {         if (str=="START") {           str = "STOP";           Serial.println("Press button to 'STOP'");           stepper1.move(0);           res = 1;         } else {           str = "START";           Serial.println("Press button to 'START'");           res = 1;         }         delay(150);     }      if (str!="START") {       digitalWrite(LED_BUILTIN, HIGH);     } else {       digitalWrite(LED_BUILTIN, LOW);     }          PREV = buttonState;     return res;      }   int delayWithRead(unsigned ms){ // Пауза с обработкой ввода   Serial.print("Delay = ");   Serial.print(ms);   Serial.println(" msec.");   int time = 0;   while (time<ms) {     delay(100);     if (inputHandler() == 1) {       Serial.println("Press Key");       delay(2000);       return 1;     }     time += 100;   }   return 0; }    void printData(){ // Вывод данных в порт     Serial.print("sMaxSpeed=");     Serial.println(sMaxSpeed);          Serial.print("sAcceleration=");     Serial.println(sAcceleration);      Serial.print("sSpeed=");     Serial.println(sSpeed);      Serial.print("count=");     Serial.println(count);      Serial.print("pos=");     Serial.println(pos);      Serial.print("smove=");     Serial.println(smove); }  void goNewPosition(){ // Обработик перехода на следующую позицию     sMaxSpeed = random(minMaxSpeed, maxMaxSpeed);     sAcceleration = random(minAcceleration, maxAcceleration);     sSpeed = random(minSpeed, maxSpeed);     stepper1.setMaxSpeed(sMaxSpeed);     stepper1.setAcceleration(sAcceleration);     stepper1.setSpeed(sSpeed);     msec = random(100,500); // Пауза между скроллами в одной группе     delayWithRead(msec); // Задержка с обработкой ввода     count--;     if (count<0) {       Serial.println("*************************************");// Разделитель групп скроллов       msec = random(minPause*10,maxPause*10)*100; // Пауза между группами скроллов       delayWithRead(msec);       dir = random(0,100);       count = random(1,5);     } else {       Serial.println("_________________________________________");// Разделитель скроллов в одной группе     }     if (dir<35) { // Скролл назад с вероятностью 35%       smove = 0 - move + (random(move/8) - move/16);     } else {       smove = 0 + move + (random(move/8) - move/16);     }             pos = pos + smove; // Счетчик общего скролла          printData();// Вывод данных в порт      if (pos>100){ // Крутить только если чуть ниже стартовой позиции       stepper1.move(smove); // Задать поворот относительно текущей позиции     }    }   void loop(){ // Основной цикл     inputHandler(); // Обработка ввода     if(stepper1.distanceToGo()==0) { // Если поворот закончили       if (str=="START") goNewPosition(); // Получаем следующую позицию     }      if (str=="START"){ // Если нет команды стоять то       stepper1.run();  // Крутим движок      } }

Из картона сделал футляр для мыши, к которому прикрепил Arduino и двигатель с ведущим колесом которое кладется на колесико мыши и вращает его.

Рисунок 4. Вид гаджета с одной стороны.
Рисунок 4. Вид гаджета с одной стороны.
Рисунок 5. Вид гаджета с другой стороны.
Рисунок 5. Вид гаджета с другой стороны.
Рисунок 6. Гаджет с подопытной мышью:)
Рисунок 6. Гаджет с подопытной мышью:)
Рисунок 7. Мышь в гаджете.
Рисунок 7. Мышь в гаджете.

Как работает устройство можно посмотреть в видео.

 Теперь, когда жене надо отлучиться, она вкладывает мышь в футляр и просто включает этот девайс.


ссылка на оригинал статьи https://habr.com/ru/articles/593697/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *