- PVSM.RU - https://www.pvsm.ru -
Всем привет. Любому автопилоту, очевидно, нужно не только принимать решения по управлению, но и заставлять автомобиль этим решениям подчиняться. Сегодня увидим, как весьма доступными средствами доработать обычный автомобиль полностью электронным рулевым управлением (steer-by-wire). Оказывается, сам авто для разработки не очень и нужен, а большинство функционала можно с комфортом отлаживать дома или в офисе. В главных ролях всем известные компоненты из хобби-магазинов электроники.
Задумаемся на секунду, что нужно для системы электронного управления? Сервопривод, который может поворачивать колёса, и контроллер, чтобы сервоприводом управлять. Внезапно, всё это в большинстве современных автомобилей уже есть, и называется "усилитель рулевого управления". Традиционные чисто механические (как правило, гидравлические) усилители стремительно исчезают с рынка, уступая место узлам с электронным блоком управления (ЭБУ). А значит, задача сразу упрощается: нам остается только "уговорить" имеющийся ЭБУ усилителя выдать нужные команды на сервопривод.
Очень удобным для доработки оказался KIA Cee'd начиная с 2015 модельного года (скорее всего аналогично и его соплатформенники от KIA/Hyundai). Сошлись одновременно несколько факторов:
Итак, получена в распоряжение рулевая колонка в сборе:
Будем заставлять её крутиться. Для этого нужно создать у блока управления впечатление, что
Пойдем по порядку.
Нужно понять интерфейс между электронным блоком управления (ЭБУ) усилителя и остальным автомобилем. Нагуглив электрическую схему [5] видим картинку:
Из схемы видно, что физически интерфейс очень прост:
Внешний вид и распиновки разъемов находим на том же сайте.
С питанием и зажиганием всё просто, берем 12V с обычного компьютерного блока питания. Но если просто подать питание и зажигание, усилитель полноценно не включится, и усиливать не будет. Дополнительно нужна информация от других блоков автомобиля: работает ли двигатель (чтобы не тратить энергию аккумулятора при выключенном), текущая скорость (чтобы делать руль "тяжелее" на скорости), наверняка что-то ещё.
Обмен данными между электронными блоками в современных автомобилях организован по шинам CAN (Controller Area Network) [6]. Это широковещательная (у пакетов нет адресов назначения) локальная сеть на витой паре, где каждый блок может публиковать свои данные. У каждого типа данных свой идентификатор. Например, в нашем случае усилитель руля рассылает значения угла поворота руля с ID 0x2B0. Часто бывает несколько физически разделенных шин, чтобы второстепенные блоки типа контроллеров стеклоподъемников не мешались обмену между критически важными компонентами. В Cee'd используется две шины: C-CAN и B-CAN (схема здесь [7], в части "Информация о канале передачи данных"). На C-CAN "висят" почти все блоки с ней и будем работать.
Первым делом понадобится CAN интерфейс для компьютера. Детальный обзор возможных решений есть например здесь [8], цены варьируются от десятков до сотен долларов. По устройствам у нас относительно доступны:
Софта разного тоже много (за обзором опять сюда [8]). Самый простой вариант — Linux c can-utils
из SocketCAN [14], за который спасибо инженерам Volkswagen. Большой плюс SocketCAN в стандартизации — любое USB устройство с поддержкой протокола LAWICEL (pdf) [15] видится системой как обычный сетевой интерфейс. Таким образом избегаем привязки к вендор-специфическому софту конкретного устройства. У текущей версии CANHacker есть небольшая несовместимость со стоковыми can-utils по работе с USB, поэтому берём патченную версию отсюда [16]. Raspberry Pi с CAN шилдом работает со стоковым пакетом can-utils из Raspbian OS без проблем.
С подключением к индивидуальному узлу на стенде всё просто: соединяем контакт CAN-High адаптера с CAN-High автомобильного узла, CAN-Low — c CAN-Low. По стандарту между CAN-High и CAN-Low должно быть 2 замыкающих резистора по 120 Ом, на практике обычно всё работает на довольно широком интервале сопротивлений, у меня например одно на 110 Ом.
На автомобиле замыкающий резистор не нужен (они там уже стоят, чтобы шина сама по себе работала). В зависимости от модели авто, возможно придется повозиться с физическим доступом к проводке шины. Самый удобный вариант — разъём OBD-II (on-board diagnostic) [17], он обязателен на всех легковых автомобилях, выпущенных в Европе с начиная 2001-2004 года и находится не дальше 60 см от рулевого колеса. На Cee'd разъём слева под рулём, за пластмасовой крышкой блока предохранителей.
Распиновка OBD-II стандартизована и включает шину CAN (CANH на 6 контакте, CANL на 14). Нам повезло, корейцы пошли по пути наименьшего сопротивления и вывели C-CAN, на которой висят все важные узлы, прямо на диагностический разъём:
В результате на Cee'd можно прослушать весь внутренний трафик, ничего в авто не разбирая. Когда машина не твоя, а знакомые пустили повозиться — большой плюс. Но такая халява не везде. У Volkswagen например служебная CAN изолирована от OBD шлюзом, поэтому подключаться пришлось бы примерно так:
Подключив все контакты, поднимаем сетевой интерфейс:
$ sudo slcand -o -c -s6 -S 115200 ttyACM0 slcan0 && sleep 1 && sudo ifconfig slcan0 up
Проверяем, что сеть работает и данные принимаются (включив зажигание):
$ cansniffer slcan0
И наконец, если всё нормально, можно записывать лог:
$ candump -L slcan0 > real-car-can-log.txt
Здесь нужно запустить двигатель, т.к. усилитель руля включается на собственно усиление только при работающем двигателе, а нам на стенде надо, чтобы он усиливал.
С записанным логом с авто можно возвращаться на стенд и приступать к обману нашего одинокого усилителя. Первым делом вспомним, что в автомобиле стоит свой собственный усилитель, он тоже шлёт данные в CAN шину, и эти пакеты есть и в нашем логе. Отфильтруем их, чтобы избежать конфликтов. Подключаемся к усилителю на стенде, смотрим, что он выдает:
$ $ candump slcan0
slcan0 2B0 [5] 00 00 00 00 00
slcan0 2B0 [5] FF 7F FF 06 F1
slcan0 2B0 [5] FF 7F FF 06 C2
slcan0 2B0 [5] FF 7F FF 06 D3
slcan0 2B0 [5] FF 7F FF 06 A4
slcan0 2B0 [5] FF 7F FF 06 B5
slcan0 2B0 [5] FF 7F FF 06 86
slcan0 2B0 [5] FF 7F FF 06 97
slcan0 2B0 [5] FF 7F FF 06 68
slcan0 5E4 [3] 00 00 00
slcan0 2B0 [5] FF 7F FF 06 79
slcan0 2B0 [5] FF 7F FF 06 4A
....
Видим, что рассылаются пакеты 2B0
(текущий угол поворота руля) и, реже, 5E4
(какой-то общий статус усилителя). Отфильтровываем их из общего лога:
$ cat real-car-can-log.txt | grep -v ' 2B0' | grep -v ' 5E4 ' > can-log-no-steering.txt
Фильтрованный лог можно подавать на воспроизведение:
% sudo ifconfig slcan0 txqueuelen 1000
$ canplayer -I can-log-no-steering.txt
Если всё сработало успешно, усилитель заработает, крутить рукой рулевой вал станет гораздо легче. Итак, работать в штатном режиме мы узел заставили, можно переходить к симуляции усилий на руле.
Крутящий момент на рулевом валу и угол поворота измеряются встроенным блоком датчиков, от которого идет жгут проводов к блоку управления усилителем:
Блок управления обрабатывает сигналы датчиков и выдаёт команды сервоприводу на создание дополнительного усилия на поворот рулевого вала.
По информации PolySync [18], на Soul, у которого с Cee'd общая платформа, два аналоговых датчика крутящего момента. Cигнал каждого — отклонение уровня постоянного напряжения от базовых 2.5V, провода в жгуте — зеленый и синий. Проверим, что у нас то же самое:
Переходим к эмуляции сигнала датчиков. Для этого поставим свой модуль в разрыв цепи между датиком и ЭБУ, будем транслировать настоящий сигнал с датчика и по команде сдвигать его на фиксированный уровень (изображая приложенное к рулевой колонке усилие). Силами одной arduino это не получится: там нет полноценного цифро-аналогового преобразователя, который мог бы выдавать постоянное напряжение. Аналоговые входы arduino нам тоже не очень подходят — хотя пинов для них целых 6, канал АЦП в контроллере только один, и его переключение между пинами занимает заметное время.
Нужно добавить к arduino внешние ЦАП/АЦП. Мне попались модули YL-40 (описание в pdf [20]) на основе чипа PCF8591 [21] — на каждой по 4 канала 8-бит АЦП и 1 8-бит ЦАП. Модуль может общаться с arduino по протоколу I2C [22]. Потребуется небольшое допиливание (в буквальном смысле): китайские товарищи поставили на плату светодиод индикации напряжения на выходе ЦАП — его обязательно надо отсоединить. Иначе утекающий через диод ток не даст ЦАП поднять напряжение на выходе больше 4.2V (вместо штатных 5V). Диод отсоединяем, отковыривая резистор R4 с обратной стороны платы.
Также на входы распаяны игрушечные нагрузки (терморезистор, фоторезистор, ещё что-то), отсоединяем их, убирая перемычки, чтобы не мешались.
С интерфейсом к arduino есть нюанс — нам нужно 2 канала ЦАП, соотвественно 2 модуля, но у них одинаковые адреса I2C (зашиты в чип). Хотя чип позволяет менять свой I2C адрес, замыкая определенные ноги на +5V вместо земли, на плате эти перемычки не разведены. Вместо перепайки возьмем костыль — две разные библиотеки I2C на arduino (стандартная Wire и SoftI2CMaster [23]), каждая на свою пару пинов. Получаем модули на разных шинах, конфликт пропадает.
Остальное прямолинейно — ставим модули в разрыв цепи от датчиков, соединяем с arduino, загружаем скетч [24]. Подробности по распиновке подключения есть в комментариях в скетче. Остается включить всё в сборе, здесь важна последовательность:
l
и r
через Serial Monitor усилитель будет поворачивать рулевой вал. Объявляется победа. На сегодня всё, на очереди доработка софта (интеграция с CAN шиной, чтение оттуда текущего угла поворота и динамическое управление крутящим усилием, чтобы внешний контроллер мог задать фиксированный угол поворота руля и система его выдерживала), отработка на автомобиле (на стенде не смоделируешь сопротивление от колёс). Возможно замена 8-битных ЦАП/АЦП на 10 или 12 бит (взял первое, что под руку попалось). Рулящая нейросеть тоже в процессе, надеюсь скоро сделать пост.
Спасибо Artemka86 [13] за ценные консультации по работе с CAN и помощь с оборудованием.
Прежде всего, внимание, CAN шилд и raspberry pi нельзя соединять напрямую, они не совместимы по напряжению. На Arduino UNO-совместимых платах напряжение логики 5V, а на raspberry pi только 3.3V, поэтому прямое соединение только сожжет задействованные пины.
Нам понадобятся:
Нужно завести на CAN шилд питание (5V), соединения интерфейса данных SPI [31] (4 пина: MOSI, MISO, SCLK, CS) и 1 пин сигнала прерывания. Всё, кроме питания, идет через преобразователь уровня, который в свою очередь тоже надо запитать.
На схемах ищем нужные пины.
Raspberry Pi:
CAN шилд:
Получаем результат:
Соединяем через преобразователь, заводим нужные напряжения питания на каждую сторону преобразователя, получается такая лапша:
Всё, кроме 5V питания и земли на шилд идёт через преобразователь:
Переходим к настройке софта (стандартный Raspbian).
Включаем поддержку SPI и CAN модуля. В /boot/config.txt
добавляем
dtparam=spi=on
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25,spimaxfrequency=1000000
dtoverlay=spi0-hw-cs
Здесь interrupt=25
указывает пин, на который заведено прерывание с шилда. Индексация идёт по GPIO пинам, поэтому interrupt=25
это GPIO 25, он же пин 22 по сквозной индексации всех пинов. Также важно указать частоту интерфейса SPI spimaxfrequency
, т.к. значение по умолчанию — 10 МГц — слишком высокое для шилда, он просто не соединится.
Перезагружаем raspberry pi, проверяем соединение с шилдом:
$ dmesg
...
[ 12.985754] CAN device driver interface
[ 13.014774] mcp251x spi0.0 can0: MCP2515 successfully initialized.
...
Устанавливаем can-utils
:
$ sudo apt install can-utils
Запускаем виртуальный сетевой интерфейс:
$ sudo /sbin/ip link set can0 up type can bitrate 500000
$ sudo ifconfig can0 txqueuelen 1000
Вторая команда важна при воспроизведении большого количества данных с raspberry pi, то есть когда записанный на автомобиле полный лог CAN шины воспоизводим для изолированного узла на стенде. Без увеличения буфера он скорее всего переполнится, когда в логе встретится несколько CAN пакетов с маленькими интервалами, и тогда соединение зависнет.
candump
, cansniffer
и всем остальным из can-utils
.Автор: waiwnf
Источник [32]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie-mikrokontrollerov/264115
Ссылки в тексте:
[1] PolySync: https://polysync.io/
[2] платформы для беспилотников: http://oscc.io/
[3] их гитхабе: https://github.com/PolySync/OSCC
[4] много полезного: https://github.com/PolySync/OSCC/wiki
[5] электрическую схему: http://kiaceed2.ru/html/elektrousilitel.html
[6] CAN (Controller Area Network): https://ru.wikipedia.org/wiki/Controller_Area_Network
[7] схема здесь: http://kiaceed2.ru/html/hod-ogni.html
[8] есть например здесь: https://makezine.com/2016/04/08/car-hacking-tools-trade/
[9] в сборе с алиэкспресса: https://ru.aliexpress.com/item/usb-to-serial-adapter-can-USB-to-CAN-CAN-CAN-turn-turn-CAN-232-to-232/32425298401.html
[10] дизайна от seeed: http://wiki.seeed.cc/CAN-BUS_Shield_V1.2/
[11] подробная инструкция: #rpi-can-shield-connection
[12] CANHacker Baby: http://canhacker.ru/%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D1%8B/can-hacker-baby/
[13] Artemka86: https://habrahabr.ru/users/artemka86/
[14] SocketCAN: https://en.wikipedia.org/wiki/SocketCAN
[15] протокола LAWICEL (pdf): http://www.can232.com/docs/can232_v3.pdf
[16] патченную версию отсюда: https://github.com/waiwnf/can-utils
[17] OBD-II (on-board diagnostic): https://en.wikipedia.org/wiki/On-board_diagnostics#OBD-II
[18] информации PolySync: https://github.com/PolySync/oscc/wiki/Steering
[19] скетч: https://github.com/waiwnf/pilotguru/tree/master/sketches/voltmeter
[20] описание в pdf: http://imrad.com.ua/userdata/modules/wproducts/wprod_products/135743/Arduino%20YL-40.pdf
[21] PCF8591: https://www.nxp.com/docs/en/data-sheet/PCF8591.pdf
[22] протоколу I2C: https://ru.wikipedia.org/wiki/I%C2%B2C
[23] SoftI2CMaster: https://github.com/felias-fogg/SoftI2CMaster
[24] скетч: https://github.com/waiwnf/pilotguru/tree/master/sketches/steering-fixed-torque
[25] Car Hacking: The definitive source: http://illmatics.com/carhacking.html
[26] Car Hacking for Poories: http://illmatics.com/car_hacking_poories.pdf
[27] The Car Hacker's Handbook: A Guide for the Penetration Tester: http://opengarages.org/handbook/ebook/
[28] MCD Software: http://opengarages.org/index.php/MCD_software
[29] Open Source Car Control: https://github.com/PolySync/OSCC/
[30] попался этот: https://tpai.ru/preobrazovateli-elektricheskogo-toka/344-preobrazovateli-elektricheskogo-toka-universalnyy-dvunapravlennyy-8-mi-kanalnyy-preobrazovatel-urovney-33v-5v-spi-i2c-uart-i-dr-.html
[31] интерфейса данных SPI: https://ru.wikipedia.org/wiki/Serial_Peripheral_Interface
[32] Источник: https://habrahabr.ru/post/338322/
Нажмите здесь для печати.