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

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

Короче, решил я подойти к делу технически и оборудовать гараж измерителем расстояния до машины и установить его на стене.
На Али были куплены крупные дисплеи и ультразвуковой измеритель расстояния.
Для начала на Ардуино был поставлен 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 у вас вся спина белая! И до встречи на дорогах.
Добавить в избранное +112 +156
+
avatar
+63
И до встречи на дорогах.
Звучит как-то пугающе…
+
avatar
  • sdivt
  • 01 апреля 2023, 09:17
+15
«Звучит как-то пугающе… » ©
особенно на фоне вступительной части:
«В результате болезни изображение в глазах у меня стало двоиться» ))

Надеюсь, это тоже относиться к 1 апреля)
+
avatar
  • Utopian
  • 01 апреля 2023, 09:02
+1
И до встречи на дорогах
Простите, вы к нам, или мы к вам?))
С 1 апреля…
+
avatar
+3
Лучше бы ни вы в нас и не мы в вас.
+
avatar
  • albus
  • 01 апреля 2023, 09:02
+15
Первое апреля, не первое апреля, но крайне хотелось бы знать где ездит автор.
+
avatar
  • He1ix
  • 01 апреля 2023, 09:19
+2
И где он такую траву берет…
+
avatar
  • Esculap
  • 01 апреля 2023, 09:47
+8
В Финляндии.
+
avatar
+8
Сначала не понял, как в доску удалось засунуть датчик и питание, потом дошло — доска просто заменила электронику. Сам использую два обрезка 60-ки в качестве упора задних колес. Иначе стеллаж сзади упирается в багажник, потому что его в зеркала плохо видно (машину ВСЕГДА загоняю задом!).
За первоапрельский обзор плюс!
+
avatar
  • art808
  • 01 апреля 2023, 09:30
+14
Известный трюк с теннисным мячиком, подвешенным на веревке на уровне середины заднего стекла.
+
avatar
  • smim
  • 01 апреля 2023, 09:13
+2
иногда задеваю зеркалами о проем, видимо, нужно какой-то лазерный гаражный прицел ставить
Два направляющих бруса вдоль хода колес, перпендикулярно
обрезоку доски
думаю заменят
лазерный гаражный прицел
Про бруски, шутка. С 1 апреля.
+
avatar
  • sdivt
  • 01 апреля 2023, 09:15
+2
Отличная концовка!
И да, с первым апреля)
+
avatar
  • Alax
  • 01 апреля 2023, 09:24
-6
+
avatar
+15
Эта часть, к сожалению, совсем не шутки.
+
avatar
+21
Те, кто читает Ваши обзоры в курсе. Здоровья Вам.
+
avatar
+3
Ммм, магическое мышление, сладенько
+
avatar
  • maxik
  • 01 апреля 2023, 23:17
+1
Ничего не понимаете, один мой друг всегда ржал, хватался за живот и кричал «умру»

Он не умер, но видит бог, рано, или поздно может накликать
+
avatar
0
Хм. До брусков я сам додумался, но если машину в гараж ставить не на стоянку, а и для проведения различных работ, ставить её нужно в разные места, подальше, поближе, задом-передом, а с покупкой более крупной машины подложенные доски перестают читаться на фоне неровностей гаража.
Хотя можно купить парктроник и прикрутить его к стене гаража, они по 1000 сейчас стоят.
+
avatar
  • smim
  • 01 апреля 2023, 09:29
0
Про бруски, шутка. С 1 апреля.
+
avatar
  • Alax
  • 01 апреля 2023, 09:35
+4
Почему шутка? На парковках некоторых торговых центров есть такие бруски (вернее, металлические барьеры) — с ними удобнее парковаться.
+
avatar
+1
Никаких шуток, дело серьезное. Я сам видел в гараже такие бруски прибитые, чтобы машина не вкатывалась дальше, чем нужно. Так же, без шуток, я говорю, что у меня лежит в гараже досочка, в которую я стараюсь вкатываться, но, бывает даже доска мне не преграда и далее стоящий мангал получает пробитие бампером.
+
avatar
+2
мангал получает пробитие бампером
Хуже, если наоборот.
+
avatar
  • SEM
  • 01 апреля 2023, 10:59
+1
На Али есть лазерные модули (как в лазерных указках) с светорассеивателями, дающими линию или крест. Прикрепите такой модуль к потолку и смотрите на линии на капоте. Например в нужном положении авто линия будет проходить по форсункам омывателя лобового стекла.
+
avatar
+1
Есть готовые именно для гаража. Погуглите goodchief. Ну или на ali по laser parking
+
avatar
0
шутки шутками, но если есть противопоказания по здоровью — зачем испытывать судьбу?
+
avatar
+9
одноглазым ездить не запрещено, а инвалидные общественные парковки в полтора раза шире обычных. И есть места в мире, где без машины тяжело — без посторонней помощи даже за продуктами не доберешься. И врачи контролируют — если есть риск по их мнению — прав враз лишишься.
Я несколько раз видел инвалидов-колясочников за рулем, иногда машина оборудована специальным краном (снаружи не виден), который коляску вытаскивает из машины и ставит рядом с водительским сиденьем).
+
avatar
  • Delanet
  • 01 апреля 2023, 12:44
0
Шампанского хочется…
+
avatar
0
Спасибо, почему-то не знал о их существовании. Надо будет взять. То, что доктор прописал :)
+
avatar
  • DVANru
  • 01 апреля 2023, 13:17
0
+
avatar
+1
Чаше улыбайтесь!
С 1 Апреля всех !MYSKU
+
avatar
  • t2k
  • 01 апреля 2023, 19:09
0
Джентльмены, у меня есть отличный план! :))
+
avatar
0
Можно и зеркало или два зеркала от грузовика (автобуса) в гараже на стене закрепить для облегчения правильного заезда в гараж, чтобы их хорошо было видно с водительского места и они очень помогают при узких воротах или маленьком гараже, и упоры для колес, чтоб стену не сдвинуть)
+
avatar
0
«Надёжно! Добротно! Хорошо!» — и никаких тебе циклов вообще.
А что на самом деле делает этот код? Потому что, если надо перевернуть биты в байте, в AVR проще всего использовать lookup table:
	// X = data address
	ldi	ZH, high(ReverseTable)
	ld	ZL, X
	lpm	ZL, Z
	st	X+, ZL
	ld	ZL, X
	lpm	ZL, Z
	st	X+, ZL
	...
+
avatar
  • OreSama
  • 01 апреля 2023, 15:09
0
Потому что, если надо перевернуть биты в байте, в AVR проще всего использовать lookup table
Но таблица на 256 байт может оказаться слишком расточительной для контроллера. Если тот же процесс переворота выполнять полубайтами, можно обойтись 16-байтовой таблицей. Правда, будет несколько медленнее.
+
avatar
0
Но таблица на 256 байт может оказаться слишком расточительной для контроллера
Может. Но сейчас из AVR, наверное, если массово пишут, то только под 328р, а у неё 32 КБ и 256 байт — это меньше 1% объема. А вот с быстродействием (по современным меркам) у AVR не очень. Прежде всего из-за разрядности.
+
avatar
+1
Транспонирование матрицы 8х8. Но в случае AVR использование такого кода является бредом сивой кобылы, так как этот код заточен под 32х битные процессоры. Для 8-ми битного AVR транспонирование матрицы куда быстрее и проще делать через банальные циклы.
PS: да, матрица битовая, поэтому там не просто транспонирование — каждый выходной байт собирается из соответствующих битов 8-ми входных байт
+
avatar
0
Транспонирование матрицы 8х8
Спасибо. Интересно.
Но в случае AVR использование такого кода является бредом сивой кобылы
Полностью согласен. Да и gcc очень плохо оптимизирует всякие там сдвиги — может для сдвига на 7 разрядов влепить цикл из 7 итераций (хотя, можно сдвинуть на 1 в другую сторону).
Для 8-ми битного AVR транспонирование матрицы куда быстрее и проще делать через банальные циклы
Сходу предположу, что самым быстрым вариантом будет 56 команд BST и 56 команд BLD — 112 тактов и 224 байта ПЗУ.
+
avatar
0
Да смысла нет — экономия ресурсов смешная. Тем более лезть в ассемблер ради такой фигни.
uint8_t mask_out = 1;
for (uint8_t i = 0; i < 8; i++) {
	out[i] = 0;
	uint8_t mask_in = 1;
	for (uint8_t j = 0; j < 8; j++) {
		if (in[j] & mask_in) out[i] |= mask_out;
		mask_in <<= 1;
	}
	mask_out <<= 1;
}
PS: в реальности этой проблемы вообще нет, так как современный модули на max7219 строго квадратные и сделаны именно под соединение в строку. Никакое транспонирование матрицы там не нужно
+
avatar
0
Тем более лезть в ассемблер ради такой фигни.
У меня в AVR без ассембплера не получается :) Как посмотрю, что за код генерирует gcc, хочется плакать. Раньше вообще писал для AVR исключительно на асме — он тут простой.
+
avatar
  • islera
  • 01 апреля 2023, 16:01
+2
Еще одна проблема, правда, так и осталась нерешенной — я иногда задеваю зеркалами о проем
Ну, проблема то стара как мир и её решение давно найдено — это колея:
+
avatar
  • Glabus
  • 01 апреля 2023, 16:07
+1
Еще одна проблема, правда, так и осталась нерешенной — я иногда задеваю зеркалами о проем, видимо, нужно какой-то лазерный гаражный прицел ставить.
Можно две надувные куклы по бокам поставить у въезда в гараж. И высматривать въезд будет приятнее и зеркала будут пружинить :D
+
avatar
  • Skylab
  • 01 апреля 2023, 17:02
+3
Лучше живую доску, чем резиновую бабу )
+
avatar
+6
это все хорошо, но зачем так сложно?!!! Ведь измерение расстояние вам не надо, главное не уехать дальше какой то метки. Для этого есть трюк с веревкой и тенисным мячём. Никахи тебе ардуино, прошивок и электричества. Из-за таких как вы, мы скоро прошивки и в утюгах обновлять будем!!! У вас спина белая.

+
avatar
  • ewavr
  • 01 апреля 2023, 20:48
+5
Зато дальномер подходит для любой машины без настройки.

П.С. Помню, в далеком детстве мама обновляла прошивку моих носков при помощи такого прибора:
+
avatar
+1
Так вот зачем этот деревянный кружочек!!!
+
avatar
  • sav1812
  • 02 апреля 2023, 13:41
+1
Тс-с-с-с-с!.. ;)
+
avatar
+1
Мне давно пришла в голову мысль лазер сверху на приборную панель. Сейчас они есть точка, линия, крест на выбор.
+
avatar
  • Mike212
  • 01 апреля 2023, 19:52
0
И долго этот висячий мяч в пустом гараже провисит?
У самого кирпичи лежат.
+
avatar
0
Для проблемных глаз явно же проще просто увидеть переключение цвета с одного на другой.
+
avatar
  • a1exus
  • 02 апреля 2023, 01:41
+1
Может мячик подвесить так, чтобы он прямо перед глазами висел, когда машина припаркована как надо, а на дальней стене мишень, чтобы при въезде визуально совмещать мячик и мишень. Это если заезжаете передом.
Ну или направляющие вдоль колес.
У меня парктроники, но я внимательно стараюсь смотреть, потому что не зацепиться зеркалом при выезде парктроник не поможет.
+
avatar
  • san_q
  • 04 апреля 2023, 03:52
0
В машине есть парковочная камера и сам парктроник, штатные, но так надежнее!
ЗЫ: Метку на стене делал не я, но с удовольствием пользуюсь.