Für einen selbst entwickelten Bordcomputer auf Basis eine RaspberryPi 4, habe ich mehrere kleine Programme geschrieben die Messdaten erfassen und sie in eine Influx Datenbank schreiben die ebenfalls auf dem Pi installiert ist. Weitere Messwerte werden über Mikrocontroller erfasst und mittels Wlan in die Datenbank geschrieben. Die Visualisierung erfolgt dann über Grafana, das ebenfalls auf dem Pi ausgeführt wird.
Soweit läuft alles zu meiner Zufriedenheit. Jetzt habe ich nur das Problem, dass mein Raspberry an seine Grenzen kommt wenn alle Programm aktiv sind.
Der CPU Load wandert weit über 4 und die Visualisierung beginnt zu "Ruckeln".
Um ein besseres Gefühl davon zu bekommen was die CPU so beansprucht habe ich zunächst mal nur einzelne Anwendungen gestartet und die Auslastung mit htop angeschaut.
Dabei ist mir aufgefallen, dass jedes der grösseren Programme schon einen der vier Kerne zu 100% beansprucht.
Hier eins der besagten Programme als Beispiel:
import time
import board
import busio
import subprocess
import digitalio
import datetime
import adafruit_gps
import serial
import neopixel
from influxdb import InfluxDBClient
# InfluxDB
client = InfluxDBClient(host='192.168.100.79', port=8086, username='xxx', password='xxx')
client.switch_database('T3')
# NeoPixel
pixel_pin = board.D12
num_pixels = 2
ORDER = neopixel.RGB
pixels = neopixel.NeoPixel(pixel_pin, num_pixels)
pixels[0] = (0, 0, 0)
pixels[1] = (0, 0, 0)
# .nmea-Datalogger
LOG_MODE = 'ab'
Datum = '{:%Y_%m_%d}'.format(datetime.datetime.now())
LOG_FILE = '/media/usb0/' + Datum + '_GPS.nmea'
print(LOG_FILE)
# Serial
uart = serial.Serial("/dev/ttyS0", baudrate=9600, timeout=10)
# Create a GPS module instance.
gps = adafruit_gps.GPS(uart, debug=False) # Use UART/pyserial
# Turn on the basic GGA and RMC info (what you typically want)
gps.send_command(b'PMTK314,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0')
# Set update rate to 2 second (0,5hz) which is what you typically want.
gps.send_command(b'PMTK220,2000')
toggle = True #Abweselnd tracken und ausgeben
last_save = '{:%Y_%m_%d}'.format(datetime.datetime.now())
last_print = time.monotonic()
wait_influx = time.monotonic()
while True:
current = time.monotonic()
if current - last_print >= 2.0:
last_print = current
# Auf neue Daten warten und abwechselnd GGA und RMC zuweisen
if toggle:
if not gps.update():
continue
waste = gps.readline()
toggle = False
else:
if not gps.update():
continue
gps.update()
toggle = True
# Auf Fix warten
if not gps.has_fix:
print('Waiting for fix...')
pixels[0] = (60, 0, 0)
continue
pixels[0] = (0, 60, 0)
# Ausgabe
print('=' * 40) # Print a separator line.
print('Fix timestamp: {}/{}/{} {:02}:{:02}:{:02}'.format(
gps.timestamp_utc.tm_mday, # Grab parts of the time from the
gps.timestamp_utc.tm_mon, # struct_time object that holds
gps.timestamp_utc.tm_year, # the fix time. Note you might
gps.timestamp_utc.tm_hour, # not get all data like year, day,
gps.timestamp_utc.tm_min, # month!
gps.timestamp_utc.tm_sec))
print('Latitude: {0:.6f} degrees'.format(gps.latitude))
print('Longitude: {0:.6f} degrees'.format(gps.longitude))
print('Fix quality: {}'.format(gps.fix_quality))
if gps.satellites is not None:
print('Satellites: {}'.format(gps.satellites))
if gps.altitude_m is not None:
print('Altitude: {} meters'.format(gps.altitude_m))
if gps.speed_knots is not None:
print('Speed: {} knots'.format(gps.speed_knots))
if gps.track_angle_deg is not None:
print('Track angle: {} degrees'.format(gps.track_angle_deg))
if gps.horizontal_dilution is not None:
print('Horizontal dilution: {}'.format(gps.horizontal_dilution))
if gps.height_geoid is not None:
print('Height geo ID: {} meters'.format(gps.height_geoid))
# Influx
influx_altitude = float(0 if gps.altitude_m is None else gps.altitude_m)
influx_satellites = int(0 if gps.satellites is None else gps.satellites)
influx_latitude = float(0 if gps.latitude is None else gps.latitude)
influx_longitude = float(0 if gps.longitude is None else gps.longitude)
influx_speed_kmh = float(0 if gps.speed_knots is None else gps.speed_knots) * 1.852
influx_dop_inv = float(0 if gps.horizontal_dilution is None else gps.horizontal_dilution) * -1
influx_angle = float(0 if gps.track_angle_deg is None else gps.track_angle_deg)
influx_fix = int(0 if gps.fix_quality is None else gps.fix_quality)
InfluxData = [
{
"measurement": "GPS",
"tags": {},
"":"",
"fields": {
"Altitude": '{0:.1f}'.format(influx_altitude),
"Satellites": '{}'.format(influx_satellites),
"Latitude": '{0:.6f}'.format(influx_latitude),
"Longitude": '{0:.6f}'.format(influx_longitude),
"Speed": '{0:.1f}'.format(influx_speed_kmh),
"DOP": '{0:.2f}'.format(influx_dop_inv),
"Angle": '{0:.1f}'.format(influx_angle),
"Fix": '{}'.format(influx_fix)
}
}
]
pixels[1] = (0, 0, 60)
client.write_points(InfluxData)
# Loggfile schreiben
sentence_1 = gps.readline()
sentence_2 = gps.readline()
print()
print(str(sentence_1, 'ascii').strip())
print(str(sentence_2, 'ascii').strip())
# Loggfile speichern
if last_save != '{:%Y_%m_%d}'.format(datetime.datetime.now()):
Datum = '{:%Y_%m_%d}'.format(datetime.datetime.now())
LOG_FILE = '/media/pi/USB/' + Datum + '_GPS.nmea'
last_save = Datum
print(LOG_FILE)
outfile = open(LOG_FILE, LOG_MODE)
outfile.write(sentence_1)
outfile.write(sentence_2)
outfile.flush()
pixels[1] = (0, 0, 0)
Alles anzeigen
Das Programm wertet alle zwei Sekunden die Signale eines GPS-Empfängers über die Serielle Schnittstelle aus und speichert sie in eine .txt und in die InfluxDB.
Bedarf das wirklich so viel Kapazitäten ? Selbst wenn ich das Intervall auf 4s oder größer setze ändert das nicht viel.
Kann es sein das bereits meine "Warteschleife" viel Rechenleistung benötigt ?
Welche Möglichkeiten habe ich um das Programm Ressourcen schonender aufzubauen ?
Wenn es eine Rolle spielt, ich habe auf dem Pi Raspbian Light installiert und starte die Programme nach dem Booten über jeweils einen Service.