忘れそうな内容をメモしています

忘れっぽいのでメモ帳がわりに色々書いてます

obdメーターを自作してみた

勤務地が変わり車を使うことが多くなりガソリン代が気になりだした。
そこで燃費を計算して表示できれば、燃費の良い運転ができるのでは!と思い試作した。

▼ハードウェア
・ELM327(OBD2スキャンツール)

 ACC電源から取れるように以下を参考に電源の配線を改造。
 写真で解説最新ELM327のACC電源化手順 | ゆとりがゆとりを手に入れる

・小型車載モニタ
 

・Raspberrypi modelB(家に転がっていた1世代) *下記リンクは2世代目です。
 

全体イメージは以下。

 [車]→(諸々の車両情報)→[ELM327]→(USBシリアルで伝送)→[Raspberry pI]→[車載モニタ]
                                              
▼ソフトウェア
OSSのpyobdを利用。しかしリアルタイムでの計測値や燃費の表示はできないためmatplotlibを用いて自作した。
 http://www.obdtester.com/pyobd
 
・コード(obd_fuelconsumption.py)
 pyobdのOBD_Recorderクラスにrecord_dataメソッドを作成し、そこで瞬間燃費[km/l]、スピード[km/h]、 気流率[g/s]をリアルタイムで描画している。
 瞬間燃費の考え方は以下の式で計算している。
  ※瞬間燃費の計算式 km/l = (14.7*0.75*1000*VSS)/(3600*MAF)
 14.7 理論空燃比
 0.75 ガソリンの比重(だいたい0.75くらいか?)
 1000 リットル換算
 VSS スピード km/h
 3600 時間換算
 MAF 気流率 g/s

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import obd_io
import serial
import platform
import obd_sensors
import time
import getpass
import numpy as np
import random
from matplotlib import pyplot as plt
from datetime import datetime
from obd_utils import scanSerial

class OBD_Recorder():
    def __init__(self, path, log_items):
        self.port = None
        self.sensorlist = []
        localtime = time.localtime(time.time())
        filename = path+"car-"+str(localtime[0])+"-"+str(localtime[1])+"-"+str(localtime[2])+"-"+str(localtime[3])+"-"+str(localtime[4])+"-"+str(localtime[5])+".log"
        self.log_file = open(filename, "w", 128)
        self.log_file.write("Time,Distance[km],Speed[km/h],MAF[g/s],RPM[rpm],TotalMAF[g]\n");

        for item in log_items:
            self.add_log_item(item)

    def connect(self):
        portnames = scanSerial()
        print portnames
        for port in portnames:
            self.port = obd_io.OBDPort(port, None, 2, 2)
            if(self.port.State == 0):
                self.port.close()
                self.port = None
            else:
                break

        if(self.port):
            print "Connected to "+self.port.port.name
            
    def is_connected(self):
        return self.port
        
    def add_log_item(self, item):
        for index, e in enumerate(obd_sensors.SENSORS):
            if(item == e.shortname):
                self.sensorlist.append(index)
                print "Logging item: "+e.name
                break
            
            
    def record_data(self):
        if(self.port is None):
            return None
        
        print "Logging started"
        fig = plt.figure()
        t = np.zeros(50)
        y1 = np.zeros(50)
        y2 = np.zeros(50)
        y3 = np.zeros(50)
     
        ax1 = fig.add_subplot(3,1,1)
        lines1, = ax1.plot(t, y1,"r")
        ax1.set_title("")
        plt.ylim(0, 120)
        plt.ylabel("F.C")
        plt.tick_params(labelbottom="off")
    
        ax2 = fig.add_subplot(3,1,2)
        lines2, = ax2.plot(t, y2,"b")
        plt.ylim(0, 120)
        plt.ylabel("Speed")
        plt.tick_params(labelbottom="off")
    
        ax3 = fig.add_subplot(3,1,3)
        lines3, = ax3.plot(t, y3,"g")
        plt.ylim(0, 30)
        plt.ylabel("MAF")
        plt.tick_params(labelbottom="off")
    
        time = 0
        total_maf = 0
        while 1:
            localtime = datetime.now()
            current_time = str(localtime.hour)+":"+str(localtime.minute)+":"+str(localtime.second)+"."+str(localtime.microsecond)
            log_string = current_time
            results = {}
            for index in self.sensorlist:
                (name, value, unit) = self.port.sensor(index)
                log_string = log_string + ","+str(value)
                results[obd_sensors.SENSORS[index].shortname] = value;

            total_maf = total_maf + results["maf"]
            results["total_maf"] = total_maf
            print results
        
            time = time +0.01
            t = np.append(t, time)
            t = np.delete(t, 0)
            if results["maf"] > 0:
                fc = (14.7*0.75*1000*results["speed"])/(3600*results["maf"])
            else:
                fc = 0  
            consumption = ((((total_maf/14.7)/0.73))/1000)
            y1 = np.append(y1, fc)
            y1 = np.delete(y1, 0)

            y2 = np.append(y2, results["speed"])
            y2 = np.delete(y2, 0)

            y3 = np.append(y3, results["maf"])
            y3 = np.delete(y3, 0)

            title = "F.C:"+str(round(fc,2)) + "Speed:"+str(round(results["speed"],2)) +" RPM:"+str(round(results["rpm"],2))+" MAF:"+str(round(results["maf"],2))+"fuel "+str(round(consumption,2))
            plt.pause(.01)
            lines1.set_data(t, y1)
            ax1.set_xlim((t.min(), t.max()))
            ax1.set_title(title)
            plt.draw()
    
            lines2.set_data(t, y2)
            plt.draw()
            ax2.set_xlim((t.min(), t.max()))
    
            lines3.set_data(t, y3)
            plt.draw()
            ax3.set_xlim((t.min(), t.max()))
            self.log_file.write(log_string+"\n")
            
username = getpass.getuser()  
logitems = ["distance","speed","maf","rpm"]
o = OBD_Recorder('/home/'+username+'/pyobd-pi/log/', logitems)
o.connect()

if not o.is_connected():
    print "Not connected"
o.record_data()

・起動バッチファイル(startlog.sh)を/home/pi/Desktop/startlog.shに配置

#!/bin/sh -
cd /home/pi/pyobd-pi/
python obd_fuelconsumption.py 

・起動時にグラフが立ち上がるように/etc/systemd/system以下に以下(pyobd.service)を配置

pyobd.service

[Unit]
Description=pyobd
After=multi-user.targe

[Service]
Environment="DISPLAY=:0"
ExecStart=/home/pi/Desktop/startlog.sh
Restart=always
Type=simple
#User=pi
#Group=pi

[Install]
WantedBy = multi-user.target

f:id:shintarof:20181117155304j:plain
このように走行時にリアルタイムで瞬間燃費が表示可能になった。
写真は市街地を時速40km程度で走行した時の速度(Speed)と 気流率(MAF)と瞬間燃費(F.C)。
*撮影は停車時に実施。

これをどう運転にフィードバックするかが課題。。