Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3 ОБД2

Разработка панели приборов на основе raspberry pi и 7″ дисплея

В качестве аппаратной части я выбрал Raspberry Pi. Была идея использовать Android планшет, но показалось, что на Raspberry Pi будет проще и быстрее. В итоге докупил официальный 7″ дисплей, и сделал CAN шилд из модуля TJA1050 Niren.

OBD2 штекер использовал от старого ELM327 адаптера.

Используются контакты: CAN_L, CAN_H, 12, GND.

Тесты в машине прошли успешно и теперь нужно было все собрать. Плату дисплея, Raspberry Pi и блок питания разместил на куске черного пластика, очень удачно подобрал пластмассовые втулки, с ними ничего не болтается и надежно закреплено.

Местом установки выбрал бардачок на торпедо, которым я не пользуюсь. По примеркам в него как раз помещается весь бутерброд.

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

Что за адаптер elm327? он мне нужен?

[adace-ad id=»5228″]

Диагностический адаптер ELM327 позволяет выполнять диагностику по протоколу стандарта OBDII. Что он может? Во-первых, это сканер ошибок — вы всегда будете знать причину, по которой автомобиль работает не в штатном режиме.

Во-вторых, он может стирать ошибки из памяти блока, что иногда помогает избавиться от мелких, «засевших» неисправностей и погасить лампочку Check Engine. В-третьих, это диагностика в реальном времени.

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

Какой адаптер elm327 купить? правда ли, что версия 2.1 глючит?

[adace-ad id=»5222″]

На Aliexpress несчетное количество вариантов примерно за одну и ту же цену. Мы решили максимально рискнуть и заказать один из самых дешевых вариантов (ссылка). Всего 175 рублей. Забегая вперед, скажем, что работает он отлично, несмотря на то, что это версия 2.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Единственный минус — посылка ехала очень долго — ровно 2 месяца (Республика Коми)

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Can scanner на arduino

Первый прибыл шилд для классической Arduino UNO. Да он стоит значительно дороже своих более мелких собратьев, но он имеет на борту всё необходимое и даже две кнопки.

Именно с ним я и начал все эксперименты. Собрал простую схему с этим шилдом и жидкокристаллическим двухстрочным экраном. Цель была — вывести на экран хоть какие-то данные. Перебирал различные библиотеки для работы с CAN шиной на Arduino (сразу скажу, что правильная и рабочая библиотека называется CAN-BUS Shield by Seeed Studio с заголовочным файлом mcp_can.h), поменял кварцевый резонатор на шилде на 16 МГц (изначально стоял 8 МГц) — данных не было.

На шилде установлены две микросхемы: контроллер CAN шины MCP2515 и драйвер CAN шины TJA1050. Почитав документацию и различные форумы, решил поменять TJA1050 на более каноничный драйвер MCP2551 и данные появились. Возможно TJA1050 была изначально неисправна, так как с её подключением двумя проводками ошибиться было очень сложно, к тому же я использовал OBD и DB9 разъёмы для подключения.

За пару часов был написан простой CAN scanner, который выводил на жидкокристаллический дисплей номер захваченного пакета, его ID и до 8 байтов данных этого пакета.

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


Начало было положено, надо переходить к более интересной реализации.

Can sniffer на arduino

Задача стояла достаточно простая:

С первыми двумя задачами я вообще не видел никаких проблем. Библиотека предоставляла прерывание при приёме очередного пакета данных и удобные функции для получения данных. А вот отправку данных в сторону компьютера решил сделать через библиотеку CyberLib, которая устраняет некоторые накладные расходы всей платформы Arduino, за счёт чего можно немного разгрузить процессор для обработки данных. Позже от этой библиотеки пришлось отказаться.

Для того, чтобы отправляемые данные корректно обрабатывались на стороне компьютера, перед каждой очередной порцией данных в поток вставляется префикс из четырёх байтов 0xAA55AA55 (почему-то вспомнились эти байты по последним двум байтам загрузочного сектора DOS, только они там были в другом порядке). Логика такая:

На этом программная часть в Arduino, на тот момент, была завершена. Позже она была значительно переделана, но общая концепция не поменялась.

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

Примерно в это же время прибыли более миниатюрные компоненты Arduino Nano и Mini CAN shield.


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

Снаружи с одной стороны OBD разъём, с другой — Mini USB. Внутри имеется переключатель для терминирующего резистора.

Can sniffer на pc с использованием wxwidgets

Набросал простую заготовку программы на C#, которая выводит в Grid получаемые данные. И пошёл проверять в автомобиль. Только пошёл не со своим ноутбуком, так как у него батарея давно приказала долго жить и использовался он как стационарный компьютер, а взял нетбук с очень слабым процессором.

То что я увидел… Я ничего не увидел. Оба ядра загружены на 100%, интерфейс приложения не реагирует. Но на моём компьютере, который всё-таки значительно шустрее нетбука, с генератором случайных пакетов приложение нормально работало и отображало данные.

Ранее я в нескольких проектах использовал библиотеку wxWidgets и о ней у меня только приятные впечатления. Она легковесная, нет необходимости тащить с собой различные библиотеки и даже кросс-платформенная, что вселяет надежду, что интерфейсную часть кода можно перенести без значительных переделок на другие платформы. В конце статьи будет ссылка на скомпилированную программу, если возиться со всем этим не будет желания.

Как установить и скомпилировать wxWidgets для Visual Studio

Можно скачать и посмотреть

видео

(менее восьми минут), а можно выполнить 6 шагов по описанию ниже.

Установка и компиляция wxWidgets:

1. Скачать и установить wxWidgets если это установщик, либо распаковать, если это архив

2. Создать переменную окружения WXWIN указывающую на папку, куда установили или распаковали (например C:wxWidgets):

Свойства системы -> Дополнительные параметры системы -> Переменные среды -> Создать
WXWIN = C:wxWidgets

3. Из папки C:wxWidgetsbuildmsw открыть файл решения под соответствующую Visual Studio (wx_vc16.sln для Visual Studio 2021)

4. В Solution Expolorer, с помощью клавиши Shift, выделить все проекты, кроме _custom_build и зайти в Properties проектов.

5. В разделе C/C -> Code Generation изменить параметр Runtime Library:

Для конфигурации Debug выбрать /MTd
Для конфигурации Release выбрать /MT

6. Скомпилировать библиотеки wxWidgets по очереди для Debug и Release конфигураций.

Пробное приложение и настройка проекта в Visual Studio (для проверки)

1. В Visual Studio создать Empty Project с указанием типа приложения Desktop Application (.exe)

2. В окне View -> Property Manager для своего проекта правой кнопкой выбрать меню Add existing property sheet… и выбрать файл:

C:wxWidgetswxwidgets.props

3. Создать файл main.cpp и скопировать в него содержимое файла:

C:wxWidgetssamplesminimalminimal.cpp

4. В настройках проекта C/C -> Code Generation изменить (если пункт не появился — сделать пробную сборку):

Runtime Library для конфигурации Debug: /MTd
Runtime Library для конфигурации Release: /MT

5. Дополнительно, если необходимы привилегии UAC, в разделе Linker -> Manifest File:

UAC Execution Level: requireAdministrator

6. Для добавления иконки exe-файлу надо добавить ресурсный файл со следующим содержимым:

#include «wxmswwx.rc»
wxicon icon app_icon.ico

Код ошибки:  Диагностический разъем Рено

Первый реализованный прототип на C и wxWidgets показал, что даже нетбук справляется с отображением данных в таблице и я приступил к разработке задуманного.

Архитектурно программа состоит из двух потоков: интерфейсный и поток работы с последовательным портом. Никаких невероятно интересных алгоритмов не применялось. Код обильно снабжён комментариями и должен быть довольно понятен. Ссылка на исходники будет в конце статьи.

Первое что было сделано — раскраска ячеек данных в таблице по давности получения этих данных. Уже в первом прототипе, глядя на 17 строк данных меняющихся непрерывно значений, я понял, что надо как-то различать свежие данные и данные, которые не изменяются или меняется редко. Сделал раскраску в два этапа:

Сразу же стало наглядно видно, какие ячейки вообще не используются, какие содержат сигналы счётчиков. Поиск же интересующих изменяющихся значений значительно упрощается. Здесь и далее все изображения анимированные. Если анимация не работает в статье (на некоторых мобильных браузерах) — кликайте по изображению для открытия полной версии анимации.

Далее мне захотелось всё-таки проверить, справляется ли последовательный порт с потоком данных. Для этого я на стороне Arduino добавил счётчики количества принятых пакетов и счетчик байтов в пакете. Эти счётчики отправляются на компьютер в пакете с идентификатором 0x000.

Программа при получении этих данных не выводит их в таблицу, а отображает в отдельных информационных полях сверху. Полученные результаты даже весьма понравились. В среднем принимается до 750 пакетов/с со скоростью до 9,5 кБ/с, а это где в районе до 80 кбит/с, что вполне по силам последовательному порту. Но всё равно, обмен данными настроен по умолчанию на 500 кбит/с, пусть лучше будет запас.

Добавление возможности записи данных в журнал появилось после того, как подключил параллельно к OBD интерфейсу диагностический адаптер ELM327 и связав его с телефоном, попробовал читать различные данные. Данные пробегали настолько быстро, что увидеть их невозможно.

Записав всё это в журнал, можно потом спокойно сесть и посмотреть передаваемые данные. Для этого в журнал могут записываться даже ASCII текстовые данные. Так же можно выбирать тип файла, символ разделитель и настроить фильтр пакетов кликом в таблице по указанному идентификатору пакета и нажатию кнопки «Добавить ID в фильтр» (по умолчанию записываются все данные), если запись всех данных избыточна.

Именно тогда пришло осознание, что все приложения для телефона, которые производят всякую «диагностику» через связку ELM327 и телефон, не общаются напрямую с CAN шиной автомобиля. Они всего лишь используют функционал диагностики OBD через CAN шину посредством обращения к CAN ID 0x7E0.

Обычно это адрес контроллера мотора (ЭБУ), ответ же от него приходит в пакете с идентификатором 0x7E8. А вот все остальные пакеты данных — это так называемый Vendor Specific и ни один производитель так просто их не раскроет (хотя есть пример: Ford выпустил SDK для своих автомобилей).

Продолжая изучать что же передаётся в этих пакетах пришёл к ещё одной идее: при клике на ячейку в таблице, в окне программы справа выводить двоичное и десятичное значение этого байта, а так же брать следующий байт и дополнять до слова. Далее это слово умножать на некий коэффициент и получить десятичный результат.

Звучит не очень понятно, но вот в связи с чем это делалось: обороты мотора приходят в пакете CAN ID 0x180, в первых двух байтах. Эти два байта дают некое слово, которое пропорционально оборотам. Если значение этого слова разделить на 8, то получатся текущие обороты.

Поэтому указывается множитель 0,125, как обратная величина от 8. Далее это слово визуализируется в графике с динамической подстройкой по амплитуде. В принципе, множитель можно искать в обратной последовательности: нашёл ячейки, которые по графику очень похожи на обороты мотора или ещё что-то искомое, после чего подгоняется множитель для получения действительных значений.

Ну а двоичное представление позволяет искать различные битовые индикаторы. Например поиск индикаторов указателей поворота сводится к тому, чтобы включить их и наблюдать какая ячейка начинает изменяться, в примере ниже это CAN ID 0x481 байт 2.

И напоследок мне понадобилось сделать отправку некоторых управляющих данных в CAN шину и посмотреть реакцию на эти команды. В программу на Arduino был добавлен код, который принимает данные со стороны компьютера и передаёт в CAN шину.

Именно на этом этапе пришлось отказаться от CyberLib, так как у неё не было поддержки прерывания поступления данных в буфер последовательного порта. В программе на компьютере добавил несколько текстовых полей, в которые можно ввести различные параметры и таблицу для просмотра ответа исполнительного устройства.

Can шина

Описывать технические подробности CAN шины в деталях — удел документации. В данной статье достаточно знать, что она:

Полистав странички одного известного интернет магазина из поднебесной, я заказал несколько различных вариантов шилдов и пошёл изучать особенности электрических сигналов в автомобиле. Подопытным автомобилем выступил LADA Kalina Cross с 127-ым мотором и электронным блоком управления ИТЭЛМА М74.5 CAN.

Подключаюсь в диагностический разъём OBD (контакты 6 и 14) и смотрю осциллографом, что там имеется. После поворота ключа зажигания начинают бегать пакеты с амплитудой до 2,5 В. Ставлю паузу на осциллографе и смотрю на пакет.

Заметны стартовые и стоповые биты, какие-то данные в пакете. На тот момент я уже знал, что скорость передачи данных ожидается 500 кбит/с, как наиболее частая для моторной CAN шины. Длительность пакета получается около 230 мкс и перед пакетом наблюдается довольно большая пауза в передаче данных. Масштабирую время и вижу три пакета и паузы между ними.

Если сложить длительность передачи данных и паузу между пакетам получается, что передача одной порции данных занимает около 1 мс.

К чему я это всё вывожу? А вопрос чисто практический: хватит ли скорости последовательного порта для передачи всех данных? И исходя из увиденного, можно сделать вывод, что скорость 500 кбит/с развивается внутри пакета, который занимает примерно четверть времени на передачу.

Значит средняя скорость передачи будет вчетверо меньшей. На тот момент я ещё не располагал тестами скорости последовательного интерфейса Arduino и забегая вперёд скажу, что даже с самым распространённым преобразователем Serial to USB CH340 стабильно работает скорость в 2 Мбит/с.

Obd dash.lite

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Только для тех, кто знает английский язык. Имеет платную версию dash.pro. Lite-версия работает только 7 дней. Потом придется купить программу

Чтобы начать работу нужно на стартовом экране нажать кнопку Settings в правом верхнем углу

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

В настройках необходимо выбрать тип подключения (Bluetooth) и устройство (OBDII)

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Начнется процесс подключение к EML (Bluetooth) и к блоку управления двигателем

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

После разблокировки (успешного подключения к ЭБУ) откроется нижнее меню, а в логе — Vehicle connection active

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Вот красиво показано напряжение бортовой сети — другие датчики «повесить» на этот экран в lite-версии нельзя. Нужно будет раскошелиться.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

OBD dash.Lite имеет на борту функции самопроверки OBD2 Readiness Monitors. Целью мониторов готовности является самопроверка систем контроля выхлопных газов автомобиля. Также они известны как мониторы выбросов, т.е. работают с выхлопной системой автомобиля.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Настройки профиля автомобиля:

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Загрузить hobdrive – hobdrive

Fork me on GitHub

Версия для загрузки:

Релиз

или

Последняя Бета

Андроид телефоны и планшетные компьютерыФайловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Скачайте APK файл для прямой установки
Apple iPhone 5/5s/6/SE, Apple iPad
Windows Phone 8/8.1 Смартфоны и Планшеты
Windows Mobile 5.x и 6.x Смартфоны и PDA
Windows CE Встроенные авто-магнитолы и отдельностоящие GPS навигаторы
Windows CE standalone пакет – не требует установки .net 3.5
Linux (Mono) Автокомпьютеры (Карпьютер, CarPC) и обычные компьютеры
Должно быть установлено окружение Mono. Запускайте хобдрайв командой “mono hobd.exe”
Windows XP/Vista АвтоКомпьютеры (Карпьютер, CarPC) и обычные компьютеры

Для платформ WindowsCE и Android мы предлагаем
демонстрационную версию . Она включает в себя

Почитайте больше о


дополнительных возможностях

которые вы получите если решите купить хобДрайв.

Демо версия недоступна для платформ Windows Phone 8 и iPhone. На этих платформах предоставляется полная версия с 30-и дневным периодом для оценки. В ней ограничен лишь функционал чтения и стирания ошибок на заводских протоколах.

Проверили хобдрайв демо, и хотите купить полную версию?

Купить !

Версия 1.1.1

Дополнительные материалы для загрузки:

Наша документация и справка:

распространяется с лицензионными условиями, аналогичными полной версии

Код ошибки:  Отзывы покупателей о Электрическая газонокосилка Makita ELM3800 | 7910186. Интернет-магазин DNS

:

Мы любим свободное программное обеспечение и за открытость информации.
Разработка частично открыта и базируется на открытом ядре – hobdcore.
Описания расширенных протоколов находятся в открытом виде, и пригодны для использования в других OBD2 программах.
Библиотека разрабатывается на хостинг-платформе
github.com

Как настроить телефон и адаптер?

Вся настройка заключается в двух нюансах — включить Bluetooth и включить GPS («Позиция»). Сделать это быстро можно через «шторку» (меню в панели уведомлений).

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

После того, как bluetooth включен — подключите адаптер ELM в OBDII-разъем вашего автомобиля. Далее зайдите в настройки Bluetooth и нажмите «Добавить устройство»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

В природе есть и wi-fi-адаптеры ELM, если у тебя такой, то после того, как вы вставили адаптер, вам нужно подключиться к его сети

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

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

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

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Далее устройство перейдет в статус «Подключено»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

И затем в «Сопряжено»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Всё, адаптер готов к работе

Куда он вставляется?

На автомобиле подобный разъем практически всегда расположен под рулем справа или слева (бывают исключения) — это диагностический разъем OBDII. Расшифровывается он соответствующее — On board diagnostics (Бортовая диагностика).

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

OBDII — это вторая версия данного разъема, которая получила уже массовое распространение среди производителей автомобилей. Это и послужило толчком для появления простых недорогих сканеров, которые могут позволить себе простые автовладельцы. Aliexpress окончательно подогрел эту тему, открыв нашим соотечественникам рынок дешевых OBDII-считывателей. Разъем универсальный, поэтому найти его не составит труда

Так он выглядит на Приоре:

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

А это одна из моделей Camry:

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

На Cherry Tiggo T11 он находится слева снизу руля:

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Приложение на телефон виртуальная панель приборов

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Если есть желание поддержать проект, то вот ссылка на приложение, принимаю любые замечания и предложения!
VAG Virtual Cockpit
Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Профессиональный, автоматический windows ce obd ii для автомобилей –

Alibaba.com позволяет легко получить доступ к широким категориям. windows ce obd ii, которые помогают в точном мониторинге и диагностике отдельных транспортных средств и механизмов. Эти наборы. windows ce obd ii оснащены модернизированными технологиями и могут помочь в максимальной заботе о машинах. Уникальная коллекция. windows ce obd ii прочны в конструкции и не требуют частого обслуживания, что позволяет экономить ваши деньги с течением времени.

Все. windows ce obd ii, доступные на сайте, имеют сложную структуру. Инструменты очень удобны, сделаны из прочных материалов, таких как железо и нержавеющая сталь, и могут охватывать несколько широко используемых систем. Эти. windows ce obd ii профессионального уровня, но при этом достаточно просты, чтобы их могли использовать и любители. Они также могут помочь в ремонте всех видов важных систем, таких как трансмиссии, двигатели, тормоза, безопасность, выбросы и так далее. Эти. windows ce obd ii имеют электрическое питание и имеют гарантийный срок.

На Alibaba.com представлен широкий выбор. windows ce obd ii различных моделей, размеров и функций. Эти. windows ce obd ii оснащены яркими светодиодными дисплеями, которые обеспечивают четкую видимость. Эти. windows ce obd ii также оснащены инновационным программным обеспечением DS Tool, которое может обновлять и показывать вам все записи о клиентах через ПК, нетбуки и другие устройства. Он совместим со всеми типами операционных систем и может помочь вам отслеживать записи.

Alibaba.com может предложить вам множество. windows ce obd ii, что поможет вам сэкономить на покупке. Эти продукты имеют сертификаты ISO, CE, SGS, что также дает уверенность в подлинности. Вы также можете размещать OEM-заказы вместе с индивидуальной упаковкой.

С чего начать?

[adace-ad id=»5714″]

Если автомобиль встречает тебя яркой (и от этого неприятной) вспышкой на значке «Check Engine», то тянуть не стоит — можно нарваться на совсем не иллюзорные проблемы. Но можно ли  оказать первую помощь самостоятельно?

Ведь при разных ситуациях даже неровный холостой ход может быть вызван множеством возможных неполадок (датчик ХХ, свечи и т.п.). Гадание на кофейной гуще или карты Таро вряд ли помогут нам найти ответ на этот вопрос. Поэтому в дело идёт адаптер ELM327

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Сar scanner elm obd2

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Универсальное приложение для всех мобильных операционных систем (кстати, в версии на Android UI выглядит куда лучше и красивей). Версия на Windows Phone также делится на бесплатную и платную (ссылка на pro-версию). В самом начале, при запуске, мы увидим, что ни подключение к адаптеру, ни подключение к блоку управления двигателем не выполнено.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Чтобы это исправить, свайпаем окно вниз и заходим в «Настройки»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Далее выбираем первый пункт «Подключение»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Здесь мы должны выбрать устройство bluetooth (мы уже подключились к адаптеру в

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Возвращаемся на начальный экран и нажимаем кнопку «Подключить». Обратите внимание, что при подключении к блоку управления программа может выдать предупреждение: «Обнаружен плохой адаптер EML»

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3

Ничего страшного в этом нет. Программа будет нормально и стабильно работать. Вероятно, так она реагирует на адаптер версии 2.1 (как мы помним, везде рекомендуется использовать 1.5). После того, как подключение удачно пройдет, всё остальное меню «разблокируется» — Ошибки, Показатели, Панель приборов. Вся программа русифицирована, поэтому проблем с понимаем работы возникнуть не должно.

Софт панели приборов на python и kivy (ui framework)

Параллельно со сборкой самой панели приборов я вел разработку приложения для отображения информации с датчиков. В самом начале я не планировал какой либо дизайн.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Первая версия панели приборов

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

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Вторая версия панели приборов

Продолжив поиски более современного дизайна я обратил внимание какие цифровые приборки делают автопроизводители и постарался сделать что-то похожее.

Файловый архив diagnost.kiev.ua | Програмное обеспечение для диагностического оборудования | Страница 3
Третья версия панели приборов

Ранее, я никогда не разрабатывал графические приложения под Linux поэтому не знал с чего начать. Вариант на вебе простой в разработке, но слишком много лишних компонентов: иксы, браузер, nodejs, хотелось быстрой загрузки. Попробовав Qt PySide2 я понял, что это займет у меня много времени, т.к. мало опыта.

Kivy позволяет запускать приложение без Иксов, прямо из консоли, в качестве рендера используется OpenGL. Благодаря этому полная загрузка системы может происходить за 10 секунд.

import can
import os
import sys
from threading import Thread
import time

os.environ['KIVY_GL_BACKEND'] = 'gl'
os.environ['KIVY_WINDOW'] = 'egl_rpi'

from kivy.app import App
from kivy.properties import NumericProperty
from kivy.properties import BoundedNumericProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.animation import Animation

messageCommands = {
    'GET_DOORS_COMMAND': 0x220D,
    'GET_OIL_TEMPERATURE' : 0x202F,
    'GET_OUTDOOR_TEMPERATURE' : 0x220C,
    'GET_INDOOR_TEMPERATURE' : 0x2613,
    'GET_COOLANT_TEMPERATURE' : 0xF405,
    'GET_SPEED' : 0xF40D,
    'GET_RPM' : 0xF40C,
    'GET_KM_LEFT': 0x2294,
    'GET_FUEL_LEFT': 0x2206,
    'GET_TIME': 0x2216
}

bus = can.interface.Bus(channel='can0', bustype='socketcan')
Полный код панели в одном python файле

# -*- coding: utf-8 -*-

import can
import os
import sys
from threading import Thread
import time

os.environ['KIVY_GL_BACKEND'] = 'gl'
os.environ['KIVY_WINDOW'] = 'egl_rpi'

from kivy.app import App
from kivy.properties import NumericProperty
from kivy.properties import BoundedNumericProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.animation import Animation

messageCommands = {
    'GET_DOORS_COMMAND': 0x220D,
    'GET_OIL_TEMPERATURE' : 0x202F,
    'GET_OUTDOOR_TEMPERATURE' : 0x220C,
    'GET_INDOOR_TEMPERATURE' : 0x2613,
    'GET_COOLANT_TEMPERATURE' : 0xF405,
    'GET_SPEED' : 0xF40D,
    'GET_RPM' : 0xF40C,
    'GET_KM_LEFT': 0x2294,
    'GET_FUEL_LEFT': 0x2206,
    'GET_TIME': 0x2216
}

bus = can.interface.Bus(channel='can0', bustype='socketcan')

class PropertyState:
    def __init__(self, last, current):
        self.last = last
        self.current = current

    def lastIsNotNow(self):
        return self.last is not self.current

class CanListener(can.Listener):
    def __init__(self, dashboard):
        self.dashboard = dashboard
        self.speedStates = PropertyState(None,None)
        self.rpmStates = PropertyState(None,None)
        self.kmLeftStates = PropertyState(None,None)
        self.coolantTemperatureStates = PropertyState(None,None)
        self.oilTempratureStates = PropertyState(None,None)
        self.timeStates = PropertyState(None,None)
        self.outDoorTemperatureStates = PropertyState(None,None)
        self.doorsStates = PropertyState(None,None)
        self.carMinimized = True

    def on_message_received(self, message):
	 messageCommand = message.data[3] | message.data[2] << 8

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_SPEED']:
            self.speedStates.current = message.data[4]
            if self.speedStates.lastIsNotNow():
                self.dashboard.speedometer.text = str(self.speedStates.current)
                self.speedStates.last = self.speedStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_RPM']:
            self.rpmStates.current = message.data[5] | message.data[4] << 8
            if self.rpmStates.lastIsNotNow():
                self.dashboard.rpm.value = self.rpmStates.current/4
                self.rpmStates.last = self.rpmStates.current
        if message.arbitration_id == 0x35B:
            self.rpmStates.current = message.data[2] | message.data[1] << 8
            if self.rpmStates.lastIsNotNow():
                self.dashboard.rpm.value = self.rpmStates.current/4
                self.rpmStates.last = self.rpmStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_KM_LEFT']:
            self.kmLeftStates.current = message.data[5] | message.data[4] << 8
            if self.kmLeftStates.lastIsNotNow():
                self.dashboard.kmLeftLabel.text = str(self.kmLeftStates.current)
                self.kmLeftStates.last = self.kmLeftStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_COOLANT_TEMPERATURE']:
            self.coolantTemperatureStates.current = message.data[4]
            if self.coolantTemperatureStates.lastIsNotNow():
                self.dashboard.coolantLabel.text = str(self.coolantTemperatureStates.current-81)
                self.coolantTemperatureStates.last = self.coolantTemperatureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_OIL_TEMPERATURE']:
            self.oilTempratureStates.current = message.data[4]
            if self.oilTempratureStates.lastIsNotNow():
                self.dashboard.oilLabel.text = str(self.oilTempratureStates.current-58)
                self.oilTempratureStates.last = self.oilTempratureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_TIME']:
            self.timeStates.current = message.data[5] | message.data[4] << 8
            if self.timeStates.lastIsNotNow():
                self.dashboard.clock.text = str(message.data[4])   ":"   str(message.data[5])
                self.timeStates.last = self.timeStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_OUTDOOR_TEMPERATURE']:
            self.outDoorTemperatureStates.current = float(message.data[4])
            if self.outDoorTemperatureStates.lastIsNotNow():
                self.dashboard.outDoorTemperatureLabel.text = str((self.outDoorTemperatureStates.current - 100)/2)
                self.outDoorTemperatureStates.last = self.outDoorTemperatureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_DOORS_COMMAND']:
            self.doorsStates.current = message.data[4]
            if self.doorsStates.lastIsNotNow():
                self.doorsStates.last = self.doorsStates.current
                self.dashboard.car.doorsStates=message.data[4]

                # all doors closed -> minimize car
                if self.doorsStates.current == 0x55:
                    self.dashboard.minimizeCar()
                    self.carMinimized = True
                else:
                    if self.carMinimized:
                        self.dashboard.maximizeCar()
                        self.carMinimized = False
          
class Dashboard(FloatLayout):
    def __init__(self,**kwargs):
        super(Dashboard,self).__init__(**kwargs)

        # Background
        self.backgroundImage = Image(source='bg.png')
        self.add_widget(self.backgroundImage)

        # RPM
        self.rpm = Gauge(file_gauge = "gauge512.png", unit = 0.023, value=0, size_gauge=512, pos=(0,0))
        self.add_widget(self.rpm)
        self.rpm.value = -200

        # Speedometer
        self.speedometer = Label(text='0', font_size=80, font_name='hemi_head_bd_it.ttf', pos=(0,-15))
        self.add_widget(self.speedometer)

        # KM LEFT
        self.kmLeftLabel = Label(text='000', font_name='Avenir.ttc', halign="right", text_size=self.size, font_size=25, pos=(278,233))
        self.add_widget(self.kmLeftLabel)

        # COOLANT TEMPEARATURE
        self.coolantLabel = Label(text='00', font_name='hemi_head_bd_it.ttf', halign="right", text_size=self.size, font_size=27, pos=(295,-168))
        self.add_widget(self.coolantLabel)

        # OIL TEMPERATURE
        self.oilLabel = Label(text='00', font_name='hemi_head_bd_it.ttf', halign="right", text_size=self.size, font_size=27, pos=(-385,-168))
        self.add_widget(self.oilLabel)

        # CLOCK
        self.clock = Label(text='00:00', font_name='Avenir.ttc', font_size=27, pos=(-116,-202))
        self.add_widget(self.clock)

        # OUTDOOR TEMPERATURE
        self.outDoorTemperatureLabel = Label(text='00.0', font_name='Avenir.ttc', halign="right", text_size=self.size, font_size=27, pos=(76,-169))
        self.add_widget(self.outDoorTemperatureLabel)

        # CAR DOORS
        self.car = Car(pos=(257,84))
        self.add_widget(self.car)

    def minimizeCar(self, *args):
        print("min")
        anim = Animation(scale=0.5, opacity = 0, x = 400, y = 240, t='linear', duration=0.5)
        anim.start(self.car)

        animRpm = Animation(scale=1, opacity = 1, x = 80, y = -5, t='linear', duration=0.5)
        animRpm.start(self.rpm)

    def maximizeCar(self, *args):
        print("max")
        anim = Animation(scale=1, opacity = 1, x=257, y=84, t='linear', duration=0.5)
        anim.start(self.car)

        animRpm = Animation(scale=0.5, opacity = 0, x = 80, y = -5, t='linear', duration=0.5)
        animRpm.start(self.rpm)


class Car(Scatter):
    carImage = StringProperty("car362/car.png")

    driverDoorClosedImage = StringProperty("car362/driverClosedDoor.png")
    driverDoorOpenedImage = StringProperty("car362/driverOpenedDoor.png")

    passangerDoorClosedImage = StringProperty("car362/passangerClosedDoor.png")
    passangerDoorOpenedImage = StringProperty("car362/passangerOpenedDoor.png")

    leftDoorClosedImage = StringProperty("car362/leftClosedDoor.png")
    leftDoorOpenedImage = StringProperty("car362/leftOpenedDoor.png")

    rightDoorClosedImage = StringProperty("car362/rightClosedDoor.png")
    rightDoorOpenedImage = StringProperty("car362/rightOpenedDoor.png")

    doorsStates = NumericProperty(0)

    size = (286, 362)

    def __init__(self, **kwargs):
        super(Car, self).__init__(**kwargs)

        _car = Image(source=self.carImage, size=self.size)

        self.driverDoorOpened = Image(source=self.driverDoorOpenedImage, size=self.size)
        self.passangerDoorOpened = Image(source=self.passangerDoorOpenedImage, size=self.size)
        self.leftDoorOpened = Image(source=self.leftDoorOpenedImage, size=self.size)
        self.rightDoorOpened = Image(source=self.rightDoorOpenedImage, size=self.size)

        self.driverDoorClosed = Image(source=self.driverDoorClosedImage, size=self.size)
        self.passangerDoorClosed = Image(source=self.passangerDoorClosedImage, size=self.size)
        self.leftDoorClosed = Image(source=self.leftDoorClosedImage, size=self.size)
        self.rightDoorClosed = Image(source=self.rightDoorClosedImage, size=self.size)

        self.add_widget(_car)
        self.add_widget(self.driverDoorOpened)
        self.add_widget(self.passangerDoorOpened)
        self.add_widget(self.leftDoorOpened)
        self.add_widget(self.rightDoorOpened)

        self.bind(doorsStates=self._update)

    def _update(self, *args):
        driverDoorStates = self.doorsStates&1
        passangerDoorStates = self.doorsStates&4
        leftDoorStates = self.doorsStates&16
        rightDoorStates = self.doorsStates&64
        if driverDoorStates != 0:
            try:
                self.remove_widget(self.driverDoorOpened)
                self.add_widget(self.driverDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.driverDoorClosed)
                self.add_widget(self.driverDoorOpened)
            except:
                pass
        if passangerDoorStates != 0:
            try:
                self.remove_widget(self.passangerDoorOpened)
                self.add_widget(self.passangerDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.passangerDoorClosed)
                self.add_widget(self.passangerDoorOpened)
            except:
                pass
        if leftDoorStates != 0:
            try:
                self.remove_widget(self.leftDoorOpened)
                self.add_widget(self.leftDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.leftDoorClosed)
                self.add_widget(self.leftDoorOpened)
            except:
                pass
        if rightDoorStates != 0:
            try:
                self.remove_widget(self.rightDoorOpened)
                self.add_widget(self.rightDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.rightDoorClosed)
                self.add_widget(self.rightDoorOpened)
            except:
                pass

class Gauge(Scatter):
    unit = NumericProperty(1.125)
    zero = NumericProperty(116)
    value = NumericProperty(10) #BoundedNumericProperty(0, min=0, max=360, errorvalue=0)
    size_gauge = BoundedNumericProperty(512, min=128, max=512, errorvalue=128)
    size_text = NumericProperty(10)
    file_gauge = StringProperty("")

    def __init__(self, **kwargs):
        super(Gauge, self).__init__(**kwargs)

        self._gauge = Scatter(
            size=(self.size_gauge, self.size_gauge),
            do_rotation=False, 
            do_scale=False,
            do_translation=False
            )

        _img_gauge = Image(source=self.file_gauge, size=(self.size_gauge, self.size_gauge))

        self._needle = Scatter(
            size=(self.size_gauge, self.size_gauge),
            do_rotation=False,
            do_scale=False,
            do_translation=False
            )

        _img_needle = Image(source="arrow512.png", size=(self.size_gauge, self.size_gauge))


        self._gauge.add_widget(_img_gauge)
        self._needle.add_widget(_img_needle)

        self.add_widget(self._gauge)
        self.add_widget(self._needle)

        self.bind(pos=self._update)
        self.bind(size=self._update)
        self.bind(value=self._turn)

    def _update(self, *args):
        self._gauge.pos = self.pos
        self._needle.pos = (self.x, self.y)
        self._needle.center = self._gauge.center

    def _turn(self, *args):
        self._needle.center_x = self._gauge.center_x
        self._needle.center_y = self._gauge.center_y
        a = Animation(rotation=-self.value*self.unit   self.zero, t='in_out_quad',duration=0.05)
        a.start(self._needle)

class requestsLoop(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.daemon = True
        self.start()

    canCommands = [
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_DOORS_COMMAND'] >> 8, messageCommands['GET_DOORS_COMMAND'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_SPEED'] >> 8, messageCommands['GET_SPEED'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_KM_LEFT'] >> 8, messageCommands['GET_KM_LEFT'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_RPM'] >> 8, messageCommands['GET_RPM'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_OIL_TEMPERATURE'] >> 8, messageCommands['GET_OIL_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_FUEL_LEFT'] >> 8, messageCommands['GET_FUEL_LEFT'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_OUTDOOR_TEMPERATURE'] >> 8, messageCommands['GET_OUTDOOR_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x746, data=[0x03, 0x22, messageCommands['GET_INDOOR_TEMPERATURE'] >> 8, messageCommands['GET_INDOOR_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_COOLANT_TEMPERATURE'] >> 8, messageCommands['GET_COOLANT_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_TIME'] >> 8, messageCommands['GET_TIME'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False)
    ]

    def run(self):
        while True:
            for command in self.canCommands:
                bus.send(command)
                time.sleep(0.005)

class BoxApp(App):
    def build(self):
        dashboard = Dashboard();
        listener = CanListener(dashboard)
        can.Notifier(bus, [listener])

        return dashboard
        
if __name__ == "__main__":
    # Send requests
    requestsLoop()

    _old_excepthook = sys.excepthook
    def myexcepthook(exctype, value, traceback):
        if exctype == KeyboardInterrupt:
            print "Handler code goes here"
        else:
            _old_excepthook(exctype, value, traceback)
    sys.excepthook = myexcepthook

    # Show dashboard
    BoxApp().run()

Код ошибки:  Скачать программы ELM327 на Андроид бесплатно

Алгоритм работы следующий, используется 3 потока:

  1. В главном потоке работаем с графическими элементы (спидометр, тахометр, часы, температуры и др) на экране
  2. Во втором потоке каждые 5 мс делаем опрос следующего датчика
  3. В третьем потоке слушаем CAN шину, получив ответ парсим его и обновляем соответствующий графический элемент


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

Проект цифровой панель приборов открытый. Рад буду предложениям и комментариям!

Файловый архив diagnost.kiev.ua | програмное обеспечение для диагностического оборудования | страница 3

СКАЧАТЬ BMWhat>>bmwhatliteios-prog
СКАЧАТЬ BMWhat lite>>
Приложение для диагностики автомобилей BMW. Работает по дилерскому протоколу, поэтому имеет большой функционал: может подключаться ко всем блокам управления авто, выводить данные в реальном времени, имеет функции программирования. Имеется две версии — платная и бесплатная. Бесплатная имеет ограниченный функционал.

СКАЧАТЬ>>ECUTracker-prog
Платформа: JAVA
Приложение является уникальным в своем роде – позволяет диагностировать автомобили практическим любым телефоном с помощью сканера на чипе ELM327 с поддержкой JAVA.

СКАЧАТЬ>>obdscope-prog
Платформа: Symbian 9.x
Хорошее приложение для диагностики автомобиля с помощью ELM327 совместимых сканеров. Имеет интуитивно понятный интерфейс, множество настраиваемых параметров, высокую скорость работы. Читать далее ObdScope v1.6.1

СКАЧАТЬ>>opendiag-prog
Программа от русских разработчиков для диагностики автомобилей российского и украинского производства. Благодаря возможности работать с адаптерами на базе ELM327 и K-line является уникальной в своем роде как по функционалу так и по продуманности интерфейса. Читать далее OpenDiag v1.4

СКАЧАТЬ>>vauxcheck-prog
Программа специально разработана для автомобилей Opel/ Vauxhall. Работает по дилерскому протоколу, поэтому поддерживает большинство автомобилей данной марки старше 1996 года. Умеет читать и сбрасывать ошибки. Читать далее VauxCheck v1.21

СКАЧАТЬ>>TECU-prog
НХорошая программа, написанная русским разработчиком. Помимо поддержки протоколов OBD-2 умеет работать и с «нестандартными» дилерскими протоколами таких автомобилей как Toyota/Lexus, Nissan, Mitsubishi , Cherry. Умеет подключаться к тем блокам управления автомобиля, с которыми другие программы отказываются работать. Читать далее TECU v2.3.2.9

СКАЧАТЬ>>forscan-prog
Программа, написанная специально для работы с автомобилями Ford, Mazda, Lincoln и Mercury. Имеет очень богатый список возможностей по сравнению с универсальными программами, может диагностировать множество различных блоков управления, проводить тесты, программировать некоторые блоки. Так же стоит отметить удобство интерфейса и русский язык. Читать далее ForScan v2.2.2

СКАЧАТЬ>>esud_1
Небольшая программа, заточена для работы с автомобилями ВАЗ с помощью адаптера ELM 327. Имеет простой лаконичный интерфейс, и может работать с автомобилями, с которыми другие программы отказываются работать. Читать далее Диагностика ЭСУД ВАЗ v1.4.2b

§

СКАЧАТЬ>>econtool
Программа умеет работать с бензиновыми двигателями Nissan по протоколу Nissan Consult (Nissan Custom, Nissan JDM) — это не OBDII. Если у вас двигатель с обычным OBDII протоколом, вам следует использовать другие программы. Программа работает через BlueTooth брелки с чипом ELM327. Читать далее EconTool v1.01

torqueСКАЧАТЬ>>
Самая популярная программа для диагностики автомобилей с помощью сканеров на базе микрочипа ELM327. Имеет очень богатый функционал, удобный интерфейс который можно настроить на свой вкус, хорошая русификация. Читать далее Torque Pro v1.8.49

СКАЧАТЬ C APPSTORE>>obddoctorios-prog
Неплохое бесплатное приложение от украинских разработчиков. Имеет простой лаконичный интерфейс, неплохую функциональность и русский интерфейс. Так же, несомненным плюсом есть то, что разработчики постоянно выпускают обновления и улучшают функционал программы.

СКАЧАТЬ C APPSTORE>>iobdios-prog
Очень хорошо проработанное приложение для диагностики автомобилей. Имеет множество встроенных профилей под разные авто, умеет проводить диагностические тесты, русские интерфейс. Бесплатно предлагается только демонстрационная версия.

СКАЧАТЬ C APPSTORE>>dashios-prog
Одно из самых функциональных приложения в AppStore для работы со сканерами на базе ELM327. Имеет большой функционал, множество настроек. Программа поддерживает различные темы оформления, так что каждый сможет настроить ее на свой вкус.

СКАЧАТЬ BMWhat>>bmwhatliteios-prog
СКАЧАТЬ BMWhat lite>>
Приложение для диагностики автомобилей BMW. Работает по дилерскому протоколу, поэтому имеет большой функционал: может подключаться ко всем блокам управления авто, выводить данные в реальном времени, имеет функции программирования. Имеется две версии — платная и бесплатная. Бесплатная имеет ограниченный функционал.

СКАЧАТЬ>>ECUTracker-prog
Платформа: JAVA
Приложение является уникальным в своем роде – позволяет диагностировать автомобили практическим любым телефоном с помощью сканера на чипе ELM327 с поддержкой JAVA.

§

Оцените статью
OBD
Добавить комментарий

Adblock
detector