Anfänger! hat math domain error und ??? im Kopf

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Benutzeravatar
ich.froehlich
User
Beiträge: 3
Registriert: Dienstag 7. April 2020, 15:39

Hallo Zusammen,

ich wollte es langsam angehen und habe erstmal ein Sensor Kit zum Warmwerden gekauft. Mit fertigen Code Snippets zum ausprobieren. leider Läuft der aber nicht. Folgende Fehlermeldung:

Traceback (most recent call last):
File "18_thermistor.py", line 61, in <module>
loop()
File "18_thermistor.py", line 35, in loop
temp = 1/(((math.log(Rt / 10000)) / 3950) + (1 / (273.15+25)))
ValueError: math domain error

Das Coding dazu :

import PCF8591 as ADC
import RPi.GPIO as GPIO
import time
import math

DO = 17
GPIO.setmode(GPIO.BCM)

def setup():
ADC.setup(0x48)
GPIO.setup(DO, GPIO.IN)

def Print(x):
if x == 1:
print ''
print '***********'
print '* Better~ *'
print '***********'
print ''
if x == 0:
print ''
print '************'
print '* Too Hot! *'
print '************'
print ''

def loop():
status = 1
tmp = 1
while True:
analogVal = ADC.read(0)
Vr = 5 * float(analogVal) / 255
Rt = 10000 * Vr / (5 - Vr)
temp = 1/(((math.log(Rt / 10000)) / 3950) + (1 / (273.15+25)))
temp = temp - 273.15
print (‚temperature = ', temp, ‚C‘)

# For a threshold, uncomment one of the code for
# which module you use. DONOT UNCOMMENT BOTH!
#################################################
# 1. For Analog Temperature module(with DO)
#tmp = GPIO.input(DO);
#
# 2. For Thermister module(with sig pin)
if temp > 33:
tmp = 0;
elif temp < 31:
tmp = 1;
#################################################

if tmp != status:
Print(tmp)
status = tmp

time.sleep(0.2)

if __name__ == '__main__':
try:
setup()
loop()
except KeyboardInterrupt:
pass

Ich habe mit den Suchbegriffen die mir einfielen keinen Thread gefunden.... Hat jemand eine Hilfestellung? Bitte nicht im Telegrammstil, da ich Einsteiger in Python bin.
Danke
Gruß von
ich.froehlich
Benutzeravatar
noisefloor
User
Beiträge: 3857
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

den "math domain error" bekommt man, wenn man den Logarithmus von Null oder einer negativen Zahl berechnen will, weil das nicht geht. Welche Werte hat `Rt` denn bei dir?

Den Code bitte nächstes mal in eine Codeblock setzen, sonst ist das nicht wirklich lesbar. Den Codeblock bekommst du, indem du im vollständigen Editor auf die Code-Schaltfläche `</>` klickst.

Gruß, noisefloor
Benutzeravatar
ich.froehlich
User
Beiträge: 3
Registriert: Dienstag 7. April 2020, 15:39

Hallo noisefloor,

Codeblock werde ich mir merken, Danke. Habe den ganzen Tag getüftelt um die Werte zu bekommen. Habe das Modul PCF8195 debugt um zu sehen was der liefert. Dabei habe ich festgestellt, das AIN0 '0' liefert. AIN1 jedoch Werte zwischen66 und 80. Hatte die Idee da ein Ami Sensor das es Fahrenheit sein könnte. 0 grad Fahrenheit = -17, irgendwas Grad C. 66 grad sind um die 18 Grad. zudem blieb AIN0 immer '0'. Habe im Code analogVal = ADC.read(0) auf (1) geändert und jetzt läuft es.Hat mich aber auch den ganze Tag gequält, das ding. Saublöder Fehler....und bitter für Anfänger
Danke für den Tipp hat mich auf die richtige Spur gebracht.
Gruß ich.froehlich
Gruß von
ich.froehlich
Benutzeravatar
__blackjack__
User
Beiträge: 13121
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ich.froehlich: In Python 2 sollte man keinen Code mehr schreiben. Das hat keine Unterstützung von den Entwicklern mehr.

So kann das nie gelaufen sein, denn die Zeile wo die Temperatur ausgegeben wird enthält typografische Anführungszeichen die keine gültige Python-Syntax sind.

``as`` bei Importen ist dazu da etwas umzubennenen. `GPIO` wird aber gar nicht umbenannt.

Der `GPIO.setmode()`-Aufruf gehört nicht auf Modulebene. Ich finde die `setup()`-Funktion auch nicht so wirklich überzeugend. Das würde ich mit dem Rest aus dem ``if __name__ …``-Zweig in eine Hauptfunktion schreiben. Da kann man dann in einem ``finally``-Zweig auch gleich noch den fehlenden `GPIO.cleanup()`-Aufruf unterbringen.

`DO` ist kein guter Name. Da weiss doch ausser Dir keiner was der bedeutet. Namen sollen dem Leser vermitteln was der Werte dahinter im Kontext des Programms bedeutet.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

`status` und `tmp` nehmen nur die Werte 0 und 1 an, und die Verwendung sieht sehr nach einem Wahrheitswert aus der aussagt ob es zu heiss ist oder nicht. Das sollte man am Namen ablesen können. Und `tmp` ist wieder eine schlechte Abkürzung. Noch schlechter wird es dadurch das in der gleichen Funktionen auch noch `temp` als Name verwendet wird. Beides sind Abkürzungen für „temporary“ und „temperature“. Was ist nun was? Wenn man für `tmp` wie für `status` einen aussagekräftigen Namen findet, und `temp` tatsächlich `temperature` nennt, besteht da keine Verwechslungsgefahr.

Die Semikolons an Zeilenenden sind überflüssig. Oft ein Zeichen das da jemand kein Python programmiert, sondern noch in einer anderen Programmiersprache denkt.

Die Berechnungen sind eigenartig kompliziert. Der gelesene Wert wird mit 5 multipliziert und dann durch 255 geteilt statt den einfach durch 51 zu teilen.

Bei `Rt` ist es noch komischer, weil da erst mit 10000 multipliziert wird um am Ende dann wieder druch 10000 zu teilen. Das macht keinen Sinn.

Die `Print()`-Funktion unterscheidet sich bei den beiden ``if``-Zweigen nur durch den Text in der Mitte der Ausgabe. `x` ist ein schlechter Name, und da der Wert eh nur `True` und `False` sein kann, sind auch zwei ``if``\s unnötig.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import math
import time

import PCF8591 as ADC
from RPi import GPIO

#
# TODO Find a better name for this constants.
#
DO_PIN = 17


def print_if_too_hot(is_too_hot):
    text = "Too Hot!" if is_too_hot else "Better~"
    line = "*" * (len(text) + 4)
    print()
    print(line)
    print(f"* {text} *")
    print(line)
    print()


def loop():
    is_too_hot = was_too_hot = False
    while True:
        v_r = ADC.read(1) / 51
        temperature = (
            1 / ((math.log(v_r / (5 - v_r)) / 3950) + (1 / (273.15 + 25)))
        ) - 273.15
        print("temperature =", temperature, "°C")

        # For a threshold, uncomment one of the code for
        # which module you use. DONOT UNCOMMENT BOTH!
        #################################################
        # 1. For Analog Temperature module (with DO_PIN)
        # is_too_hot = not GPIO.input(DO_PIN)
        #
        # 2. For Thermister module (with sig pin)
        if temperature > 33:
            is_too_hot = True
        elif temperature < 31:
            is_too_hot = False
        #################################################

        if is_too_hot != was_too_hot:
            print_if_too_hot(is_too_hot)
            was_too_hot = is_too_hot

        time.sleep(0.2)


def main():
    try:
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(DO_PIN, GPIO.IN)
        ADC.setup(0x48)
        loop()
    except KeyboardInterrupt:
        pass
    finally:
        GPIO.cleanup()


if __name__ == "__main__":
    main()
Was mich hier noch stört ist das der GPIO-Pin 17 zwar als Eingang geschaltet wird, vom Code dann aber überhaupt nicht verwendet wird. Damit wird das `GPIO`-Modul überhaupt nicht gebraucht. Kommentarblöcke mitten im Code wo man Teile von auskommentieren soll, wo aber noch andere Teile vom Code von abhängen, das ist äusserst unschön und ein Wartungsalbtraum.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ich.froehlich
User
Beiträge: 3
Registriert: Dienstag 7. April 2020, 15:39

Hallo _blackjack_

Danke für die Ausführliche Unterstützung, ich werde deine Anregungen durcharbeiten und dein Coding ausprobieren. Wie ich schon sagte, in Sachen Python bin ich Anfänger. Das das Coding in Python2 ist hat sich mir nicht erschlossen. Das Coding wird so mit den Sensoren von SunFounder zur Verfügung gestellt. Aber es zeigt sich, dass man einem geschenkten Gaul doch ins Maul schauen muss :( .

Hätte es zum Anfang vielleicht mit kleineren Brötchen versuchen sollen :wink: . Aber so ist Ostern auch gerettet :lol:

Nochmal ehrlichen Dank
Gruß von
ich.froehlich
Antworten