[PYTHON] Créez un compteur de voiture avec Raspberry Pi

Ceci est une continuation de la précédente Gestion de l'alimentation. Cette fois, j'ai réalisé un affichage côté compteur en utilisant electron. À ce niveau, c'était facile parce que les choses que je faisais avec des fenêtres fonctionnaient presque comme elles étaient. Si vous voulez voir tout le code, cliquez ici pi_meter

pi_meter.gif

Une petite explication

code

côté électron

index.html


<!DOCTYPE html>
<html>
<header>
	<link rel="stylesheet" type="text/css" href="./style.css">
</header>
<head>
	<meta charset="UTF-8">
	<title>pi_meter</title>
</head>
<body>
	<div class="wrapper">
		<div class="analog" >
			<div class="analog_li" id="a_wtmp">
				<img src="./img/a_water_t.png " alt="panel" />
			</div>
			<div class="analog_li" id="a_otmp">
				<img n src="./img/a_oil_t.png " alt="panel" />
			</div>
			<div class="analog_li" id="a_opls">
				<img  src="./img/a_oil_p.png " alt="panel" />
			</div>
		</div>
		<div class="degital">
			<div class="d_li" id="d_wtmp">
				<img class="d_p"  src="./img/d_water_t.png " alt="panel" />
			</div>
			<div class="d_li" id="d_otmp">
				<img class="d_p"  src="./img/d_oil_t.png " alt="panel" />
			</div>
			<div class="d_li" id="d_opls">
				<img class="d_p"  src="./img/d_oil_p.png " alt="panel" />
			</div>
		</div>
		<div class="analog_bar">
			<div class="b_bar_li" id="b_wtmp">
				<img class="b_a" src="./img/a_bar.png " id="im_wtmp"  alt="meter_bar" />
			</div>
			<div class="b_bar_li" id="b_otmp">
				<img class="b_a" src="./img/a_bar.png " alt="meter_bar" />
			</div>
			<div class="b_bar_li" id="b_opls">
				<img class="b_a" src="./img/a_bar.png " id="im_opls" alt="meter_bar" />
			</div>
		</div>
		<div class="digital_str">
			<div class="digital_str_li" id="str_wtmp">
			</div>
			<div class="digital_str_li" id="str_otmp">
			</div>
			<div class="digital_str_li" id="str_opls">
			</div>
		</div>
	</div>
</body>
<script type="text/javascript" src="script.js"></script>
</html>

main.js


'use strict';

const electron = require("electron");
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
let mainWindow;

app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({
        frame: true,
        fullscreen: true,
  });
  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

script.js


'use strict';


const remote = require('electron').remote;
//Obtenir la fenêtre du navigateur
const browserWindow = remote.getCurrentWindow();
//Obtenir un tableau de tailles d'écran[0]Est la largeur,[1]Est la largeur verticale
const win_size = browserWindow.getSize();

//Compteur utilisé à l'ouverture
var counter=0;
//Nombre maximum de compteurs à utiliser à l'ouverture
var animaton_counter=100;//10msec * 200 = 2seconds
//Compteur utilisé dans l'ouverture mobile de chaque compteur
var counter1=0;
var counter2=0;
var counter3=0;
//Valeur pour avancer le compteur utilisé dans l'ouverture du mouvement de chaque mètre
var add_counter1 = 0; 
var add_counter2 = (win_size[0]/3)/animaton_counter; 
var add_counter3 = (win_size[0]/3*2)/animaton_counter; 

//Valeur maximale du compteur = point fixe
var count_max1 = 0;
var count_max2 = (win_size[0]/3);
var count_max3 = (win_size[0]/3*2);

//Acquisition de chaque fond de mètre rond
var a_wtmp = document.getElementById("a_wtmp");
var a_otmp = document.getElementById("a_otmp");
var a_opls = document.getElementById("a_opls");

//Obtenez chaque arrière-plan de compteur de caractères
var d_wtmp = document.getElementById("d_wtmp");
var d_otmp = document.getElementById("d_otmp");
var d_opls = document.getElementById("d_opls");

//Acquisition de l'affichage des caractères pour chaque compteur de caractères
var str_wtmp = document.getElementById("str_wtmp");
var str_otmp = document.getElementById("str_otmp");
var str_opls = document.getElementById("str_opls");

//Acquisition de l'image d'aiguille de chaque mètre rond
var bar_wtmp = document.getElementById("b_wtmp");
var bar_otmp = document.getElementById("b_otmp");
var bar_opls = document.getElementById("b_opls");

//Angle d'affichage de chaque aiguille de mètre
var rt_wtmp=0;
var rt_otmp=0;
var rt_opls=0;

//Variables d'acquisition de la température de l'eau et variables pour le stockage temporaire
var tmp_wtmp1=0;
var tmp_wtmp2=0;

//Variable d'acquisition de température d'huile et variable de stockage temporaire
var tmp_otmp1=0;
var tmp_otmp2=0;

//Variables d'acquisition de la pression hydraulique et variables pour le stockage temporaire
var tmp_opls1=0;
var tmp_opls2=0;

//Drapeau enveloppant utilisé dans l'ouverture
var turn_flg=0;

//Acquisition du fichier de données pour le compteur
var fs = require('fs');
var filepath = './meter_data.json';

//Minimiser la fenêtre
document.getElementById("im_opls").addEventListener("click", function (e) {
	browserWindow.minimize(); 
});

//Terminer le traitement
document.getElementById("im_wtmp").addEventListener("click", function (e) {
	browserWindow.close();
}); 

//Mouvement du mètre rond
function mv_analog_p(){
	a_wtmp.style.left = 0+'px';
	a_wtmp.style.top= 0+'px';

	a_otmp.style.left = counter2+'px';
	a_otmp.style.top= 0+'px';

	a_opls.style.left = counter3+'px';
	a_opls.style.top= 0+'px';
}

//Déplacement du compteur de caractères
function mv_dgital_p(){
	d_wtmp.style.left = 0+'px';
	d_wtmp.style.top= (win_size[0]/3)+'px';
	
	d_otmp.style.left = counter2+'px';
	d_otmp.style.top= (win_size[0]/3)+'px';
 
	d_opls.style.left = counter3+'px';
	d_opls.style.top= (win_size[0]/3)+'px';
}

//Déplacer l'affichage du modificateur
function mv_dgital_str(){
	str_wtmp.style.right = (counter3+(win_size[0]/12))+'px';
	str_wtmp.style.top= (win_size[0]/24*9)+'px';
	str_wtmp.style.zIndex = '4';
	str_wtmp.style.fontSize=(win_size[0]/8)+"px";

	str_otmp.style.right = (counter2+(win_size[0]/12))+'px';
	str_otmp.style.top= (win_size[0]/24*9)+'px';
	str_otmp.style.zIndex = '4';
	str_otmp.style.fontSize=(win_size[0]/8)+"px";

	str_opls.style.right = (win_size[0]/12)+'px';
	str_opls.style.top= (win_size[0]/24*9)+'px';
	str_opls.style.zIndex = '4';
	str_opls.style.fontSize=(win_size[0]/8)+"px";
}

//Mouvement de l'aiguille du mètre rond
function mv_analog_bar(){
	bar_wtmp.style.left = 0+'px';
	bar_wtmp.style.top= 0+'px';
	bar_wtmp.style.zIndex = '5';
	bar_wtmp.style.webkitTransform = "rotate("+rt_wtmp+"deg)";

	bar_otmp.style.left = count_max2+'px';
	bar_otmp.style.top= 0+'px';
	bar_otmp.style.zIndex = '5';
	bar_otmp.style.webkitTransform = "rotate("+rt_otmp+"deg)";

	bar_opls.style.left = count_max3+'px';
	bar_opls.style.top= 0+'px';
	bar_opls.style.zIndex = '5';
	bar_opls.style.webkitTransform = "rotate("+rt_opls+"deg)";
}

//Pour dessiner l'ouverture
function draw_data(){
	bar_wtmp.style.webkitTransform = "rotate("+rt_wtmp+"deg)";
	document.getElementById("str_wtmp").innerHTML = (rt_wtmp/2.25).toFixed(0);
	bar_otmp.style.webkitTransform = "rotate("+rt_otmp+"deg)";
	document.getElementById("str_otmp").innerHTML = (rt_otmp/1.8).toFixed(0);
	bar_opls.style.webkitTransform = "rotate("+rt_opls+"deg)";
	document.getElementById("str_opls").innerHTML = (rt_opls/27).toFixed(1);
}

//Ouverture du mouvement du panneau
function start_meter(){
	if(counter<animaton_counter){
		mv_analog_p();
		mv_dgital_p();
		counter2=counter2+add_counter2;
		counter3=counter3+add_counter3;
		counter++;
		setTimeout('start_meter()',10);
	}else{
		counter1=count_max1;
		counter2=count_max2;
		counter3=count_max3;
		mv_analog_p();
		mv_dgital_p();
		mv_dgital_str();
		mv_analog_bar();
		opening();
	}
}

//ouverture
function opening() {
	if( (rt_wtmp!=270) && (turn_flg==0) ){
		rt_wtmp+=2;
		rt_otmp+=2;
		rt_opls+=2;
		draw_data();
		setTimeout("opening()",10);
	}else if( (rt_wtmp==270) && (turn_flg==0)  ){
		turn_flg=1;
		setTimeout("opening()",200);
	}else if((rt_wtmp!=0) && (turn_flg==1)){
		rt_wtmp-=2;
		rt_otmp-=2;
		rt_opls-=2;
		draw_data();
		setTimeout("opening()",10);
	}else if ((rt_wtmp==0) && (turn_flg==1)){
		turn_flg=0;
		setTimeout("mainloop()",15);
	}
}

//Lire les données
function check_data() {
        try{
                var json_data = JSON.parse(fs.readFileSync(filepath, 'utf8'));
                tmp_wtmp1=parseInt(json_data["wtmp"]);
                tmp_otmp1=parseInt(json_data["otmp"]);
                tmp_opls1=parseInt(json_data["opls"]);
        }catch (err){
        }
}
//Vérification de test_data()Au lieu de l'utiliser maintenant
function test_data() {
	if(turn_flg==0){
		tmp_wtmp1++;
		tmp_otmp1++;
		tmp_opls1++;
	}else{
		tmp_wtmp1--;
		tmp_otmp1--;
		tmp_opls1--;
	}
	if(tmp_wtmp1==100){
		turn_flg=1;
	}else if(tmp_wtmp1==0){
		turn_flg=0;
	}
}

//Boucle principale
function mainloop(){
	check_data();
	if(tmp_wtmp1!=tmp_wtmp2){
		if(tmp_wtmp1 > tmp_wtmp2){
			tmp_wtmp2++;
		}else{
			tmp_wtmp2--;
		}
		rt_wtmp=tmp_wtmp2*2.25;
		bar_wtmp.style.webkitTransform = "rotate("+rt_wtmp+"deg)";
		document.getElementById("str_wtmp").innerHTML = tmp_wtmp2 ;
	}
		
	if(tmp_otmp1!=tmp_otmp2){
		if(tmp_otmp1 > tmp_otmp2){
			tmp_otmp2++;
		}else{
			tmp_otmp2--;
		}
		rt_otmp=tmp_otmp2*1.8;
		bar_otmp.style.webkitTransform = "rotate("+rt_otmp+"deg)";
		document.getElementById("str_otmp").innerHTML =tmp_otmp2;
	}

	if(tmp_opls1!=tmp_opls2){
		if(tmp_opls1 > tmp_opls2){
			tmp_opls2++;
		}else{
			tmp_opls2--;
		}
		rt_opls=tmp_opls2*2.7;
		bar_opls.style.webkitTransform = "rotate("+rt_opls+"deg)";
		document.getElementById("str_opls").innerHTML =(tmp_opls2/10).toFixed(1);
	}
	setTimeout("mainloop()",15);
}


window.onload = function(){
	start_meter();
}

Voici la différence précédente.

côté arduino

arduino.ino


#define WTMP_IN (A0) //water temp
#define OTMP_IN (A1) //oil temp 
#define OPLS_IN (A2) //oil press
#define B_LV_IN (A3) //battery level 

~~~~~~~~~~~~~~

/get message from pi
void get_message(int n){
~~~~~~~~
  }else if((cmd[0] >= 48) && (cmd[0] < 79)) //0x30~0x4F return message state 
  {
  	message_state = cmd[0];
  }
~~~~~~~~
}


~~~~~~~~~~~~~~

//send message to pi
void send_message(){
  //when get cmd switch
  switch (message_state) {
~~~~~~~~
   //analog read
   case 0x31: //water temp upper bit
   Wire.write(r_wtmp >> 8);
   break;
   case 0x32: //water temp low bit
   Wire.write(r_wtmp & 0xFF);
   break;
   case 0x33: //oil temp upper bit
   Wire.write(r_otmp >> 8 );
   break;
   case 0x34: //oil temp low bit
   Wire.write(r_otmp & 0xFF);
   break;
   case 0x35: //oil press upper bit
   Wire.write(r_opls >> 8);
   break;
   case 0x36: //oil press low bit
   Wire.write(r_opls & 0xFF);
   break;
   case 0x37: //battery level upper bit
   Wire.write(r_b_lv >> 8);
   break;
   case 0x38: //battely level low bit
   Wire.write(r_b_lv & 0xFF);
   break;
 
~~~~~~~~
 }
}

~~~~~~~~~~~~~~

void check_input()
{
  switch (read_counter){
    case 0:
    r_wtmp=analogRead(WTMP_IN);
    read_counter++;
    break;

    case 1:
    r_otmp=analogRead(OTMP_IN);
    read_counter++;
    break;
 
    case 2:
    r_opls=analogRead(OPLS_IN);
    read_counter++;
    break;
 
    case 3:
    r_b_lv=analogRead(B_LV_IN);
    read_counter++;
    break;
 
    case 4:
    read_counter=0;
    break;
 
  }

}

~~~~~~~~~~~~~~

//main loop
void loop()
{
~~~~~~~~
  switch(ino_state)
  {
~~~~~~~~
    case 0x01: //arduino normal state
      if( (acc==0) && (!slp_interbal_flg) )
      {
        ino_state++; //pi shutdown state
      }
      //check sleep interbal
      else if(slp_interbal_flg)
      {
        if(counter_switch)
        {
          if(millis() > onslp_max_time)
          {
            slp_interbal_flg = false;
          }
        }
        else
        {
          if( (millis() < onslp_past_time) && (millis() > onslp_max_time) )
          {
            slp_interbal_flg = false;
          }
        }
      }else
      {
        check_input();
      }
      break;
~~~~~~~~
}


côté python de framboise pi

arduino_meter.py


import math
~~~~~~~~~~~~~~

#thermistor config
THERM_B=4181
THERM_R1=3.00
THERM_R0=2.3
THERM_T0=298.15

~~~~~~~~~~~~~~

#get thermistor
def get_therm(tmp):
    if ( tmp <= 0) | ( tmp > 1023):
        TMP = 1
    else:
       TMP = tmp
    temp = 0
    rr1 = THERM_R1 * TMP / (1024.0 - TMP)
    t = 1 / ( math.log( rr1/THERM_R0 ) / THERM_B  +  1/THERM_T0 )
    temp = (t - 273.5)
    return int(temp)

#get oil_press
def get_oil_press(tmp):
    vol = (5000/1023)*tmp
    press = (vol-600)/40
    return press

~~~~~~~~~~~~~~
#get car data
def get_analog_level(addr,u_data,l_data):
    TRY1 = I2C_TRY
    TRY2 = I2C_TRY
    analog_leve=0
    while TRY1:
        try:
            reading = int(bus.read_byte_data(addr,u_data))
            analog_level = reading << 8
        except IOError as e:
            print "get car data IO error"
            TRY1-=1
        except :
            print "get car date Unexcepted error"
            raise
        else:
            break

    if not TRY1:
        raise

    while TRY2:
        try:
            reading = int(bus.read_byte_data(addr,l_data))
            analog_level = analog_level | reading
            return analog_level
        except IOError as e:
            print "get car data IO error"
            TRY2-=1
        except :
            print "get car date Unexcepted error"
            raise
        else:
            break

    if not TRY2:
        raise
~~~~~~~~~~~~~~

#write data
def write_data():
    m_data = {"wtmp":"" , "otmp":"" ,"opls": ""}
    m_data["wtmp"]=get_therm(w_temp)
    m_data["otmp"]=get_therm(o_temp)
    m_data["opls"]=get_oil_press(o_press)
    with open('meter_data.json','w') as f:
        json.dump(m_data, f, sort_keys=True, indent=4)

~~~~~~~~~~~~~~

    #main loop
    while True:
        check_state(SLAVE_ADDRESS)
        w_temp = get_analog_level(SLAVE_ADDRESS,0x31,0x32)
        o_temp = get_analog_level(SLAVE_ADDRESS,0x33,0x34)
        o_press = get_analog_level(SLAVE_ADDRESS,0x35,0x36)
        b_level = get_analog_level(SLAVE_ADDRESS,0x38,0x38)
        write_data()
        time.sleep(0.1)

~~~~~~~~~~~~~~

Schéma de connexion simple

Le capteur utilise la série PK fabriquée par Auto Gauge sur le marché pour la température et la pression hydraulique. Peu importe le fabricant si vous prenez les données, mais comme il y a des données du travail précédent, je les utilise telles quelles. 回路説明図.png

Recommended Posts

Créez un compteur de voiture avec Raspberry Pi
Utiliser une webcam avec Raspberry Pi
Faire une minuterie de lavage-séchage avec Raspberry Pi
Faites fonctionner l'oscilloscope avec le Raspberry Pi
GPGPU avec Raspberry Pi
DigitalSignage avec Raspberry Pi
Créer un système de notification des visiteurs à l'aide de Raspberry Pi
Créer une socket avec une interface Ethernet (eth0, eth1) (Linux, C, Raspberry Pi)
Plantes Mutter avec Raspberry Pi
Créez un capteur de couleur à l'aide d'une tarte à la râpe et d'une caméra
Utilisation de la voiture 4RM FT-MC-004 d'Akizuki Denshi avec Raspberry Pi
J'ai essayé de créer un bouton pour Slack avec Raspeye + Tact Switch
Créer un répertoire avec python
Un mémorandum lors de la réalisation d'une caméra de surveillance avec Raspeye
Créez des jeux LCD (16x2) avec Raspberry Pi et Python
Créez une partition, puis installez le système d'exploitation Raspberry Pi
J'ai créé un moniteur de ressources pour Raspberry Pi avec une feuille de calcul
getrpimodel: Reconnaître le modèle Raspberry Pi (A, B, B +, B2, B3, etc.) avec python
J'ai fait une caméra de surveillance avec Raspberry PI pour la première fois.
[Raspberry Pi] Contrôle du moteur pas à pas avec Raspberry Pi
Utilisez vl53l0x avec RaspberryPi (python)
Commande de servomoteur avec Raspberry Pi
Communication série avec Raspberry Pi + PySerial
Créez un environnement virtuel avec Python!
Configuration du système d'exploitation avec Raspberry Pi Imager
Essayez L Chika avec raspberrypi
Essayez de déplacer 3 servos avec Raspeye
Créez un stepper de poisson avec numpy.random
Créer un téléchargeur de fichiers avec Django
Contrôlez le moteur avec un pilote de moteur en utilisant python sur Raspberry Pi 3!
Faisons un ordinateur de vélo avec Raspberry Pi Zero (W, WH)
J'ai créé un serveur Web avec Razpai pour regarder des anime
Faire une boussole d'affichage kanji avec Raspberry Pi et Sense Hat
[Remarque] Utilisation d'un écran LCD à 16 caractères à 2 chiffres (1602A) de Python avec Raspeye
Mesurer la force du signal SIM avec Raspberry Pi
Créer un décorateur de fonction Python avec Class
Surveillance des animaux avec Rekognition et Raspberry pi
[Raspberry Pi] Ajouter un thermomètre et un hygromètre
Créez une image factice avec Python + PIL.
Bonjour le monde avec Raspberry Pi + Minecraft Pi Edition
[Python] Créez un environnement virtuel avec Anaconda
Créons un groupe gratuit avec Python
Créer une application graphique avec Tkinter de Python
Essayez de pêcher le Wakasagi avec Raspberry Pi
Créer un gros fichier texte avec shellscript
Capteur humain amélioré fabriqué avec Raspberry Pi
Créer une machine virtuelle avec un fichier YAML (KVM)
Essayez la détection d'objets avec Raspberry Pi 4 + Coral
Exécuter le servomoteur SG-90 avec Raspberry Pi
Créer un compteur de fréquence de mots avec Python 3.4
Travailler avec des capteurs dans Mathematica sur Raspberry Pi
Créer un voisin le plus proche de connexion avec NetworkX
Modèle Infer Custom Vision avec Raspeye
Créer un service Web avec Docker + Flask
Créez une image diabolique avec le script de Blender
Créer une matrice avec PythonGUI (zone de texte)
Enregistrement de la valeur d'Inkbird IBS-TH1 avec Raspberry Pi