Arduino und VB

"VB" steht für "Visual Basic" von Microsoft®, das es für Privatanwender als Entwicklungsumgebung kostenlos gibt und das ich noch in der alten (archaischen) Version VB 2010 nutze. Da ich selber damit programmiere (bzw. mit VB.net) und dieses Programm (siehe Stellpult, Ampelsteuerung, Pendelzugsteuerung etc.) mehrere Arduinos ansteuern soll, stand ich vor dem Problem, dass mein VB-Programm herausfinden muss, welches Arduino-Board an welchem COM-Anschluss (USB) angeschlossen ist - denn auf den Arduinos laufen ja verschiedene Steuerungsprogramme (Sketches). Die übergebenen Befehle an das jeweilige Arduino sind jedoch gleich - und Windows ordnet dem erstangeschlossenen Arduino-Board den ersten freien COM-Port zu, der sich dann auch noch ändert, falls man den USB-HUB austauschen muss. Möglich sind COM-Anschlüsse von 1 bis 127...

Eigentlich müsste VB ja irgendwie in der Lage sein, die Boards zu unterscheiden.

Leider findet man im Netzt zwar gefühlte 1.000.000 Treffer auf diese Frage, aber keine Lösung. Das googlen mit dem Begriff "friendly name" (das ist der Name, der bei einem COM-Anschluss als angeschlossenes Gerät angezeigt wird, also z.B. "ARDUINO UNO" an COM3) bringt mich nicht weiter, denn alle ARDUINO UNOs haben den selben Namen - halt 'ARDUINO UNO'. Genial wäre es, wenn man diesen friendly name bei einem Board ändern könnte - z.B. in "Board Lichtschaltung" oder in "Board Weichensteuerung" usw.

DAS allerdings geht wohl so einfach nicht.

Ich bin beim Suchen letztendlich über eine wmi-Funktion gestolpert:

    Imports System.Management

System.Management wird in den Projekteinstellungen (Projekt -> 'IhrProjektname'-Einstellungen , Registerkarte "Verweise" , Button "Hinzufügen: Verweis..." , Registerkarte ".NET" , "System.Management" wählen , Button "OK") dem VB-Projekt hinzugefügt und mit dem Imports-Befehl über der public class des forms importiert.

System.Management stellt eine Menge Infos über das Systemmanagement des Rechners zur Verfügung, unter anderem auch über die seriellen Ports (was ein USB-Port, an den ein ARDUINO angeschlossen wird, ja ist). Mit folgendem VB-Code kann man nun einige interessante Dinge über den jeweiligen COM-Port bzw. alle COM-Ports herausfinden:

Private Sub btnTEST_Click(sender As System.Object, e As System.EventArgs)Handles btnTEST.Click

    Dim searcher As New ManagementObjectSearcher("root\CIMV2", "SELECT * FROM Win32_SerialPort")
    ListBox1.Items.Clear()
    ListBox1.Items.Add("Win32_SerialPort: Name")
    ListBox2.Items.Clear()
    ListBox2.Items.Add("Win32_SerialPort: PNPDeviceID")

    For Each queryObj As ManagementObject In searcher.Get()

    ListBox1.Items.Add(queryObj("Name"))
    ListBox2.Items.Add(queryObj("PNPDeviceID").ToString)

    Next

End Sub

Kurze Erklärung: Auf einer Form wird ein Button erstellt mit dem Namen btnTEST sowie zwei ListBoxen mit den Namen ListBox1 und ListBox2. Beim Klicken auf den Button werden die Listboxen mit den gefundenen Werten gefüllt. Das schöne an dieser Abfrage ist, dass man auch den COM-Anschluss (also die Nummer) auslesen kann für eine bestimmte PNPDevice-ID! Denn die PNPDeviceID ist bei jedem ARDUINO absolut eindeutig. Welche Felder der Abfrage was ergeben kann man im Internet leicht nach "Win32_SerialPort" googlen. Folgende Felder finde ich aber mal ganz interessant wegen der Information die man erhält:

"Description" ergibt z.B. "ARDUINO UNO R3",
"DeviceID" ergibt z.B. "COM3",
"Name" ergibt eine Zusammenführung von "Description" und "DeviceID", also z.B. "ARDUINO UNO R3 (COM3)",
die "PNPDeviceID" ist eindeutig - also z.B. 74134373733351110281 und bei (original) ARDUINO UNOs ist die Nummer von rechts 20-stellig.

Das Arduino Mega 2560 funktioniert auch, aber mit dem Arduino Leonardo hat man so seine Problemchen: Enthält die “Description” den string “Leonardo” muss (!) der Port zusätzlich wie folgt konfiguriert werden:

    SerialPort1.DtrEnable = True
    SerialPort1.RtsEnable = True

Ansonsten feuert das DataReceived-Event nicht! Wenn man das weiß, kann man es leicht einbauen - und das senkt die Kosten für die Arduino-Boards ganz erheblich, da das Leonardo preiswerter als das UNO R3 ist! Das Gleiche gilt für’s ARDUINO MICRO.

Je nachdem, was man nun benötigt, kann man seinen SQL-String anpassen, z.B. "SELECT DeviceID FROM Win32_SerialPort WHERE PNPDeviceID = XXXXXXX" <- das XXXXXXX natürlich durch die echte ID ersetzen, klar.

Damit ist eine eindeutige Zuordnung eines bestimmten ARDUINO-Boards zu dem gerade aktuellen COM-Anschluss möglich und das minutenlange Rumfrickeln und Einstellen kann entfallen. Die eindeutigen ID's z.B. in einer Datenbank ablegen und beim Programmstart automatisch den richtigen COM-Port zuordnen lassen... :)

Imports System.Management vor der public class des Forms nicht vergessen!!!

"Echte" Programmierer mögen mir verzeihen, falls ich etwas unrichtig dargestellt habe oder vielleicht "zu lang" oder "zu doof" programmiere - ich programmiere hobbymäßig (das bedeutet bei mir konkret "als Hobby, und meistens mäßig") - aber die dargestellte Variante funktioniert tatsächlich und hat mein blödes "friendly-name-Problem" gelöst. Wen die Klasse "Win32_SerialPort" genauer interessiert:

Win32_SerialPort.pdf