Auslesen MPU6050 via I2C & ESP8266 (micropython)

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

Hallo zusammen,

ich bin neu hier und will nicht direkt unangenehm auffallen. :-) Darf ich hier meinen Code posten? Ich habe keine Regeln gefunden die das explizit ausschließen.
Wenn ja, würde ich direkt durchstarten.

Danke für eine kurze RM.
TobiasKB
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Klar, es wird sogar darum gebeten. Denn worüber sonst sollte man sich unterhalten?
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

Fair enough. :-) Danke für die Antwort. Dann lege ich mal direkt los.

Folgendes Problem:
Ich habe einen ESP8266 mit meiner MPU6050 verbunden und möchte via mqtt meinen Raspi als Broker vernetzen. Der MPU6050 ist dann mein Publisher. Die Subscriberseite habe ich noch nicht implementiert. Ich versuche zunächst die Publisher-Broker-Beziehung zu "errichten". Dazu lese ich die Daten mittels mircopython auf dem ESP8266 aus. Diese sollen dann publisht werden.

Das ist der Code mit dem ich den i2c lokal auf dem ESP8266 auslese. Wenn ich nur diesen Code ausführe, funktioniert es und ich bekomme die gewünschten Ausgaben.

Code: Alles auswählen

from machine import I2C, Pin

class acc():
    def __init__(self, i2c, sensor_id="MPU6050", addr=0x68):
        self.iic = i2c
        self.sensor_id = sensor_id
        self.addr = addr
#Line 8       self.iic.start()
        self.iic.writeto(self.addr, bytearray([107,0]))
        self.iic.stop()
      
    def get_raw_values(self):
        self.iic.start()
        a = self.iic.readfrom_mem(self.addr, 0x3B, 6)
        self.iic.stop()
        return a
        
    def bytes_toint(self, firstbyte, secondbyte):
        if not firstbyte & 0x80:
            return firstbyte << 8 | secondbyte
        return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)
    
    def get_values(self):
        raw_ints = self.get_raw_values()
        vals = {}
#        print(raw_ints[0])
#        print(vals)
        vals["AcX"] = self.bytes_toint(raw_ints[0], raw_ints[1]) / 16384.0
        vals["AcY"] = self.bytes_toint(raw_ints[2], raw_ints[3]) / 16384.0
        vals["AcZ"] = self.bytes_toint(raw_ints[4], raw_ints[5]) / 16384.0
        return vals

if __name__ == "__main__":   #if __name__ == "__main__": means: this code runs only if file is executed and not when it is imported
    i2c = I2C(scl=Pin(5), sda=Pin(4))
    accelerometer = acc(i2c)
    print(accelerometer.get_values())
    print(type(accelerometer.get_raw_values()))
Mit dem nachfolgenden Code will ich nun den Code von oben importieren und die Daten publishen.

Code: Alles auswählen

from thingflow import *
from wifi import wifi_connect
from mqtt_writer import MQTTWriter
import network
from mpu6050mqtt2 import *
from machine import I2C

ap = network.WLAN(network.AP_IF)
ap.active(False)
wlan = network.WLAN(network.STA_IF)
wlan.active(True)

SID="Messnetz"
PASSWORD="'########"
MQTT_HOST="192.168.1.1"
wifi_connect(SID, PASSWORD)
m = MQTTWriter("esp8266", MQTT_HOST, 1883, "sensor-data")

#Line 19  sensor = SensorAsOutputThing(acc(1))  
sensor.connect(Output())
sensor.connect(m)

sched = Scheduler()
sched.schedule_periodic(sensor, 2.0)
sched.run_forever()
Nun bekomme ich folgende Traceback:
File "<stdin>", line 19, in <module>
File "mpu6050mqtt2.py", line 8, in __init__
AttributeError: "int" object has no attribute "start"

Da stehe ich jetzt auf dem Schlauch. Wenn ich die Datei allein ausführe, ohne sie zu importieren, initialisiere ich den I2C "außerhalb" der Klasse und ich bekomme meinen Output.

Ich habe nun noch in dieser Form versucht das Problem zu lösen, erreiche aber auch nichts... Standalone ausgeführt bekomme ich beim nachfolgenden Code wieder meine gewünschten Ergebnisse.

Code: Alles auswählen

from machine import I2C, Pin


class Accel:
    def __init__(self, i2c, scl_pinno=5, sda_pinno=4, addr=0x68):
        self.i2c = I2C(scl=Pin(scl_pinno, Pin.IN),
                       sda=Pin(sda_pinno, Pin.IN))
        self.addr = addr
        self.i2c.start()
        self.i2c.writeto(self.addr, bytearray([107, 0]))
        self.i2c.stop()
        self.counter = 0

    def get_raw_values(self):
        self.i2c.start()
        a = self.i2c.readfrom_mem(self.addr, 0x3B, 6)
        self.i2c.stop()
        return a

    def get_ints(self):
        b = self.get_raw_values()
        c = []
        for i in b:
            c.append(i)
        return c

    def bytes_toint(self, firstbyte, secondbyte):
        if not firstbyte & 0x80:
            return firstbyte << 8 | secondbyte
        return - (((firstbyte ^ 255) << 8) | (secondbyte ^ 255) + 1)

    def get_values(self):
        raw_ints = self.get_raw_values()
        vals = {}
        vals["accX"] = self.bytes_toint(raw_ints[0], raw_ints[1]) / 16384.0
        vals["accY"] = self.bytes_toint(raw_ints[2], raw_ints[3]) / 16384.0
        vals["accZ"] = self.bytes_toint(raw_ints[4], raw_ints[5]) / 16384.0
        
        return vals  # returned in range of Int16
    
if __name__ == "__main__":   #if __name__ == "__main__": means: this code runs only if file is executed and not when it is imported
    i2c = I2C(scl=Pin(5), sda=Pin(4))
    accelerometer = Accel(i2c)
    print(accelerometer.get_values())
Ich freue mich über Unterstützung. Ich stehe noch am Anfang meiner Codingkarriere. Seht mir ggfs. Fehler nach.

Tobias
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na was ist denn der Unterschied zwischen

Code: Alles auswählen

i2c = I2C(scl=Pin(5), sda=Pin(4))
acc(i2c)
und

Code: Alles auswählen

acc(1)
?
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

:D Okay, challenge accepted. Ich versuch mich mal. Danke für dein schnelles erstes Feedback!

Wenn ich NUR auf acc() schaue, wird bei acc(1) nicht i2c als Argument berücksichtigt und i2c nicht initialisiert? :-) Wie aber löse ich das Problem, wenn ich die Klasse acc() importiere? Wo müsste ich bei Aufruf den i2c initialisieren? Ich stehe auf dem Schlauch. :? In der mpu6050mqtt2.py oder in der Aufruf-Datei mit dem thingflow code?

Ich habe versucht das Thingflow Tutorial auf meinen Code zu übertragen...

https://thingflow-python.readthedocs.io ... put-things

https://thingflow-python.readthedocs.i ... -a-sensor
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Dieses `acc` erwartet als erstes Argument ein I2C-Objekt, Du übergibst aber eine 1. Das kann nicht funktionieren. An anderen Stellen erzeugst Du ja I2C-Objekte.
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

Du hast Recht. Danke dir.

Ich habe den Code wie folgt angepasst. Aufruf mit acc(1, I2C)

Code: Alles auswählen

sensor = SensorAsOutputThing(acc(1, I2C)
Nun bekomme ich wieder einen traceback für folgende Codezeile:

Code: Alles auswählen

4 def __init__(self, I2C, scl_pinno=5, sda_pinno=4, sensor_id="MPU6050", addr=0x68):
5 	self.iic = I2C(-1, scl=Pin(scl_pinno, Pin.IN), sda=Pin(sda_pinno, Pin.IN))
File "mpu6050mqtt.py", line 5, in __init__
TypeError: can´t convert type to int

Wenn ich die "mpu6050mqtt.py" nicht importiere und direkt ausführe über die if __name__ == "__main__" Bedingung, habe ich das Problem nicht. Warum taucht jetzt dieser Fehler auf? Egal wie ich das google, da find ich nix.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was soll denn dieses 1 beim acc? Warum denkst du, du brauchst das?
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

Hi __deets__, ganz ehrlich, die Frage ist berechtigt. Ich hatte das irgendwo bei thingflow im Tutorial gelesen. Hier siehst du das:

https://thingflow-python.readthedocs.io ... g-a-sensor

Code: Alles auswählen

from thingflow.base import SensorAsOutputThing
MEAN = 100
STDDEV = 10
sensor = SensorAsOutputThing(RandomSensor(1, MEAN, STDDEV, stop_after=5))
Warum nehmen die hier die 1 auf??

Ich denke, dass ich das unreflektiert übernommen habe... Jetzt ohne die 1 habe ich einen ganz anderen Traceback an anderer Stelle im Code. Das muss ich jetzt einmal ergründen. Jetzt habe ich einen traceback in der thingflow.py Datei. Da habe ich wahrscheinlich vorher noch etwas vergeigt... Ich muss mir das jetzt erst einmal ansehen.
tobiaskb
User
Beiträge: 8
Registriert: Donnerstag 12. November 2020, 17:35

Hallo __deets__, du hast mich auf die richtige Spur gebracht. Meinen raspi erreichen nun die Posts von meinem Sensor!!!

Mille grazie und ein schönes WE dir.

Ggfs. bis bald. :-)
Man, das fühlt sich gut an. :-) :-)
Antworten