Внимание - много текста
Задумал поставить управление мышкой в подрулевой переключатель.
У меня ВАЗ-2111 с подрулевым от Калины (Приоры, Шеви-Нивы).
Правый подрулевой переключатель пустотелый, легко разбирается.
Решил туда воткнуть маленький трекбол.
Далее излагаю по порядку.
Для реализации проекта приобрел:
- Arduino Pro Micro;
- Трекбол от BlackBerry Bold 9000.
Выбор обусловлен тем, что оба компонента очень компактны. Arduino Pro Micro умеет прикидываться HID мышкой.
Плата (и корпус) трекбола с 4-мя датчиками Холла и кнопкой, с выводами для пайки (Размеры 16мм х 12мм).
К нему шарик с магнитами на осях (можно выбирать цвет:желтый, синий, розовый, черный, зеленый, оранжевый, фиолетовый)
И все это накрывается крышкой.
И вот тут я уперся в скетч.
Пытался использовать стандартный Button Mouse Control из примеров с офф. сайта.
С кнопками все замечательно работает - курсор мыши ползает, меня устраивает. Правда нет правой кнопки (а она удобна и под Win и под Android). Ну да ничего, решаемо.
Дальше вместо 4х кнопок подключил трекбол (схему подглядел на Sparkfun)
Подключил так (кликабельно):
Все прекрасно, курсор ползает в нужных направлениях, все хорошо.
Кроме того, что иногда, после того как перестаешь крутить шарик, курсор мыши продолжает ползти в последнем направлении.
Начал разбираться почему.
Однозначно проблема в Механизме трекбола и Датчиках Холла (далее ДХ).
Вот Datasheet на датчики - ссылка.
Вот так работает механизм трекбола (вид сбоку):
Шар не крутится, он поджат снизу пружиной (красная) к крышке трекбола.
Магнитные поля осевых магнитов направлены перпендикулярно ДХ. С ДХ нет никаких сигналов на Arduino. Курсор мыши неподвижен.
Начинаем пальцем вращать шар вправо.
Шар смещается и прижимается к оси RIGHT, начиная вращать ее (и магнит) относительно ДХ.
При изменении направления магнитного поля Датчик Холла выдает "1", Arduino её видит и курсор мыши движется вправо.
Если продолжить вращение, то за один оборот шара, ось (и магнит) провернутся 9 раз (т.е. на 360° шара - 9 оборотов оси).
Проскочит 9 раз "1" и курсор продвинется дальше.
Убираем палец, прекращая вращение. Шар отводится пружиной от оси прекращая ее вращение.
"1" перестают поступать на вход Arduino, курсор мыши остановился. Это в идеале.
Однако в реальности, после того как шар перестал крутить ось, магнит может остаться в положении,
когда датчик постоянно выдает "1". На рисунке видно, что ось (и магнит) справа осталась повернута перпендикулярно относительно исходного положения.
Соответственно Arduino видит постоянно "1" на своем порту и курсор мыши ползет по экрану.
Такая ситуаци может быть и сразу после включения мыши. И после загрузки курсор мыши начинает свое "независимое путешествие" в одном ей известном направлении.
Получается, что Arduino надо реагировать не на высокий уровень на входе, а на фронт импульса или на изменение логического состояния входа. Если состояние входа статично, постоянно "0" или "1", то контроллер должен это игнорировать.
Как сделать этакий программный XOR, дополнить скетч, я пока понять не могу. Если у кого есть мысли на этот счет - прошу поделиться, буду крайне признателен.
Сейчас скетч выглядит так (кнопки работают, добавлена правая клавиша мыши):
Код:
// set pin numbers for the five input:
const int upButton = 2;
const int downButton = 5;
const int leftButton = 4;
const int rightButton = 3;
const int mouseButton = 6;
const int mouseRightButton = 7;
int range = 1; // output range of X or Y movement; affects movement speed
int responseDelay = 20; // response delay of the mouse, in ms
void setup() {
// initialize the buttons' inputs:
pinMode(upButton, INPUT);
pinMode(downButton, INPUT);
pinMode(leftButton, INPUT);
pinMode(rightButton, INPUT);
pinMode(mouseButton, INPUT);
pinMode(mouseRightButton, INPUT);
// initialize mouse control:
Mouse.begin();
}
void loop() {
// read the buttons:
int upState = digitalRead(upButton);
int downState = digitalRead(downButton);
int rightState = digitalRead(rightButton);
int leftState = digitalRead(leftButton);
int clickState = digitalRead(mouseButton);
int mouseRightState = digitalRead(mouseRightButton);
// calculate the movement distance based on the button states:
int xDistance = (rightState - leftState) * range;
int yDistance = (downState - upState) * range;
// if X or Y is non-zero, move:
if ((xDistance != 0) || (yDistance != 0)) {
Mouse.move(xDistance, yDistance, 0);
}
// if the mouse button is pressed:
if (clickState == HIGH) {
// if the mouse is not pressed, press it:
if (!Mouse.isPressed(MOUSE_LEFT)) {
Mouse.press(MOUSE_LEFT);
}
}
// else the mouse button is not pressed:
else {
// if the mouse is pressed, release it:
if (Mouse.isPressed(MOUSE_LEFT)) {
Mouse.release(MOUSE_LEFT);
}
}
// if the mouse button is pressed:
if (mouseRightState == HIGH) {
// if the mouse is not pressed, press it:
if (!Mouse.isPressed(MOUSE_RIGHT)) {
Mouse.press(MOUSE_RIGHT);
}
}
// else the mouse button is not pressed:
else {
// if the mouse is pressed, release it:
if (Mouse.isPressed(MOUSE_RIGHT)) {
Mouse.release(MOUSE_RIGHT);
}
}
// a delay so the mouse doesn't move too fast:
delay(responseDelay);
}
Прошу прощения за обилие текста. Реально уперся в скетч, нужна помощь опытных коллег.