Skript zur Ladesteuerung einer Batterie
Verfasst: Montag 22. Oktober 2018, 17:02
Guten Tag,
in den letzten zwei Monaten habe ich von 0 angefangen mich mit dem Thema Raspberry Pi´s, Elektronik und Programmierung auseinander zu setzen. Daher bitte ich um Verzeihung für meinen "unschönen" Code...
Ich habe ein Skript für eine Ladesteuerung einer Batterie geschrieben (bitte keine DIskussion über den Sinn dahinter... es ist für mich erstmal ein Weg in ein Thema reinzukommen), das grundsätzliche Prinzip sieht folgendermaßen aus: Ich habe eine Ladeplatine, die ich mit einem Raspberry Pi via CAN anspreche. Je nach Nachricht, die ich der Ladeplatine schicke, setzt diese etwa eine Spannung an um die Batterie zu laden, sendet einen Heartbeat (wichtig, weil sonst die Ladeplatine nach einer gewissen Zeit "aus geht" wenn kein Heartbeatrequest gesendet wird), sendet die auf der Platine gemessene Spannung oder beendet den Ladevorgang.
Der Sinn des Skripts ist folgender: Zunächst wird ein Can-Bus aufgebaut. Dann soll eine Excel-Datei erstellt werden, die nachfolgend die Platinenspannung sekündlich loggt. Schön wäre, wenn die Datei je nachdem, wann ich das Skript ausführe, folgende Kennzeichnung hat: Platinenspannung_TTMMJJJJ und wenn ich das Skript mehrmals am selben Tag ausführe nicht überschreibt, sondern dann einfach etwa noch eine (2) ans Ende schreibt.
Das Skript soll dann sekündlich die Platinenspannung abfragen und ausgeben. Da die Antwort der Platine bei Spannungsabfrage in Hex kommt, muss diese noch konvertiert werden. Gleichzeitig soll alle 10 Sekunden ein Heartbeatrequest an die Platine gesendet werden, damit diese nicht einfach "ausgeht". Sobald die Platinenspannung 3 mal einen bestimmten Wert erreicht hat (etwa 41000 mV), soll die Nachricht zum beenden des Ladevorgangs gesendet & die Excel-Datei geschlossen werden sowie der Heartbeat-Task beendet werden.
Im Folgenden seht ihr meinen derzeitigen Code:
Mein Problem ist zunächst das Erstellen einer immer neuen Excel Datei für jedes Ausführen des Skripts. Weiterhin habe ich das Problem, dass der Heartbeat-Task erst beendet wird, wenn der Task aufgewacht ist und ein letztes mal gesendet hat. Vorher wird das Programm nicht beendet. Ich möchte aber eigentlich gerne den Task beenden, sobald mein Ladevorgang gestoppt wird.... sonst muss ich im blödesten Fall 9:59 min warten. Außerdem tue ich mich mit dem bis 3 laufenden Counter schwer und weiß nicht genau, wie diese Stelle aussehen soll. Am Anfang seht ihr, dass ich matplotlib importe, das liegt daran, dass ich damit gerne die Excel direkt plotten möchte. Aber dafür muss ich mich noch etwas mit matplotlib auseinandersetzen. Und die grundsätzliche Frage wäre, ob das Skript so überhaupt "gut" ist. Es wirkt für mich so dahingeschustert. Ich lese mich zwar gerade in das schreiben von Klassen ein, weiß aber noch nicht, wie ich dieses Konzept in meinem Skript anwenden kann.
Ich bin für jede Hilfe wirklich dankbar
in den letzten zwei Monaten habe ich von 0 angefangen mich mit dem Thema Raspberry Pi´s, Elektronik und Programmierung auseinander zu setzen. Daher bitte ich um Verzeihung für meinen "unschönen" Code...
Ich habe ein Skript für eine Ladesteuerung einer Batterie geschrieben (bitte keine DIskussion über den Sinn dahinter... es ist für mich erstmal ein Weg in ein Thema reinzukommen), das grundsätzliche Prinzip sieht folgendermaßen aus: Ich habe eine Ladeplatine, die ich mit einem Raspberry Pi via CAN anspreche. Je nach Nachricht, die ich der Ladeplatine schicke, setzt diese etwa eine Spannung an um die Batterie zu laden, sendet einen Heartbeat (wichtig, weil sonst die Ladeplatine nach einer gewissen Zeit "aus geht" wenn kein Heartbeatrequest gesendet wird), sendet die auf der Platine gemessene Spannung oder beendet den Ladevorgang.
Der Sinn des Skripts ist folgender: Zunächst wird ein Can-Bus aufgebaut. Dann soll eine Excel-Datei erstellt werden, die nachfolgend die Platinenspannung sekündlich loggt. Schön wäre, wenn die Datei je nachdem, wann ich das Skript ausführe, folgende Kennzeichnung hat: Platinenspannung_TTMMJJJJ und wenn ich das Skript mehrmals am selben Tag ausführe nicht überschreibt, sondern dann einfach etwa noch eine (2) ans Ende schreibt.
Das Skript soll dann sekündlich die Platinenspannung abfragen und ausgeben. Da die Antwort der Platine bei Spannungsabfrage in Hex kommt, muss diese noch konvertiert werden. Gleichzeitig soll alle 10 Sekunden ein Heartbeatrequest an die Platine gesendet werden, damit diese nicht einfach "ausgeht". Sobald die Platinenspannung 3 mal einen bestimmten Wert erreicht hat (etwa 41000 mV), soll die Nachricht zum beenden des Ladevorgangs gesendet & die Excel-Datei geschlossen werden sowie der Heartbeat-Task beendet werden.
Im Folgenden seht ihr meinen derzeitigen Code:
Code: Alles auswählen
import can
import time
import os
import sys
import queue
import colorama
from colorama import Fore
from threading import Thread
import threading
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
# Bus-channel aufbauen
try:
bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except OSError:
print('Cannot find PiCAN board.')
exit()
threadtasks=True
Stopp_Charge = 0x00200039
Start_Charge = 0x00200038
Heartbeat_Request = 0x0FE00000 #Can-Nachrichten für die Ladeplatine
Voltage_Request = 0x00200040
Voltage_Reply = 0x00002006
outfile = open('Platinenspannung_Datum.csv','w', newline='')
def start_charge():
msg = can.Message(arbitration_id=Start_Charge,data=[],extended_id=True)
bus.send(msg)
print(Fore.BLUE + "\n" "Charging initiated" "\n")
print(Fore.RESET)
start_charge()
def stopp_charge():
msg = can.Message(arbitration_id=Stopp_Charge,data=[],extended_id=True)
bus.send(msg)
print("Charging stopped. Battery full. Stop program")
global threadtasks
threadtasks=False
sys.exit(0)
def heartbeat_task(): # heartbeat thread
global threadtasks
while threadtasks:
time.sleep(600)
msg = can.Message(arbitration_id=Heartbeat_Request,data=[],extended_id=True)
bus.send(msg)
print(Fore.YELLOW + "\n" "Heartbeatrequest sent" "\n")
print(Fore.RESET)
def can_rx_task(): # Receive thread
global threadtasks
while threadtasks:
message = bus.recv()
if message.arbitration_id == Voltage_Reply:
q.put(message) # Put message into queue
def can_tx_task(): # Transmit thread
global threadtasks
while threadtasks:
msg = can.Message(arbitration_id=Voltage_Request,data=[],extended_id=True)
bus.send(msg) #Sent a Voltage request
time.sleep(1)
heart = Thread(target = heartbeat_task)
heart.start()
q = queue.Queue()
rx = Thread(target = can_rx_task)
rx.start()
tx = Thread(target = can_tx_task)
tx.start()
try:
while True:
while(q.empty() == True): # Wait until there is a message
pass
message = q.get()
s=''
for i in range(message.dlc ):
s += '{0:x} '.format(message.data[i])
x = s.split() #Konvertierung in DEZ
y = x[0]
z = x[1]
if len(y) == 1:
y = '0' + y
volt = int(z+y, 16)
if volt > 41000:
print(Fore.RED + "\n"'OVERHEATING')
print(Fore.RESET)
outfile.close()
stopp_charge()
else:
print(volt, 'mV')
print(volt, file = outfile) # Save data to file
except KeyboardInterrupt:
print(Fore.RED + '\n\r keyboard interrupted\n')
print(Fore.RESET)
outfile.close() # Close logger file
stopp_charge()
Ich bin für jede Hilfe wirklich dankbar
