Товары из Китая

Гаражный парктроник с тактильной обратной связью


Гаражный парктроник с тактильной обратной связью

Эта история случилась уже лет семь тому назад. В результате болезни изображение в глазах у меня стало двоиться и, чтобы как-то оценить обстановку, приходилось закрывать один глаз.

Одно время вообще ходил как пират — с повязкой на глазу. Без нее пользоваться компьютером было вообще нереально. Ни о каком бинокулярном зрении, естественно, речи не было. Загнать машину в гараж — это был просто квест. Летом машину можно и около дома оставить, а в холода лучше бы в гараже держать — откопать ее из под снега или отскрести окна было не реально, кроме зрения проблем хватало. Одно время я вообще передвигался на инвалидной коляске — как можно в таком состоянии машину отрыть?

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

На Али были куплены крупные дисплеи и ультразвуковой измеритель расстояния.

Для начала на Ардуино был поставлен scmRTOS — ну, вы сами понимаете, как же можно что-то делать без операционной системы реального времени?

«Лучше день потерять, потом за пять минут долететь!» — как говаривал один гриф из мультика.

Ну а дальше — «Пошёл! Пошёл! Работаем, работаем, страус, пошёл». Готовых библиотек для MAX7219 сейчас хоть пруд пруди, тогда мне то ли не удалось найти подходящей, то ли они мне просто не понравились.

Там есть одна тонкость — надо было писать подпрограмму для переворота битовой матрицы, если хочется, например, иметь бегущую строку.

Гаражный парктроник с тактильной обратной связьюВ большинстве библиотек это сделано очень тупо и прямолинейно. Сразу видно, люди в детстве хороших книжек не читали и игрушки у них были прибиты к полу гвоздями. Если бы читали «Hacker’s Delight» (я ее на русском тоже видел под менее романтичным названием «Алгоритмические трюки для программистов», если склероз не подводит), очевидно, они бы сделали так:

void MAX7219SPI::ImageRotate()

{
for(int8_t i=0; i<SECTIONS_NUM; i++)
{
// Hacker's Delight
uint32_t x,y,t;
x = (uint32_t)ImageBuff[0+i*8]<<24;
x |= (uint32_t)ImageBuff[1+i*8]<<16;
x |= (uint32_t)ImageBuff[2+i*8]<<8;
x |= ImageBuff[3+i*8];
y = (uint32_t)ImageBuff[4+i*8]<<24;
y |= (uint32_t)ImageBuff[5+i*8]<<16;
y |= (uint32_t)ImageBuff[6+i*8]<<8;
y |= ImageBuff[7+i*8];
t = (x ^ (x>>7)) & 0x00AA00AA;
x = x ^ t ^ (t<<7);
t = (y ^ (y>>7)) & 0x00AA00AA;
y = y ^ t ^ (t<<7);
t = (x ^ (x>>14)) & 0x0000CCCC;
x = x ^ t ^ (t<<14);
t = (y ^ (y>>14)) & 0x0000CCCC;
y = y ^ t ^ (t<<14);
t = (x & 0xF0F0F0F0) | ((y>>4) & 0x0F0F0F0F);
y = ((x<<4) & 0xF0F0F0F0) | (y & 0x0F0F0F0F);
x = t;
LineBuff[0+i*8] = x>>24;
LineBuff[1+i*8] = x>>16;
LineBuff[2+i*8] = x>>8;
LineBuff[3+i*8] = x;
LineBuff[4+i*8] = y>>24;
LineBuff[5+i*8] = y>>16;
LineBuff[6+i*8] = y>>8;
LineBuff[7+i*8] = y;
}
}

«Надёжно! Добротно! Хорошо!» — и никаких тебе циклов вообще. Тот, который для разрядов дисплея — к делу не относится и поэтому не считается.

После этого прикрутить ультразвуковой датчик расстояния — это даже не вопрос. Прерывание и таймер — наше все.

#include "scmRTOS.h"

#include "processes.h"
#include "Arduino.h"
/*
* sonar pins:
* 7 (PD7) trigger
* 8 (PB0) echo
*/
TProc1 Proc1;
OS::channel<uint16_t, 2> SonarTime;
int16_t Distance;
namespace OS
{
template<> void TProc1::exec()
{
tick_count_t next_tick;
tick_count_t current_tick;
DDRD |= 1<<PD7; // TRIG pin
DDRB &= ~(1<<PB0); // ECHO pin
TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS11); // noise canceler, rising edge. 16/8=2Mhz
TCCR1A = 0x00;
next_tick = OS::get_tick_count();
for (;;)
{
uint16_t SensorTime;
TIMSK1 |= 1<<ICIE1; // capture interruption enabled
PORTD |= 1<<PD7; // trigger sonar
OS::sleep(1);
PORTD &= ~(1<<PD7);
SonarTime.pop(SensorTime,200);
Distance=SensorTime/116;
next_tick += 500;
current_tick = OS::get_tick_count();
if (current_tick < next_tick) sleep(next_tick - current_tick);
}
}
}
// sonar ISP
ISR(TIMER1_CAPT_vect)
{
static uint16_t TimerData;
if (TCCR1B & (1<<ICES1))
{
TimerData = ICR1;
TCCR1B &= ~(1<<ICES1); // falling edge
}
else
{
OS::TISRW ISR;
TimerData = ICR1 - TimerData;
TCCR1B |= 1<<ICES1; // rising edge
TIMSK1 &= ~(1<<ICIE1); // interruption disabled
SonarTime.push(TimerData);
}
}

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

Пошел в гараж рассматривать на месте, что и как поставить.

Тут на глаза попался обрезок доски — и вуаля!

Гаражный парктроник с тактильной обратной связьюПроблема мгновенно решена. За прошедшие годы ни разу не понадобилась обновлять прошивку, батареи менять не надо, заряжать ничего не надо. Надежность и удобство пользования просто зашкаливает.

Еще одна проблема, правда, так и осталась нерешенной — я иногда задеваю зеркалами о проем, видимо, нужно какой-то лазерный гаражный прицел ставить.

Извиняюсь, статья почти не иллюстрирована своими фотографиями — они либо не делались, либо давно утеряны. В наличии остались только исходники программного обеспечения и до сих пор валяющиеся без дела модули.

Гаражный парктроник с тактильной обратной связью

P.S. A у вас вся спина белая! И до встречи на дорогах.


СМОТРИ ТАКЖЕ

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

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