Serielle Komunikation - Python (ursprünglich über Win Komandozeile)

Hallo liebes Forum,

Ich wollte mit meinem PC Funksteckdosen per Webbrowser kontrollieren. Es gibt ja bereits einige realisierungen mittels Netzwerkshield, bei mir soll alles über einen PC als Server laufen.

Mittlerweile habe ich mich so weit in IIS und Python eingelesen, dass ich es schaffe einfache *.bat Dateien zu öffnen. Der Arduino lässt sich aber nur per Seriellen Port richtig steuern und ansprechen, wenn einmalig die Komunikation über die Arduino Software aufgebaut wurde.

Ich vermute es wird irgendeine Initialisierungsbotschaft gesendet. Könnt ihr mir helfen diese Botschaft einmalig über die Dos Komandozeile zu senden?

Es gibt keine Initialisierungsbotschaft. Allerdings resettet der Arduino normalerweise beim Aufbau der seriellen Verbindung, daher dauert es natürlich etwas bis das eigentliche Programm läuft. Könnte es daran liegen?

Revox:
Ich vermute es wird irgendeine Initialisierungsbotschaft gesendet. Könnt ihr mir helfen diese Botschaft einmalig über die Dos Komandozeile zu senden?

Nein, ein am PC angeschlossener Arduino führt jedesmal einen automatischen Reset aus, wenn am PC die serielle Schnittstelle geöffnet wird. Das nennt sich “Auto-Reset” und dient dem komfortablen Hochladen von Programm-Sketchen ohne am Reset-Button rumfummeln oder einen ISP-Programmer verwenden zu müssen. Dann läuft zunächst mal der Bootloader, und wenn einige Sekunden lang kein neuer Sketch hochgeladen wird, startet der vorhandene Sketch auf dem Arduino. Sobald der läuft und dort die Initialisierung mit Serial.begin(9600); (oder welche Baudrate auch immer) abgelaufen ist, ist die Schnittstelle für die Kommunikation bereit.

Korrektes Verhalten einer seriellen Anwendung auf dem PC wäre also:

  • serielle Schnittstelle zum Arduino öffnen
  • einige Sekunden warten bis der Arduino vollständig resettet hat
  • dann die serielle Kommunikation beginnen

Alternativ kannst Du den Auto-Reset auf dem Arduino-Board abschalten, z.B. durch einen Kondensator von 10 Mikrofarad zwischen GND und Reset Pin. Allerdings kannst Du Sketche per Bootloader dann nur mit manuellem Reset hochladen.

Wenn Du unter Windows z.B. so eine Kommandozeile eingibst um das Datum an COM10 zu senden:
echo %date% >\.\COM10
dann funktioniert das auf einem Arduino mit aktiver Auto-Reset Schaltung nicht: Diese Zeile öffnet den COM-Port und sendet die Zeichen unmittelbar, die am Arduino genau dann eintreffen, wenn er gerade resettet und seinen Bootloader laufen hat (der damit nichts anfangen kann).

Öffnen des entsprechenden COM-Ports am PC ist die eine Sache. Unter Beachtung der kleinen Zeitverzögerung bis zum ersten "Befehl".

Ich denke mal, Revox's Problem besteht darin, wie er sich nun mit welchen Kommandos mit dem Arduino unterhalten soll, bzw. was der macht wenn man ihm was sagt und was er ggf. zurücksendet, wenn man ihn was fragt.

Da gibt es - so weit ich weiß - keine festen Regeln. D.h. jeder muss sich sein eigenes Protokoll nach eigenen Wünschen/Erfordernissen selbst basteln.

Vielen Dank schon mal für die Antworten!

Ich hätte insgesammt nicht gedacht, dass ich mein Ziel so schnell Erreiche. Nochmal eine kurze Zusammenfassung was ich bisher geschafft habe:

  • Mittels der RS switch Libary (http://code.google.com/p/rc-switch/wiki/HowTo_Send?tm=6) habe ich erfolgreich meine Steckdosen ansprechen können.
  • Mein Komunikationsprotokoll über die Serielle Schnittstelle ist SEHR einfach ein A schaltet DoseA an, ein a schaltet DoseA aus. Die Umwandlung zwischen Asci Zeichen und der jeweiligen Steckdose ist hart im Code integriert
  • Da die Dos Komandozeile anscheinend Steuerzeichen mitsendet habe ich den folgenden Befehl gefunden: “set /p x=“A” \.\COM9” der die Steuerzeichen weglässt
  • Mittels Python habe ich es geschafft in meinem IIS Servers die *.bat Dateien mit den Com Komandos zu starten (vielleicht ginge es auch direkt mit Python, ich wollte aber die Bat Dateien eventuell auch für die Windows aufgabenplanung verwenden). Dieser Teil hat am längsten gedauert, da die Rechtevergabe in IIS und Win 2012 Server nicht so einfach ist
  • Mit dem genailem Android Programm “Tasker” habe ich Desktop Icons erstellt, mit einem HTTP GET befehl, sodass die Python skripte ausgeführt werden

Sobald ich einmalig den Seriellen Monitor der Arduino Software öffne und anschließend schließe, funktioniert das senden über die Komandozeile.
Ohne das Starten des Seriellen Monitors funktioniert jenes nicht. Dies ist leider unabhängig davon, ob ich den Resetpin durch Anbringen eines Kondensators blockiere.
Übrigens habe ich für das Projekt meinen Diavolino verwendet, wohlmöglich ist dort die Hardware doch etwas verschieden. Dort ist die USB to Serial Brücke im USB Stecker integriert und eine Leitung wird an kapazitiv mit dem Reset Pin gekoppelt.

Ich verwende im Moment Pin 13 um die Stromversorgung für das Sendemodul zur Verfügung zu stellen, da ich so das Modul direkt auf den Arduino stecken konnte. Pin 13 auch an den ISP Header. Könnte hier der Fehler liegen ?

Vielleicht bringt dich ein kleiner Blich in dieses Posting eine Kleinigkeit in Sachen "Protokoll" (noch) weiter !? :D http://forum.arduino.cc/index.php?topic=176097.msg1306845#msg1306845

Wenn ich Zeit finde, dann werde ich die Komunikation mit dem Arduino sicher noch aufbohren. Aktuell bin ich erstmal zufrieden, wenn die aktuelle Lösung zuverlässig funktioniert (d.h. das Reset Problem beseitigt ist). Wichtiger ist da eher noch eine geeignette Zugriffskontrolle hier in der WG.

  #include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch(); 
void setup(){ 
mySwitch.enableTransmit(12);
Serial.begin(9600);

}
void loop (){ 
  if (Serial.available()) {
    //Als Asci einlesen
    int ser = Serial.read();
    //Rückgabe
    Serial.println(ser);
   //capitol A for on
     if(ser == 65) {mySwitch.switchOn("11001", "01000");}
     if(ser == 97) {mySwitch.switchOff("11001", "01000");}  
     }
  }

// Ansteuerung per CMD set /p x="A" <nul >\\.\COM9 um keine weiteren Steuerzeichen zu versenden

Revox: - Mittels Python habe ich es geschafft in meinem IIS Servers die *.bat Dateien mit den Com Komandos zu starten (vielleicht ginge es auch direkt mit Python, ich wollte aber die Bat Dateien eventuell auch für die Windows aufgabenplanung verwenden). Dieser Teil hat am längsten gedauert, da die Rechtevergabe in IIS und Win 2012 Server nicht so einfach ist

Ist so aber eigentlich doch ein Schmarrn (von hinten durch die Brust ins Auge). Lass die Batchdateien weg, installier Dir die pySerial Komponente und mach es komplett in Python. Python und Arduino sind ein super Gespann. Und Python Programme kannst Du genauso gut über den Aufgabenplaner starten.

Ich gebe dir da absolut recht! Es ist nun aber so, dass ich zunächst die für mich schnellste Möglichkeit gewählt habe. Das die Realisierung 1. Nicht optimal ist und 2. schlecht ausbaufähig ist mir bewusst. Egal wie, möchte ich es jedoch so einfach wie Möglich halten, da z.b. bei einem komplexeren Komunikationsprotokoll auch der Dokumentationsaufwand steigt (ich möchte ja auch noch in 2 Jahren durchsteigen). Momentan gehts aber erstmal darum das System überhaupt zum Laufen zu bekommen und da ist der Reset stark im Weg. Auch wenn der Server momentan 24/7 läuft möchte ich nicht selbst bei jedem Start Hand anlegen. Danach werde ich mich dann zunächst um die Sicherheit kümmern (mit dem richtigen Link dürft ihr momentan sogar mein Licht anschalten :* )

Kann jemand die Methode mit dem 10uf Kondensator nochmal bestätigen? Eventuell muss ich dann den Arduino wechseln.

Revox: Kann jemand die Methode mit dem 10uf Kondensator nochmal bestätigen? Eventuell muss ich dann den Arduino wechseln.

Ich habe noch mal genau auf den Kondensator geschaut, den ich für den Zweck herumliegen habe, der trägt die Aufschrift: 100?F10V

Also 100?F zur Verhinderung des Auto-Resets funktioniert bei mir sicher an meinen Arduino-Boards. 47?F hatte ich auch mal ausprobiert, funktioniert ebenfalls.

Ob's auch 10?F schon tun, müßtest Du mal ausprobieren. Und wenn Du keine große Lust zum Ausprobieren hast, nimmst Du eben 47?F oder noch mehr auf der sicheren Seite 100?F

Revox: ... Egal wie, möchte ich es jedoch so einfach wie Möglich halten, da z.b. bei einem komplexeren Komunikationsprotokoll auch der Dokumentationsaufwand steigt (ich möchte ja auch noch in 2 Jahren durchsteigen). ...

Da wirst du wohl nicht drumherum kommen, wenn du da später mal was drann ändern oder erweitern willst ! Insbesondere, wenn man sich seine Quelltexte nicht oder nur teilweise selbst ausgedacht hat (der s. g. "KnoHow-Transfer" von anderen Proggern :grin:) und man dazu noch mit Batches oder anderen Dingen gearbeitet hat, was ein bestimmtes "Setup" erfordert.

Mir passiert das auch immer wieder, wenn ich jahrelang im Keller gelegene Projekte hervorkrame, weil es was zu ändern gibt oder der Gedanke im Raum steht: " .... das hast du doch schon mal da oder dort gemacht / gelöst". Dann sitzt man da Stunden und sogar Tage, dreht den Monitor hin und her und versteht sein eigenes getippe nicht mehr, weil es eben "damals" ausgesprochen Tricky war und man dazu div. Sachen beachten musste. Im worst case erfindet man sein eigenes Rad neu !

Ich empfehle dir daher dringend: - Kommentiere nach Möglichkeit jede Programmzeile, was dort passiert - und wenn das noch so banal erscheint (heute !) Irgendwo steht dann mal ne Zahl wie 12,57 im Text und du rätselst ne Ewigkeit, was dass denn wohl war. Mitten in der Nacht fällts dir dann wieder ein: 4 x pi gerundet ! - Schreib dir dazu ein extra Text-Dokument, in dem nun grob oder detailiert den Programmablauf beschreibst. Ganz luxoriös dann auch mit Flussdiagramm... - Hat es was mit Mechanik oder so zu tun oder hast du dir sonst was dazu skizziert, Datenblätter gesammlt ? Scan das ein und packs dabei.

Jaja, ich weiß - man nimmt sich das immer höchstlöblich vor, aber dann werden da mal eben schnell wieder in Zeitdruck ein paarhundert Zeilen zusammengeknallt. Logo ohne Kommentare, Hauptsache läuft. Jetzt ... noch ... 8)

Revox: Ich gebe dir da absolut recht! Es ist nun aber so, dass ich zunächst die für mich schnellste Möglichkeit gewählt habe. Das die Realisierung 1. Nicht optimal ist und 2. schlecht ausbaufähig ist mir bewusst. Egal wie, möchte ich es jedoch so einfach wie Möglich halten, da z.b. bei einem komplexeren Komunikationsprotokoll auch der Dokumentationsaufwand steigt (ich möchte ja auch noch in 2 Jahren durchsteigen). Momentan gehts aber erstmal darum das System überhaupt zum Laufen zu bekommen und da ist der Reset stark im Weg. Auch wenn der Server momentan 24/7 läuft möchte ich nicht selbst bei jedem Start Hand anlegen. Danach werde ich mich dann zunächst um die Sicherheit kümmern (mit dem richtigen Link dürft ihr momentan sogar mein Licht anschalten :* )

Kann jemand die Methode mit dem 10uf Kondensator nochmal bestätigen? Eventuell muss ich dann den Arduino wechseln.

Aber genau das ist doch der Punkt. Die Mischung mit Python und Batchdateien macht das Ganze langfristig wesentlich unübersichtlicher als wenn Du innerhalb eines System bleibst.

Was das Ansprechen der seriellen Schnittstelle in Python betrifft:

import serial

def main():
    ser = serial.Serial()
    ser.port = "COMn"
    ser.baudrate = 19200
    ser.bytesize = serial.EIGHTBITS
    ser.parity = serial.PARITY_NONE
    ser.stopbits = serial.STOPBITS_ONE
    ser.writeTimeout = 2

    try:
        ser.open()

    except Exception, e:
        print "error open serial port: " + str(e)
        exit()

    if ser.isOpen():
        try:
            ser.write(chr(0x41) + chr(0x10))    # sends 'A' + linefeed

        except Exception, e1:
            print "error communicating...: " + str(e1)

        finally:
            ser.close()

if __name__ == "__main__":
    main()

wobei das natürlich schon eine recht ausführliche Version ist. Wenn man auf die ganze Fehlerbehandlich verzichtet, gehts auch wesentlich kürzer.

Was das Abschalten des Reset angeht: Alternativ geht auch ein 120 Ohm Widerstand zwischen Reset und 5V.

Vielen Dank Mafu, mit der Vorlage kann ich mich nicht um eine Implementierung innerhalb der Reptilie herumschlabüstern!
Bis knapp ende des Monats werde ich keine Zeit dafür finden, anschließend setzte ich mich nochmals an das Projekt heran, bevor ich weitere Steckdosen “anlerne”.
Da ich die Angelegenheit dann auch richtig dokumentieren muss, werde ich eine Doku (dann auch mit Bildern) hier online stellen.

Wäre es nicht möglich den RESET des Arduinos durch sich selbst auf HIGH nach einer bestimmte Zeit zu ziehen?
Das würde ein Neuprogrammieren in der Anfangszeit erlauben. Durch einen geeignetten Befehl (über die Serielle Konsole geschickt) ließe sich der Arduino dann wieder ohne Pullupwiderstand verwenden.

Dann ließe sich der Reset per Konsole aktivieren, über die Arduino Software würde dieser dann neu gestartet werden und es ließen sich Updates “hochladen”, da in der Anfangszeit (lassen wir es 3min sein) der Arduino sich resetten lässt.

Du kannst natürlich auch den 120 Ohm Widerstand zwischen Reset und einem beliebigen Pin setzen und diesen Pin nach Bedarf auf HIGH (Reset unterbunden) oder LOW (Reset möglich) setzen.

Ich habe nun die Serial Bibliothek in Python hineingeladen.
Meine Quelle war die folgende Seite:

Leider scheitert das Programmbeispiel schon an der ersten Zeile, Import Serial spuckt bereits eine Fehlermeldung aus.

Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:06:53) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> import serial
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import serial
  File "C:\Python33\lib\site-packages\serial\__init__.py", line 19, in <module>
    from serialwin32 import *
ImportError: No module named 'serialwin32'
>>>

Dabei ist der Dateipfad richtig und dort befindet sich auch die Datei Serialwin32 (Win 2012 müsste ja eigentlich 32bit kompatiebel sein?)

Der entsprechende Programmcode der aufgerufenen init sieht so aus:

import sys

if sys.platform == 'cli':
    from serialcli import *
else:
    import os
    # chose an implementation, depending on os
    if os.name == 'nt': #sys.platform == 'win32':
        from serialwin32 import *
    elif os.name == 'posix':
        from serialposix import *
    elif os.name == 'java':
        from serialjava import *
    else:
        raise Exception("Sorry: no implementation for your platform ('%s') available" % os.name)

Ich verwende Python 2.7 (es gibt mir einfach noch zu viele interessante Module, die zur 3er Version noch nicht kompatibel sind), aber PySerial funktioniert unter Python 3.x, daran sollte es also nicht liegen. Bei meiner Version 2.7pre1 der PySerial sieht der Inhalt der init.py aber minimal anders aus.

import sys

if sys.platform == 'cli':
    from serial.serialcli import *
else:
    import os
    # chose an implementation, depending on os
    if os.name == 'nt': #sys.platform == 'win32':
        from serial.serialwin32 import *
    elif os.name == 'posix':
        from serial.serialposix import *
    elif os.name == 'java':
        from serial.serialjava import *
    else:
        raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,))
...

Sorry dass, ich hiermit meinen Beitrag nochmal Pushe. Ich habe den Thementitel angepasst, weil er momentan eher zu meinem Problem passt.

Stefan