Sie befinden sich hier: Lego® - Raspberry Pi - Raspberry Pi mit Lego NXT

Kommunikation zwischen Raspberry Pi und Lego mindstorms NXT


In diesem Tutorial wird eine Möglichkeit der Datenübertragung zwischen dem Lego mindstorms NXT und dem Raspberry Pi erläutert.
Es wird folgender Ansatz gewählt:

  • Zum senden der Daten, vom NXT zum Raspberry Pi, wird ein Motorausgang des NXT genutzt. Dieser gibt ein PWM- Signal (Pulsweitenmodulation) aus. Dieses PWM- Signal wird in ein Analog- Signal umgewandelt. Da der Raspberry Pi wiederum keine Analogen- Eingänge besitzt, wird dieses Signal anschließend über I2C an den Raspberry Pi gesendet.
  • Zum empfangen der Daten vom Raspberry Pi, werden die Digitalen- Ausgänge des Raspberry Pi genutzt. Dessen Werte werden dann über I2C an den NXT gesendet.

    Hinweis:
    Der Lego mindstorms NXT lässt sich nicht direkt mit dem Raspberry Pi über die I2C- Schnittstelle verbinden. Um das Problem der Spannungsdifferenz zwischen Raspberry Pi (3,3V) und NXT (4,3V) zu beheben, kann ein I2C- Repeater (PCA 9517) eingesetzt werden. Infolge dessen erkennt der Raspberry Pi auf der I2C Leitung etwas, aber es sind willkürliche, nicht brauchbare Daten. Das kommt daher, da der NXT mit einer Baudrate von 9600 bit/sec. und der Raspberry Pi mit einer anderen Baudrate arbeitet. Die Baudrate beider Geräte lässt sich nicht angleichen. Daher verstehen sie sich nicht.


Lego Mindstorms NXT sendet Daten an Raspberry Pi


Folgende Schaltung wandelt das PWM- Signal vom NXT Port A in ein Analoges Signal um. Dazu wird das PWM- Signal an einen Tiefpass angeschlossen. Am Ausgang des Tiefpasses befindet sich ein Operationsverstärker, der das Analoge Signal stabilisiert. Der PCF 8591 erhält das Analoge- Signal und sendet dieses über die I2C- Schnittstelle an den Raspberry Pi.

    stromlaufplan
    Da die I2C- Schnittstelle auf dem Raspberry Pi standardmäßig deaktiviert ist, muss diese aktiviert werden, sofern es noch nicht geschehen ist:
    • smbus ist bei Raspbian Stretch schon automatisch installiert. Sollte eine andere Version genutzt werden, muss smbus noch installiert werden.
    • Aktivieren der I2C- Schnittstelle:

      Über das Terminal mit 'sudo raspi- config' zur Konfiguration wechseln

      Interfacing Options auswählen

      I2C auswählen

      I2C- Schnittstelle aktivieren? -> Ja

      I2C- Schnittstelle wurde aktiviert -> ok

    • Wurde ein I2C Gerät über I2C mit dem Raspberry Pi verbunden, kann mit folgendem Befehl überprüft werden, ob die I2C- Schnittstelle funktioniert.

      i2cdetect : Befehl zum auffinden von I2C Geräten
      -y :              Befehl ohne Nachfrage ausführen
      1 :               I2C Bus 1 nutzen. In der Regel wird Bus 1 (Pin 3 und 5) genutzt, da Bus 0 in der Regel reserviert ist.

      In der obigen Schaltung wurde ein PCF 8591 mit dem Raspberry Pi über I2C verbunden. Das Bauteil wurde auf dem Bus erkannt und dessen Adresse (48) ausgegeben. Der I2C- Bus ist funktionsfähig eingerichtet. Wären weitere I2C Geräte/ Bauteile mit dem I2C Bus verbunden, würden auch deren Adresse angezeigt.

      Ein paar Infos zum PCF 8591:
      Der PCF 8591 ist ein A/D-D/A- Wandler mit einer Auflösung von 8-Bit. Somit kann er Werte von 0-255 ausgeben. In obiger Schaltung wird er als A/D- Wandler (Anlog/ Digital- Wandler) genutzt. Dazu stehen 4 analooge Eingänge zur Verfügung, wobei hier nur einer (AIN0) verwendet wird. Die restlichen Eingänge werden mit Masse verbunden.
      Über I2C verbundene Geräte müssen eine eindeutige Adresse erhalten, damit die Daten den entsprechenden I2C- Geräten zugeordnet werden können. Beim PCF 8591 legt man die Adresse über die Anschlüsse A0-A2 fest. Sie können auf Masse (LOW) oder an VDD (HIGH) gelegt werden. In diesem Fall liegen A0-A2 auf Masse. Dies ergibt die Adresse 48.


    Beispiel: Taster an NXT einlesen und Zustand an Raspberry Pi senden


    Im folgenden Beispiel werden Daten vom NXT an den Raspberry Pi gesendet. Dazu wird ein Taster an Input 2 vom NXT angeschlossen. Dessen Schaltzustände werden an den Raspberry Pi gesendet und dort ausgegeben.

    Auf dem NXT läuft folgendes LabVIEW Programm:

      Rohwert vom angeschlossenen Taster an NXT_Input-2 wird ausgelesen und an NXT_Port-A ausgegeben.
      Da am Motorport vom NXT nur Werte zwischen 0-100 (Prozent Leistung) möglich sind, wird der Rohwert zuvor rechnerisch angepasst.

    Auf dem Raspberry Pi läuft folgendes Python Programm:
      #!/usr/bin/python
      
      ''' I2C '''
      import smbus            
      bus = smbus.SMBus(1)    #I2C- Bus 1 kann im folgenden über bus angesprochen werden
      
      ''' PCF 8591 '''
      adresse = 0x48          # I2C Adresse
      channel_0 = 0x00        # Input AN0
      
      ''' Funktionen '''
      def readAD():           # I2C Geräte einlesen und Wert zurückgeben
         analog = bus.read_byte_data(adresse, channel_0)
         return analog
      
      def read_NXT():
         analog0 = readAD()                     # aktueller Analogwert
         analog0 = (analog0-180)*(-1)           # Werte intvertieren
         if analog0 > 170:					  
            print("Taster:", analog0, "FALSE")  # Ausgabe von 'Rohwert' und Boolean: Taster wurde NICHT betätigt
         else:
            print("Taster:", analog0, "TRUE")   # Ausgabe von 'Rohwert' und Boolean: Taster wurde betätigt     
      
      ''' Hauptprogramm '''
      while True:   
         read_NXT()  							  # Aufruf der Funktion read_NXT    
          
      Im Hauptprogramm wird die Funktion 'def read_NXT()' aufgerufen. Diese ruft die Funktion 'def readAD()' auf und gibt den aktuellen Analogwert zurück. Dieser wird nun in der Funktion 'def read_NXT' weiter verarbeitet. Auf dem Bildschirm wird der aktuelle Schaltzustand ausgeben.

    Ausgabe des Python- Programms:
      Aktueller Schaltzustand


Lego Mindstorms NXT empfängt Daten vom Raspberry Pi


Der PCF 8574 ist ein über I2C-Bus angeschlossener 8-Bit I/O Port-Expander. Da dem Raspberry Pi nur eine begrenzte Anzahl von Ports zur Verfügung steht, können irgendwann alle Ports belegt sein. Mit dem PCF 8574 stehen weitere Digitale Ports zur Verfügung, wenn man ihn als Output verwendet. Hier wird der PCF 8574 als Input verwendet, um Daten via I2C an den NXT zu senden.
GPIO 18 (Pin12) besitzt 2 Binäre Zustände. 1 und 0. Diese werden den Tasterzustand (Taster an GPIO 23 betätigt - Taster an GPIO 23 nicht betätigt) 'anzeigen'.


Beispiel: Taster an Raspberry Pi einlesen und Zustand an Lego mindstorms NXT senden


Im folgenden Beispiel werden Daten vom Raspberry Pi an den NXT gesendet. Dazu wird ein Taster an GPIO 23 vom Raspberry Pi angeschlossen. Dessen Schaltzustände werden an den NXT gesendet und dort ausgegeben.

Auf dem NXT läuft folgendes LabVIEW Programm:

    Da beim PCF 8574 A0-A2 auf Masse liegen, besitzt er die Adresse Dez: 64. Dies ist der erste Wert der I2c Kommunikation.
    Der zweite Wert Dez: 15 legt die Ports P0-P3 als Eingänge fest. Hier würde es genügen den Wert 1 einzufügen, da nur P0 als Eingang genutzt wird. Die Werte der Case- Struktur müssten dann mit 0 und 1 angepasst werden.

    Auf dem Raspberry Pi läuft folgendes Python Programm:
      # Wird der Taster an GPIO 23 betätigt, ändert GPIO 18 seinen Status
      # Status von GPIO 18 wird an NXT übermittelt 
      
      #!/usr/bin/python
      
      import RPi.GPIO as GPIO 				# GPIO- Bibliothek importieren und Kürzel festlegen
      
      GPIO.setwarnings(False)					# Warnungen unterdrücken
      GPIO.setmode(GPIO.BCM)  				# GPIO-Portnummern verwenden
      GPIO.setup(18, GPIO.OUT, initial=0) 	# initialisiert GPIO-Port 18 als Ausgang mit Anfangswert 0 (AUS) 
      GPIO.setup(23, GPIO.IN, GPIO.PUD_DOWN) 	# initialisiert GPIO-Port 23 als Eingang; interner Pulldown Widerstand
      TASTER = 23     						# Variable für GPIO 23
      
      while True:
          if GPIO.input(TASTER)==True:
              GPIO.output(18, 1)  			# GPIO-Port 18 EIN
          else:
              GPIO.output(18, 0)  			# GPIO-Port 18 AUS
          
      GPIO 18 wird ja nach Tasterzustand (GPIO 23) EIN oder AUS geschaltet

    Ausgabe des Vi's:
      Taster wurde nicht betätigt Taster wurde betätigt


Komplettes Programm zum gleichzeitigen senden und empfangen von Daten


Im folgenden Beispiel werden nun Daten vom NXT an den Raspberry Pi gesendet und empfangen. Dazu sind ein Taster an Input 2 vom NXT und ein Taster am Raspberry Pi GPIO 23 angeschlossen. Die jeweiligen Schaltzustände werden an den Raspberry Pi und NXT gesendet.

Auf dem NXT läuft folgendes LabVIEW Programm:

    LabVIEW- Vi

Auf dem Raspberry Pi läuft folgendes Python Programm:
    #!/usr/bin/python
    import smbus 
    import RPi.GPIO as GPIO 
    
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)                 
    GPIO.setup(18, GPIO.OUT, initial=0)     
    GPIO.setup(23, GPIO.IN, GPIO.PUD_DOWN) # Taster an Raspberry Pi
    TASTER = 23                    
    
    ''' I2C '''
    bus = smbus.SMBus(1)
    
    ''' PCF 8591 '''
    adresse = 0x48      # I2C Adresse
    channel_0 = 0x00    # Input AN0
    
    ''' I2C Geräte auslesen - PCF 8591 '''
    def readAD():
       analog = bus.read_byte_data(adresse, channel_0)
       return analog
    
    ''' aktueller Schalterzustand - NXT Input 2 '''
    def read_NXT():
       analog0 = readAD()
       analog0 = (analog0-180)*(-1)      
       if analog0 > 170:
          print("Taster:", analog0, "FALSE")
       else:
          print("Taster:", analog0, "TRUE")
    
    ''' aktueller Schalterzustand - Raspberry Pi GPIO 18 '''
    def write_NXT():
       if GPIO.input(TASTER)==True:
            GPIO.output(18, 1)  			# GPIO-Port 18 EIN
       else:
            GPIO.output(18, 0)  			# GPIO-Port 18 AUS
           
    ''' Hauptprogramm '''
    while True:   
       read_NXT() 		# Funktionsaufruf read_NXT
       write_NXT() 		# Funktionsaufruf write_NXT
        
    Python Programm


Ich kann keinerlei Haftung für die Schaltungen übernehmen und auch keine Funktionsfähigkeit garantieren. Der Nachbau und Einsatz der hier veröffentlichten Schaltungen erfolgt auf eigene Gefahr. Ich übernehme keinerlei Garantie. Die VDE-Vorschriften sind zu beachten.