obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене ОБД2

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

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

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

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

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

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

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

Код ошибки:  OBD2 — GM 12pin. Правильная распиновка | Электроника. Радиотехника

Can сниффер из arduino uno

Чтобы послушать, что отправляет VCDS в CAN шину я собрал сниффер на макетке из Arduino и модуля MCP2515 TJA1050 Niren.

Схема подключения следующая:

Vw transport protocol 2.0

Volkswagen Transport Protocol 2.0 используется в качестве транспортного уровня, а данные передаются в формате KWP2000. Keyword Protocol 2000 – это протокол для бортовой диагностики автомобиля стандартизированный как ISO 14230. Прикладной уровень описан в стандарте ISO 14230-3. Более подробно в википедии.

Т.к. KWP2000 использует сообщения переменной длины, а CAN шина позволяет передавать сообщения не больше 8 байт, то VW TP 2.0разбивает длинное сообщение KWP2000 на части при отправке по CAN шине и собирает заново при получении.

Диагностические данные от двигателя по протоколу KWP2000 (Skoda Octavia A5)
Диагностические данные от двигателя по протоколу KWP2000 (Skoda Octavia A5)

Видео работы цифровой панели приборов на базе raspberry pi

ОБНОВЛЕНО 24.06.2021

Диагностический адаптер elm327

Для меня некоторое время было вопросом, как получить данные из CAN шины и передать на телефон. Можно было бы разработать собственный шлюз с Wi-Fi или Bluetooth, как это делают производители сигнализаций, например Starline. Но изучив документацию на популярный автомобильный сканер ELM327 понял, что его можно настроить с помощью AT команд на доступ к CAN шине.

Копия диагностического сканера ELM327
Копия диагностического сканера ELM327
Не все ELM327 одинаково полезны

Оригинальный ELM327 от компании elmelectronics стоит порядка 50$, в России я таких не встречал в продаже. У нас продаются только китайские копии/подделки, разного качества и цены 10-30$. Бывают полноценные копии, которые поддерживают все протоколы, а бывают и те которые умеют отвечать только на несколько команд, остальные игнорируют, такие адаптеры не имеют доступ к CAN шине. Я например пользуюсь копией Viecar BLE 4.0, который поддерживает 100% всех функций оригинала.

Для работы с протоколом UDS через ELM327 нужно указать адреса назначения, источника и разрешить длинные 8 байтные сообщения, по умолчанию пропускается максимум 7 байт.

Последовательность ELM327 AT команд для работы с UDS по CAN шине:

ATZ // сброс настроек
AT E0 // отключаем эхо
AT L0 // отключаем перенос строки
AT SP 6 // Задаем протокол ISO 15765-4 CAN (11 bit ID, 500 kbaud)
AT ST 10 // Таймаут 10 * 4 мс, иначе EBU шлет повторные ответы каждые 100 мс, а мы не отвечаем, потому что ожидаем конца, а нам нужен только первый ответ
AT CA F0
AT AL // Allow Long (>7 byte) messages
AT SH 7E0 // задаем ID, к кому обращаемся (двигатель)
AT CRA 7E8 // CAN Receive Address. Можно задать несколько 7Xe
AT FC SH 7E0
AT FC SD 30 00 00
AT FC SM 1 // Режим Flow Control 1 должен быть определен после FC SH и FC SD, иначе в ответ придет "?"
03 22 F4 0С 55 55 55 55 // UDS запрос оборотов двигателя

Для работы с протоколом KWP2000 через ELM327 нужно только указать адреса назначения и источника.

Последовательность ELM327 AT команд для работы с VW TP 2.0 по CAN шине:

Как подключить obd2 сканер – motordata obd

Подсоедините адаптер к диагностическому разъему автомобиля.
На рисунке показаны возможные места расположения диагностического разъема.

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене

Если, после подключения OBD-сканера, отмечается необычное поведение комбинации приборов (загораются, мигают или гаснут индикаторы, появляются предупреждающие сообщения, аномальные показания спидометра) то, возможно, возникли нарушения в работе соответствующих систем. Будьте внимательны, могут быть затронуты компоненты, относящиеся к обеспечению безопасности движения!

Например, на автомобиле Toyota постоянно мигающая лампа ABS, означает, что система перешла в диагностический режим, в котором антиблокировочная система отключена, что существенно меняет на безопасность!

Внимание!
Движение на автомобиле с отключенной ABS небезопасно!
Это происходит из-за того, что на некоторых моделях Toyota вставленный адаптер перемыкает выводы разъема, отвечающие за режим самодиагностики, который активируется сразу после включение зажигания. Это связано не с работой программы MotorData OBD, а с наличием лишних, для этих моделей, контактов OBD-адаптера и алгоритмом работы блоков управления.

Возможные решения:

  1. приобретение специализированного адаптера
  2. удаление 13 и 14 контактов из разъема OBD-адаптера
  3. подключение OBD-адаптера в разъем черезе несколько секунд после включения зажигания или запуска двигателя. При этом блок управления не активирует режим диагностики, и ABS не отключается, однако делать это придется при каждом включении/выключении зажигания.

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

Мобильное приложение vag virtual cockpit

Для разработки мобильного приложения подключаемого к автомобилю требовалось:

Мобильное приложение VAG Virtual Cockpit для iOS
Мобильное приложение VAG Virtual Cockpit для iOS

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

Пару слов про точность данных. Штатная панель приборов не точно показывает скорость – завышает показания на 5-10 км/ч, стрелка охлаждающей жидкости всегда на 90 °C, хотя реальная температура может быть 80 – 110 °C, стрелка уровня топлива до середины идет медленно, хотя топлива уже меньше половины и при нуле на самом деле топливо еще есть в баке. Производитель это делает для удобства и безопасности водителя.

На данный момент приложение показывает следующие параметры:

Я стремлюсь чтобы приложение поддерживало как можно больше моделей автомобилей. Пока что поддерживаются производители: Volkswagen, Skoda, Seat, Audi. На разных комплектациях могут отображаться не все параметры, но это поправимо.

Сейчас я провожу тестирование версии 3.0. Приложение доступно только на iOS, после релиза 3.0 перейду к разработке версии для Android.

Панель приборов авто obd2 на алиэкспресс — купить онлайн по выгодной цене

Перед покупкой сравните цены на панель приборов авто obd2, прочитайте реальные отзывы покупателей, ознакомьтесь с техническими характеристиками.

Закажите панель приборов авто obd2 онлайн с доставкой по России: товары с пометкой Plus доступны с ускоренной доставкой и улучшенными условиями возврата.

На Алиэкспресс панель приборов авто obd2 всегда в наличии в большом ассортименте: на площадке представлены как надежные мировые бренды, так и перспективные молодые.

Подслушиваем запросы с помощью диагностической системы vag-com (vcds)


Описание VCDS с официального сайта

Приборной панели автомобиля obd купить по низкой цене на aliexpress

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

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

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

Читайте отзывы. Посмотрите, нравится ли приборной панели автомобиля obd другим покупателям. Читайте реальные отзывы о товаре — вы найдёте много полезной информации, а также советы и подсказки для удобного шопинга.

Так будет проще найти приборной панели автомобиля obd по выгодной цене и воспользоваться быстрой доставкой или бесплатным возвратом товара. А новых пользователей ждут спецпредложения и подарки! Заходите на сайт AliExpress, чтобы найти и купить ещё больше товаров из категории.”

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

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене
obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене
Если есть желание поддержать проект, то вот ссылка на приложение, принимаю любые замечания и предложения!
VAG Virtual Cockpit
obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене

Программный сниффер vcds

Программный сниффер VCDS: CAN-Sniffer
Программный сниффер VCDS: CAN-Sniffer

Чтобы узнать по какому протоколу общаются электронные блоки я использовал специальную версию VCDS с программным сниффером в комплекте. В этот раз никаких железных снифферов на Arduino или RPi не пришлось изобретать. С помощью CAN-Sniffer можно подсмотреть общение между VCDS и автомобилем, чтобы затем телефон мог прикинуться диагностической утилитой и отправлять те же самые запросы.

Я собрал некоторую статистику по использованию диагностических протоколов на разных моделях автомобилей:

Протокол uds

Unified Diagnostic Services (UDS) – это диагностический протокол, используемый в электронных блоках управления (ЭБУ) автомобильной электроники. Протокол описан в стандарте ISO 14229-1 и является производным от стандарта ISO 14230-3 (KWP2000) и ныне устаревшего стандарта ISO 15765-3 (Diagnostic Communication over Controller Area Network (DoCAN)).Более подробно в википедии.

Диагностические данные от двигателя по протоколу UDS (Skoda Octavia A7)
Диагностические данные от двигателя по протоколу UDS (Skoda Octavia A7)

Самый простой способ сделать реальное отображение температуры двигателя на lada vesta

 25 февраль 2020 Лада.Онлайн  
 98 073  
  

 
 


Самый простой способ сделать реальное отображение температуры двигателя на Lada Vesta

Особенность некоторых комбинаций приборов Lada Vesta – ступенчатое показание реальной температуры. После 55 градусов стрелка резко поднимается до 90 градусов. Разбираемся, как сделать так, чтобы стрелка приборной панели показывала реальные показания температуры охлаждающей жидкости.

Потребуется:

  1. Адаптер ELM327 V1.5, цена около 200 рублей, ссылка на AliExpress.
  2. Смартфон с установленной программой ECU Tweaker (архив ecu.zip скопировать в корень внутренней или внешней памяти, не распаковывая)

Порядок действий:

  1. Подключить адаптер ELM327 V1.5 к OBDII порту автомобиля.
  2. Включить зажигание.
  3. Запустить на смартфоне приложение «ECU Tweaker»
  4. В поиске выбрать «KOLEOS II»
  5. Выбрать «Meter Cluster»
  6. Выбрать «Cluster_15-40_v3.30.05»
  7. Выбрать «Ecrans Configuration»
  8. Выбрать «Conf Prestations IHM»
  9. Найти строчку «SCROKMsg_CF»
  10. Изменить значение с «With SCR OK MMI» на «Without SCR OK MMI»
  11. Нажать «SCR OK» (рядом со строкой SCROKMsg_CF)

В поиске выбрать «KOLEOS II»Выбрать «Meter Cluster»Выбрать «Cluster_15-40_v3.30.05»Выбрать «Ecrans Configuration»Выбрать «Conf Prestations IHM»Найти строчку «SCROKMsg_CF»

Процесс включения реальной температуры двигателя на Весте также показан на видео:

Напомним, сделать реальное отображение температуры ОЖ на Весте можно еще при помощи программатора Usbdm OSBDM V4.95. Для этого щиток приборов нужно будет снять, разобрать и прошить.

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

Кстати, при помощи ELM327 адаптера еще можно:

Ключевые слова: панель приборов лада веста | система охлаждения лада веста | двигатель лада веста | ELM327

Поделиться в социальных сетях:

Обнаружили ошибку? Выделите ее и нажмите Ctrl Enter..

Гости не могут оставлять комментарии в новостях, пожалуйста авторизируйтесь.

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

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

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене
Первая версия панели приборов

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

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене
Вторая версия панели приборов

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

obd2 speedometer на АлиЭкспресс — купить онлайн по выгодной цене
Третья версия панели приборов

Ранее, я никогда не разрабатывал графические приложения под 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()


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

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

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

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

Установка

Все действия вы делаете на свой страх и риск!

Потребуется:

  1. адаптер ELM327 V1.5, цена около 200 рублей, ссылка на AliExpress.
  2. архив с базой и ПО

Установка ПО на смартфон Android:

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