Schachspiel mittels kollaborierendem UR-Roboter unter ROS: Unterschied zwischen den Versionen

Aus HSHL Mechatronik
Zur Navigation springen Zur Suche springen
Zeile 63: Zeile 63:
|Hauptakteur des Projektes ist der UR3 Roboterarm der Firma Universal Robots (UR). Der UR3 ist der kleinste der von UR angebotenen kollaborierenden Roboter. Dabei hat der UR3 ein Gewicht von 11 kg mit einer maximalen Traglast von 3 kg. Die Reichweite des Roboters beträgt bei voll ausgestrecktem Arm 500 mm. Alle Gelenke des UR3 lassen sich um +/- 360° drehen.  Der Roboter benötigt eine Betriebspanung von 24 V  im Schaltschrank und 12 V an der Werkzeugschnittstelle. Die Kommunikation des Roboters zu PC findet über einen Ethernet-Anschluss statt. Weitere Informationen sind dem Datenblatt<ref name = 'Datenblatt UR3'> UR3Roboter: ''UniversalRobots- UR3Roboter''. 2022. Online im Internet: https://www.i-botics.de/wp-content/uploads/2016/08/ur3_de.pdf; Abruf: 08.01.2022</ref> zu entnehmen.
|Hauptakteur des Projektes ist der UR3 Roboterarm der Firma Universal Robots (UR). Der UR3 ist der kleinste der von UR angebotenen kollaborierenden Roboter. Dabei hat der UR3 ein Gewicht von 11 kg mit einer maximalen Traglast von 3 kg. Die Reichweite des Roboters beträgt bei voll ausgestrecktem Arm 500 mm. Alle Gelenke des UR3 lassen sich um +/- 360° drehen.  Der Roboter benötigt eine Betriebspanung von 24 V  im Schaltschrank und 12 V an der Werkzeugschnittstelle. Die Kommunikation des Roboters zu PC findet über einen Ethernet-Anschluss statt. Weitere Informationen sind dem Datenblatt<ref name = 'Datenblatt UR3'> UR3Roboter: ''UniversalRobots- UR3Roboter''. 2022. Online im Internet: https://www.i-botics.de/wp-content/uploads/2016/08/ur3_de.pdf; Abruf: 08.01.2022</ref> zu entnehmen.
|[[Datei:UR3Roboter.jpg|126px|mini|zentriert|UR3Roboter]]
|[[Datei:UR3Roboter.jpg|126px|mini|zentriert|UR3Roboter]]
|X €
|-
|-
|DGT Smart Board
|DGT Smart Board
|Das freundlicherweise vom Hersteller Digital Game Technology (DGT) bereitgestellte "DGT Smart Board" wird üblicherweise zur Übertragung von Turnierspielen ins Internet verwendet. Das bedeutet, dass dieses Smart Board die Möglichkeit zum Auslesen der einzelnen Figuren auf den bestimmten Feldern bietet. Die Datenübertragung wird durch ein USB-Kabel sichergestellt. Gleichzeitig kann eine von DGT hergestellte Schachuhr an das Schachbrett angeschlossen werden. Weitere Informationen sind unter der Quelle <ref name = 'DGT Smart Board' > DGT: ''DGT - DGT Smart Board''. 2022. Online im Internet: https://digitalgametechnology.com/products/home-use-e-boards/smart-board-with-indices; Abruf: 08.01.2022</ref> zu finden.
|Das freundlicherweise vom Hersteller Digital Game Technology (DGT) bereitgestellte "DGT Smart Board" wird üblicherweise zur Übertragung von Turnierspielen ins Internet verwendet. Das bedeutet, dass dieses Smart Board die Möglichkeit zum Auslesen der einzelnen Figuren auf den bestimmten Feldern bietet. Die Datenübertragung wird durch ein USB-Kabel sichergestellt. Gleichzeitig kann eine von DGT hergestellte Schachuhr an das Schachbrett angeschlossen werden. Weitere Informationen sind unter der Quelle <ref name = 'DGT Smart Board' > DGT: ''DGT - DGT Smart Board''. 2022. Online im Internet: https://digitalgametechnology.com/products/home-use-e-boards/smart-board-with-indices; Abruf: 08.01.2022</ref> zu finden.
|[[Datei:DGT Smartboard.png|126px|mini|zentriert|DGT Smartboard]]
|[[Datei:DGT Smartboard.png|126px|mini|zentriert|DGT Smartboard]]
|X €
|-
|-
| DGT 3000 Schachuhr
| DGT 3000 Schachuhr
| Die Schachuhr DGT 3000 kann über ein AUX Kabel mit dem DGT Smart Board verbunden werden. Diese Verbindung ermöglicht eine Zeit- und Spielererkennung beim auslesen des Boards. Weitere Informationen zur Schachuhr sind unter der Quelle <ref name = 'DGT 3000' > DGT: ''DGT - DGT3000''. 2022. Online im Internet: https://digitalgametechnology.com/products/chess-clocks/dgt3000-fide-approved; Abruf: 08.01.2022</ref>
| Die Schachuhr DGT 3000 kann über ein AUX Kabel mit dem DGT Smart Board verbunden werden. Diese Verbindung ermöglicht eine Zeit- und Spielererkennung beim auslesen des Boards. Weitere Informationen zur Schachuhr sind unter der Quelle <ref name = 'DGT 3000' > DGT: ''DGT - DGT3000''. 2022. Online im Internet: https://digitalgametechnology.com/products/chess-clocks/dgt3000-fide-approved; Abruf: 08.01.2022</ref>
|[[Datei:DGT 3000 Schachuhr.png|126px|mini|zentriert|DGT3000 Schachuhr]]
|[[Datei:DGT 3000 Schachuhr.png|126px|mini|zentriert|DGT3000 Schachuhr]]
|X €
|}
|}



Version vom 22. Januar 2022, 10:09 Uhr


Autoren: Manfred Listner, Benjamin Reuter

Betreuer: Prof. Dr. Mirek Göbel & Marc Ebmeyer

Wintersemester: 2021/2022

Fachsemester: 7

zurück zum Hauptartikel: Praktikum Produktionstechnik


Einleitung

Als Teil des Bachelorstudiengangs Mechatronik an der HSHL, wird im siebten Semester das Fach Produktiontechnik VII unterrichtet. Semesterbegleitend wird dieses Fach als Praktikum durchgeführt. In diesem Praktikum sollen die Studierenden ein mechatronisches Projekt in kleinen Gruppen selbstständig bearbeiten. Das hier beschriebene Projekt handelt vom Schachspiel eines Roboterarms (UR3) unter ROS.

Aufgabenstellung

Aufgabe ist es, dem von der HSHL bereitgestellten Roboterarm UR3 das Schachspielen beizubringen. Dazu soll die Software "Robot Operation System" (ROS) verwendet werden. Das System soll letzten Endes dazu in der Lage sein gegen einen menschlichen Gegenspieler anzutreten. Dazu benötigt das System eine Möglichkeit zur Erkennung des Spielfelds und eine Positionserkennung der einzelnen Spielfiguren. Zusätzlich muss das System dazu in der Lage sein, das Spielfeld auswerten und korrekte Spielzüge ausführen zu können.

Vorgehensweise nach V-Modell

Abbildung 1: V-Modell2020.png

Zur strukturierten Bearbeitung des Projektes wird nach dem V-Modell vorgegangen (vgl. Abbildung 1). Durch dieses vorgehen kann sichergestellt werden, dass alle notwendigen Schritte die zur erfolgreichen Bearbeitung eines Projektes benötigt werden auch durchgeführt werden.
Die Verwaltung der verschiedenen erstellten Dokumente wird über das Programm TortoiseSVN[1] gewährleistet. Nachfolgend werden die Dokumente unter den jeweiligen Punkten des V-Modells als Link zum Download bereitgestellt.



Anforderungsdefinition

Die an das Projekt gestellten Anforderungen werden im ersten Schritt, der Anforderungsdefinition[2], des V-Modelles in der Anforderungsliste definiert. Dabei wird die Anforderungsliste in verschiedene Kategorien unterteilt:

  • Anforderungen an das System
  • Sicherheit
  • Schnittstellen
  • Software / Werkzeuge
  • Dokumentation

Funktionaler Systementwurf

Abbildung 2: Nodestruktur.JPG

Der funktionaler Systementwurf[3], zeigt in einer schematischen Darstellung die Struktur und Verknüpfung der einzelnen in ROS zu programmierenden Nodes (vgl. Abbildung 2). Der Aufbau der vier geplanten Nodes lässt sich wie folgt beschreiben:

  • Node 1: Sendet die Befehle 0x08 & 0x42 an das Smart Board um die Spielfeld- und Spielerinformationen anzufordern
  • Node 1: Sendet die erhaltenen Spielfeldinformationen über ein Topic an Node 2.
  • Node 2: Wertet über die Einbindung der Stockfish-Schachengine die Spielfeldinformationen aus und ermittelt den Zug den der Roboter ausführen muss.
  • Node 2: Sendet den ermittelten Spielzug (Figur, von Feld XY, nach Feld YZ) an Node 3.
  • Node 3: Ermittelt die Koordinaten die dem Roboter zur Bewegungsausführung bereitgestellt werden müssen.
  • Node 3: Sendet die Befehle über ein weiteres Topic an Node 4.
  • Node 4: Verantwortlich für die auszuführenden UR_Befehle

Zusätzlich findet sich unter dem o.g. Link ein Programmablaufplan (PAP) der Auskunft über den generellen Ablauf und Rahmenbedingungen die bei der Zugdurchführung zu beachten sind.

Technischer Systementwurf

Im technischen Systementwurf[4] werden die verwendeten Komponenten und deren Schnittstellen übersichtlich dargestellt. Gleichzeitig wird hier gezeigt, wie die Komponenten untereinander verbunden sind.

Komponentenspezifikation

In der Komponentenspezifikation[5] wird definiert, welche Komponenten konkret für die Erfüllung der Aufgaben verwendet werden sollen. Dabei wurden die Komponenten in Hardware und Software unterteilt.

Hardware

Komponenten Beschreibung Bild Preis
UR3 Hauptakteur des Projektes ist der UR3 Roboterarm der Firma Universal Robots (UR). Der UR3 ist der kleinste der von UR angebotenen kollaborierenden Roboter. Dabei hat der UR3 ein Gewicht von 11 kg mit einer maximalen Traglast von 3 kg. Die Reichweite des Roboters beträgt bei voll ausgestrecktem Arm 500 mm. Alle Gelenke des UR3 lassen sich um +/- 360° drehen. Der Roboter benötigt eine Betriebspanung von 24 V im Schaltschrank und 12 V an der Werkzeugschnittstelle. Die Kommunikation des Roboters zu PC findet über einen Ethernet-Anschluss statt. Weitere Informationen sind dem Datenblatt[6] zu entnehmen.
UR3Roboter
X €
DGT Smart Board Das freundlicherweise vom Hersteller Digital Game Technology (DGT) bereitgestellte "DGT Smart Board" wird üblicherweise zur Übertragung von Turnierspielen ins Internet verwendet. Das bedeutet, dass dieses Smart Board die Möglichkeit zum Auslesen der einzelnen Figuren auf den bestimmten Feldern bietet. Die Datenübertragung wird durch ein USB-Kabel sichergestellt. Gleichzeitig kann eine von DGT hergestellte Schachuhr an das Schachbrett angeschlossen werden. Weitere Informationen sind unter der Quelle [7] zu finden.
DGT Smartboard
X €
DGT 3000 Schachuhr Die Schachuhr DGT 3000 kann über ein AUX Kabel mit dem DGT Smart Board verbunden werden. Diese Verbindung ermöglicht eine Zeit- und Spielererkennung beim auslesen des Boards. Weitere Informationen zur Schachuhr sind unter der Quelle [8]
DGT3000 Schachuhr
X €

Software

Als Programmierumgebung wird das Robot Operating System (ROS) verwendet. ROS ist eine Softwareanwendung, die bei der Programmierung und Inbetriebnahme von mehrachsigen Greifrobotersystemen zur Anwendung kommt. Dabei besteht ROS aus mehreren Softwarebibliotheken. ROS bietet verschiedenste Werkzeuge. Von Treibern für diverse Roboter bis hin zur graphischen Simulation von Bewegungsabläufen durch RViz. Durch die höhere Verfügbarkeit von Bibliotheken unter dem Linux Betriebssystem (Ubuntu 16.04 bis 20.04) ist eine Nutzung von ROS unter Linux zu empfehlen.

  • ROS
    • Versionen: Durch die stetige Weiterentwicklung von ROS, finden sich diverse Versionen im Internet. Die aktuellen und noch durch einen Support unterstütze Versionen sind unter: www.docs.ros.org[9] zu finden. Bei der Auswahl der ROS-Version ist unbedingt auf die Kompatibilität von ROS-Version und benötigter Ubuntu Version zu achten. Je nach Version werden verschiedene Bibliotheken angeboten. Daher sollte nach Möglichkeit im Vorhinein recherchiert werden, welche ROS-Version für die geplante Anwendung benötigt wird.
    • Installation: Nach Auswahl der gewünschten ROS-Version wird die Anwendung unter Ubuntu durch Terminalbefehle installiert. Zum Öffnen des Terminals ALT + STRG + T drücken. Hier die nötigen Befehle zur Installation nach und nach in das Terminalfenster kopieren und ausführen. Ebenfalls sollten alle Kommentare zwischen den Befehlen gelesen und befolgt werden. Je nachdem welche Version installiert werden soll ergeben sich ebenfalls andere Installationswege.
    • Funktionsweise: Unter www.docs.ros.org/en/foxy/Tutorials.html[10] finden sich diverse Tutorials zur Funktionsweise von ROS2 Foxy. Die allgemeine Funktionsstruktur bleibt sowohl bei älteren als auch neueren ROS-Versionen grundsätzlich dieselbe. Nachfolgend werden die wichtigsten Grundlagen von ROS kurz erklärt
      • Nodes: [11] Die sogenannten Nodes sind in ROS für die Abgrenzung von verschiedenen Modulen verantwortlich. Dabei haben in ROS die verschiedenen Module eine eigene Aufgabe (z.B. eine Node liest die Umdrehungsfrequenz eines Motors und eine Node ermittelt die Geschwindigkeit). Um einen Datenaustausch zu ermöglichen ist jede Node dazu in der Lage Informationen zu versenden und zu empfangen. Dazu werden allerdings weitere Funktionen innerhalb der Node benötigt: Die sogenannten Topics, Services und Actions.
      • Topics: [12] Durch den modularen Aufbau von komplexen Systemen unter ROS muss eine Kommunikation unter den Nodes hergestellt werden. Dazu werden die ROS-Topics verwendet. Dabei sendet eine Node, durch den sogenannten Publisher an den Subscriber einer anderen Node, eine Nachricht. Das Topic erfüllt hier den Zweck des Weiterleitens der Informationen an die dafür vorgesehene Node. Ein Topic kann dabei nicht auswerten, ob alle an das Topic angeschlossene Nodes die Information erhalten müssen, oder nur einzelne Nodes. Das bedeutet das jede Information mit allen Subscribern, die an das Topic angeschlossen ist, geteilt wird.
      • Services: [13] Die sogenannten sevices sind eine weitere Art der Kommunikation von Nodes in ROS. Anders als beim Datenaustausch durch ein Topic, wird hier eine Information erst gesendet, wenn der Service Server eine Anfrage erhalten hat. Dazu wird eine Anfrage innerhalb des Service Clients einer Node an den Service gesendet. Dieser Service unterscheidet dann zunächst, ob es sich bei der Information um eine Anfrage oder eine Antwort handelt. Sofern der Service die Information als Anfrage einstuft, wird diese an den Service Server weitergeleitet. Dabei ist wichtig zu erwähnen, dass es beim Datenaustausch über den ROS-Service immer nur einen Service Server, aber mehrere Service Clients geben kann. Erhält der Service eine Anfrage sendet dieser eine Antwort zurück an den Service. Dieser leitet die Antwort dann an den Service Client zurück.
      • Actions: [14] Eine weitere Art der Kommunikation zwischen zwei Nodes ist die ROS-Action. Actions bestehen aus drei Teilen, dem Ziel, einem Feedback und einem Ergebnis. Gleichzeitig vereinen die Actions die Eigenschaften der Services und Topics miteinander. Hier sendet ein Action Client ein Ziel an den Action Server. Über den Feedback Publisher wird nach Annahme des Ziels ein durchgehender Strom aus Informationen an den Feedback Subscriber übermittelt. Dadurch kann der Action Client auswerten, wie viel Abweichung noch zum Zielzustand besteht. Sobald der Zielzustand erreicht ist, wird durch den Action Server eine Antwort an den Client gesendet um beispielsweise eine Bewegung eines Roboters zu beenden.
  • RViz
    • Getting started with MoveIt and RViz: RViz ist ein Simulationstool das zur Bewegungsplanung und -steuerung verwendet werden kann. Dabei werden die Bewegungsdaten über die Bibliothek "MoveIt" an den Roboter übermittelt. Ein Tutorial für RViz und MoveIt findet sich unter: https://ros-planning.github.io/moveit_tutorials/ [15]
    • Laden des UR3-Modells in RViz Schritt für Schritt: die Nachfolgenden Befehle müssen jeweils in einem einzelnen Terminal in der aufgeführten Reihenfolge eingegeben werden um RViz mitsamt dem UR3-Modell zu starten.
//Sourced den korrekten Workspace und lädt die UR-Description (URDF & SRDF)//
cd catkin_ws
source devel/setup.bash
roslaunch ur_description ur3_upload.launch

//Sourced den korrekten Workspace und lädt die "planning scene" (Umgebungsinformation)//
cd catkin_ws
source devel/setup.bash
roslaunch ur3_moveit_config ur3_moveit_planning_execution.launch

//Sourced den korrekten Workspace und öffnet RViz zur Steuerung//
cd catkin_ws
source devel/setup.bash
roslaunch ur3_moveit_config moveit_rviz.launch config:=true


Programmierung/Entwicklung

In Schritt Entwicklung[16] wird die notwendige Software programmiert. Hierbei sind drei unterschiedliche C++-Skripte entwickelt worden. Eines, welches einfach das Board einmal ausliest und in das Terminal ausgibt. Das nächste, welches die Schachuhr kontinuierlich ausliest und in das Terminal ausgibt. Und das dritte, welches die Schachuhr kontinuierlich ausliest und das Board einmal ausgibt, sobald die Uhr das Signal sendet, dass Spieler Schwarz am zug ist.
Zunächst einmal muss aber die Kommunikation zwischen dem Board und dem Computer hergestellt werden. Dies ist unter Ubuntu nicht einfach als Anfänger. Es müssen bestimmte Flaggen gesetzt oder disabled werden. Eine genauere beschreibung befindet sich hier[17]. Diese Schreitweise befolgung der Anleitung hat uns zu dem folgendem Unterprogramm geführt, welches als Setup vorher ausgeführt werden muss.

Setup Funktion
Beschreibung: Dient der Vorbereitung des Informationsaustausch via USB.


void setup()
{

	serial_port = open("/dev/ttyACM0", O_RDWR);	//"/dev/ttyACM0" ist der angeschlossene Port muss ggf. angepasst werden!

	// Check for errors
	if (serial_port < 0) 
	{
		printf("Error %i from open: %s\n", errno, strerror(errno));
	}
	
	// Create new termios struct, we call it 'tty' for convention
	// No need for "= {0}" at the end as we'll immediately write the existing
	// config to this struct
	struct termios tty;

	// Read in existing settings, and handle any error
	// NOTE: This is important! POSIX states that the struct passed to tcsetattr()
	// must have been initialized with a call to tcgetattr() overwise behaviour
	// is undefined
	if (tcgetattr(serial_port, &tty) != 0) 
	{
		printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
	}

	tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
	tty.c_cflag |= PARENB;  // Set parity bit, enabling parity

	tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
	tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication

	tty.c_cflag &= ~CSIZE; // Clear all the size bits, then use one of the statements below
	tty.c_cflag |= CS8; // 8 bits per byte (most common)

	tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)

	tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

	tty.c_lflag &= ~ICANON;

	tty.c_lflag &= ~ECHO; // Disable echo
	tty.c_lflag &= ~ECHOE; // Disable erasure
	tty.c_lflag &= ~ECHONL; // Disable new-line echo

	tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

	tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl

	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes

	tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
	tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
						   // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
						   // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)

	tty.c_cc[VTIME] = 1;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
	tty.c_cc[VMIN] = 0;

	// Set in/out baud rate to be 9600
	cfsetispeed(&tty, B9600);
	cfsetospeed(&tty, B9600);

	// Save tty settings, also checking for error
	if (tcsetattr(serial_port, TCSANOW, &tty) != 0) 
	{
		printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
	}
}


Zusätzlich muss in einem Terminal der Befehl "$ sudo adduser $USER dialout" ausgeführt werden. Hierdurch wird der Fehler errno13 unterbunden, welcher die unzureichende Berechtigung mitteilt (Ausgabe im Terminal: permission denied). Nach dem Ausführen des Befehls muss der PC einmal neugestartet werden, damit die Gruppenänderung in Kraft tritt. Nun hat man die Berechtigung, um auf den USB-Port zugreiffen zu können.
Als nächstes folgen die drei verschiedenen Programme.

Board auslesen
Beschreibung: Liest das Board einmal aus und gibt die Daten in das Terminal aus. Programm beendet sich nach der einmaligen Ausgabe. Die Ausgabe ist ein 8x8 Feld mit zweistelligen Hex-Werten, welches das Board darstellt.


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h>

using namespace std;

int serial_port;

void setup();

int main()
{
	setup();	//öffnet den Port

	char read_buf [100];	//erzeugt ein Array in welches die Daten geschrieben werden
	unsigned char msg[1] = {'\x42'}; //die zu übermittelnde Nachricht "DGT_REQ_BOARD" in hex siehe DGT-Manuel
	int i=0;	//Zähler für for-Schleife

	write(serial_port, msg, sizeof(msg));	//Schreibt die Nachricht auf den Port

	int n = read(serial_port, &read_buf, sizeof(read_buf));	//liest erhaltene information aus
// n is the number of bytes read. n may be 0 if no bytes were received, and can also be negative to signal an error.


	for(i = 3; i<n; i++)	//Ausgabe der Information ins Terminal
	{
		int HexOut = read_buf[i];	//char zu int konvertierung

		if(HexOut<16)	//für konstante zweistellige Hexzahlen; vorherige Ausgabe Zahl<16 mit 0
		{
			cout << "0";
		}

		cout << hex << HexOut << " ";	//Ausgabe der int-zahl als Hex

		if((i-2)%8 == 0)	//dient der formatierung; erzeugt 8x8 Feld im Terminal
		{
			cout << endl;
		}
	}
	close(serial_port);
}


void setup()
{

	serial_port = open("/dev/ttyACM0", O_RDWR);	//"/dev/ttyACM0" ist der angeschlossene Port muss ggf. angepasst werden!

	// Check for errors
	if (serial_port < 0) 
	{
		printf("Error %i from open: %s\n", errno, strerror(errno));
	}
	
	// Create new termios struct, we call it 'tty' for convention
	// No need for "= {0}" at the end as we'll immediately write the existing
	// config to this struct
	struct termios tty;

	// Read in existing settings, and handle any error
	// NOTE: This is important! POSIX states that the struct passed to tcsetattr()
	// must have been initialized with a call to tcgetattr() overwise behaviour
	// is undefined
	if (tcgetattr(serial_port, &tty) != 0) 
	{
		printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
	}

	tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
	tty.c_cflag |= PARENB;  // Set parity bit, enabling parity

	tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
	tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication

	tty.c_cflag &= ~CSIZE; // Clear all the size bits, then use one of the statements below
	tty.c_cflag |= CS8; // 8 bits per byte (most common)

	tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)

	tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

	tty.c_lflag &= ~ICANON;

	tty.c_lflag &= ~ECHO; // Disable echo
	tty.c_lflag &= ~ECHOE; // Disable erasure
	tty.c_lflag &= ~ECHONL; // Disable new-line echo

	tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

	tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl

	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes

	tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
	tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
						   // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
						   // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)

	tty.c_cc[VTIME] = 1;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
	tty.c_cc[VMIN] = 0;

	// Set in/out baud rate to be 9600
	cfsetispeed(&tty, B9600);
	cfsetospeed(&tty, B9600);

	// Save tty settings, also checking for error
	if (tcsetattr(serial_port, TCSANOW, &tty) != 0) 
	{
		printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
	}
}


Uhr auslesen
Beschreibung: Liest die Uhr kontinuierlich aus und gibt die Daten in das Terminal aus. Programm beendet sich nicht selbstständig. Hierfür STRG + C ins Terminal eingeben. Es werden hierbei insgesamt 10 Bytes eingelesen, aber nur Bytes 4-10 Ausgegeben. Die ersten drei Bytes sind Header Bytes und können ignoriert werden.
Die ausgegebenen 7 Bytessind folgende:

  • Bytes 4-6: Zeit Spieler Weiß (Stunde|Minute|Sekunde)
  • Bytes 7-9: Zeit Spieler Schwarz (Stunde|Minute|Sekunde)
  • Byte 10: Spieler aktivität (z.B. Welcher Spieler dran ist)

Zusätzlich werden in diesem Modus auch Feldaktualisierungen gemeldet. Hierbei werden bei Bewegung einer Figur Zusätzlich ins Terminal je zwei Bytes geschrieben. Byte eins gibt das Feld an, welches sich verändert hat. Und Byte zwei gibt an welche Figur sich auf dem Feld nun befindet (für die Aufschlüsselung Feld und Figur siehe DGT-Manuel). Da beim Bewegen einer Figur für gewöhnlich zwei Felder aktualisiert werden (Start Feld und Ziel Feld) werden dementsprechend auch zwei mal zwei Bytes ausgegeben. ACHTUNG! bei Figuren die sich mehr als ein Feld weit bewegen können, kann es passieren, dass auch mehr als zwei aktualisierte Felder angezeigt werden (z.B. wenn ein Turm vier Felder über das Board ohne anheben nach vorne geschoben wird).


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h>

using namespace std;

int serial_port;

void setup();

int main()
{
	setup();	//öffnet den Port

	char read_buf[100];	//erzeugt ein Array in welches die Daten geschrieben werden
	unsigned char msg[] = { '\x08' };	//die zu übermittelnde Nachricht "DGT_CMD_CLOCK_BUTTON" in hex siehe DGT-Manuel
										//Da die Uhr nicht immer auf Hexzahlen anspricht ggf.mit ASCII übermitteln
	int i = 0;	//Zähler für for-Schleife						
	int HexOut = 0;	//Variable zum konvertieren char zu int
	int n = 0;	//Variable zum ermitteln, wie viel Bytes empfangen wurden

	write(serial_port, msg, sizeof(msg));	//Schreiben der Nachricht an USB-Port
											//Nach erhalt der Nachricht sendet die Uhr kontinuierlich, 
											//sobald sich etwas in der Anzeige verändert 

	while (true)	
	{
		n = read(serial_port, &read_buf, sizeof(read_buf));	//liest erhaltene Information aus

		if (n>0)	//gibt nur Daten ins Terminal aus, wenn welche empfangen wurden 
		{
			for (i = 3; i<n; i++)
			{
				HexOut = read_buf[i];	//char zu int konvertierung

				if (HexOut<16)	//für konstante zweistellige Hexzahlen; vorherige Ausgabe Zahl<16 mit 0
				{
					cout << "0";
				}
				cout << hex << HexOut << " ";	//Ausgabe der int-zahl als Hex
			}
			cout << endl;	//Zeilenumbruch; WICHTIG!!! ohne Zeilenumbruch gibt das Terminal 
							//die Informationen erst nach einem overflow aus!
		}
		usleep(100);	//Systempause
	}
	close(serial_port);
}



void setup()
{

	serial_port = open("/dev/ttyACM0", O_RDWR);

	// Check for errors
	if (serial_port < 0) 
	{
		printf("Error %i from open: %s\n", errno, strerror(errno));
	}


	// Create new termios struct, we call it 'tty' for convention
	// No need for "= {0}" at the end as we'll immediately write the existing
	// config to this struct
	struct termios tty;

	// Read in existing settings, and handle any error
	// NOTE: This is important! POSIX states that the struct passed to tcsetattr()
	// must have been initialized with a call to tcgetattr() overwise behaviour
	// is undefined
	if (tcgetattr(serial_port, &tty) != 0) 
	{
		printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
	}

	tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
	tty.c_cflag |= PARENB;  // Set parity bit, enabling parity

	tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
	tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication

	tty.c_cflag &= ~CSIZE; // Clear all the size bits, then use one of the statements below
	tty.c_cflag |= CS8; // 8 bits per byte (most common)

	tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)

	tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

	tty.c_lflag &= ~ICANON;

	tty.c_lflag &= ~ECHO; // Disable echo
	tty.c_lflag &= ~ECHOE; // Disable erasure
	tty.c_lflag &= ~ECHONL; // Disable new-line echo

	tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

	tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl

	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes

	tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
	tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
						   // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
						   // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)

	tty.c_cc[VTIME] = 1;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
	tty.c_cc[VMIN] = 0;

	// Set in/out baud rate to be 9600
	cfsetispeed(&tty, B9600);
	cfsetospeed(&tty, B9600);

	// Save tty settings, also checking for error
	if (tcsetattr(serial_port, TCSANOW, &tty) != 0) 
	{
		printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
	}
}




Kombination aus Uhr auslesen und Board auslesen
Beschreibung: Liest kontinuierlich die Schachuhr aus. Sobald das Programm in Byte 10 (wie im vorherigen Programm beschrieben) 0x13 (Spieler Schwarz) empfängt, wird das Board einmal ausgelesen und ins Terminal ausgegeben. Desweiteren läuft ein Zähler mit, welcher die Periode mit ausgibt (hilft auch beim Debuggen). Daraufhin wird eine Flagge gesetzt, welche dafür sorgt, dass das Board nicht erneut ausgeben wird, solange Spieler Schwarz noch am Zug ist. Sobald das Programm in Byte 10 0x09 (Spieler Weiß) empfängt, wird die gesetzte Flagge zurückgesetzt.


#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h>

using namespace std;

int serial_port;

void setup();

/************************************************************************************/
int main()
{
	char read_buf[100];	//Array anlegen in denen die erhaltenen Daten eingelesen werden

	unsigned char msg1[] = { '\x08' };	//Der Befehl "DGT_CMD_CLOCK_BUTTON" in Hex
	unsigned char msg2[] = { '\x42' };	//Der Befehl "DGT_REQ_BOARD" in Hex
	unsigned char msg3[] = { '\x03' };	//Der Befehl "DGT_CMD_CLOCK_END" in Hex

	int ControlFlag = 1;	//Kontroll Flagge als Indikator, dass das Board bereits ausgegeben wurde; am Anfang 1, um anfängliche falsch Übertragungen zu verhindern!

	int i = 0;	//Zähler für "for" Schleifen
	int HexOut = 0;	//Variable dient zum konvertieren "char" zu "int"
	int n = 0;	//Variable dient zum Kontrollieren, dass informationen vom Board erhalten wurden
	int p = 0;	//Zähler der Perioden für Spieler 2

	setup();	//ermöglicht den Zugriff auf die Schnittstelle zum Board; vollständige Funktion unten! 


	while (true)	//dient als Dauerschleife zum empfangen der Daten; Abbruchbedingung bei Spielende muss noch hinzugefügt werden!
	{
		/*********************************************************/
		//Do-Schleife dient zum stetigen abfragen des Spielers
		do {
			write(serial_port, msg1, sizeof(msg1));
			usleep(100);
			n = read(serial_port, &read_buf, sizeof(read_buf));

			HexOut = read_buf[9];

			if (HexOut == '\x09')	//Wenn Spieler1 am Zug ist wird die Kontrollflagge zurückgesetzt
			{
				ControlFlag = 0;	//Reset der Kontrollflagge
			}

		} while (HexOut != '\x13');	//Abbruchbedingung ist der Spielerwechsel (wenn Spieler2 am Zug ist wird die Schleife verlassen) 
									/*********************************************************/

		if (ControlFlag == 0)	//Wenn Spieler2 am Zug ist UND noch NICHT das Board ausgelesen wurde, wird das Board ausgelesen
		{

			ControlFlag = 1;	//Setze Kontrollflagge auf 1 um die erneute Ausgabe des Boards im selben Zug zu unterbinden!

			write(serial_port, msg2, sizeof(msg2));	//Übertragung des Befehls 0x42 an Board
			usleep(100);	//Systempause um eventuelle verzögerungen des Boards und entsprechenden Auslesefehler zu vermeiden 
			n = read(serial_port, &read_buf, sizeof(read_buf));	//Auslesen der Informationen des Boards; n entspricht der Länge des übermittelten "char" Arrays

			for (i = 3; i<n; i++)	//Daten werden mittels for-Schleife auf Terminal ausgegeben
			{
				HexOut = read_buf[i];	//Konvertiere char zu int

				if (HexOut<16)	//Um durchgängig zwei Ziffern auszugeben wird bei hex-zahlen kleiner 16 noch eine 0 zuvor ausgegeben
				{
					cout << "0";
				}

				cout << hex << HexOut << " ";	//Ausgabe in Hex

				if ((i - 2) % 8 == 0)	//erzeugt in dem Terminal ein 8x8 Feld
				{
					cout << endl;
				}

			}
			p = p + 1;	//Zählt die Periode
			cout << endl << "Periode: " << dec << p;	//gibt die Periode in Terminal aus
			cout << endl << "-------------------------------------------------" << endl;	//dient der übersichtlichkeit 
		}
		usleep(100);
	}

	close(serial_port);
}


/****************************************************************************************/



// Nichts unter dieser Linie verändern!!!
/**************************************************************************************/

void setup()
{
	serial_port = open("/dev/ttyACM0", O_RDWR);

	// Check for errors
	if (serial_port < 0) {
		printf("Error %i from open: %s\n", errno, strerror(errno));
	}


	// Create new termios struct, we call it 'tty' for convention
	// No need for "= {0}" at the end as we'll immediately write the existing
	// config to this struct
	struct termios tty;

	// Read in existing settings, and handle any error
	// NOTE: This is important! POSIX states that the struct passed to tcsetattr()
	// must have been initialized with a call to tcgetattr() overwise behaviour
	// is undefined
	if (tcgetattr(serial_port, &tty) != 0) {
		printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
	}

	tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
	tty.c_cflag |= PARENB;  // Set parity bit, enabling parity

	tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
	tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication

	tty.c_cflag &= ~CSIZE; // Clear all the size bits, then use one of the statements below
	tty.c_cflag |= CS8; // 8 bits per byte (most common)

	tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)

	tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

	tty.c_lflag &= ~ICANON;

	tty.c_lflag &= ~ECHO; // Disable echo
	tty.c_lflag &= ~ECHOE; // Disable erasure
	tty.c_lflag &= ~ECHONL; // Disable new-line echo

	tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

	tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl

	tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); // Disable any special handling of received bytes

	tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
	tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
						   // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
						   // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)

	tty.c_cc[VTIME] = 1;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
	tty.c_cc[VMIN] = 0;

	// Set in/out baud rate to be 9600
	cfsetispeed(&tty, B9600);
	cfsetospeed(&tty, B9600);

	// Save tty settings, also checking for error
	if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
		printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
	}
}



Dies sind Lauffähige C++-Programme, siehe nachfolgend in dem Kapitel Komponententest entsprechende Beispiele. Jedoch sind dies noch keine Nodes welche in ROS eingebunden werden können. Diese Skribte müssen dementsprechend noch zu Nodes konvertiert werden! Außerdem sind diese C++-Skribte Vorlagen zur ersten von vier geplanten Nodes.

Komponententest

Komponenten Beschreibung Bild
UR3 Hier Text einfügen
UR3Roboter
DGT Smart Board Hier Text einfügen
DGT Smartboard
DGT 3000 Schachuhr Hier Text einfügen
DGT3000 Schachuhr

Integrationstest

noch nicht erfolgt

Systemtest

noch nicht erfolgt

Abnahmetest

noch nicht erfolgt

Literatur

weitere nützliche sonstige Literatur[18] ist unter diesem Punkt zu finden.

Zusammenfassung

Ausblick

Da nicht alle Tätigkeiten die zur Umsetzung des Projektes benötigt waren umgesetzt werden konnten, werden nachfolgend einige noch offene Aufgaben aufgeführt und kurz erläutert.

  • vorhandenes C++-Sktipt in ROS-Node umwandeln: Da ROS mit einzelnen Nodes arbeitet und diese mit der C++ Syntax programmiert werden können, muss das vorliegende und funktionstüchtige C++-Skript zum auslesen der Board- und Uhreninformationen in eine ROS-Node transferiert werden.
  • Verbindung zwischen UR3 und RViz herstellen: Für die Bewegungsplanung über ROS/RViz muss die Verbindung zwischen UR3 und Computer über die Ethernet Schnittstelle hergestellt werden.
  • Node 2 - 4 erstellen: Um das System zu vervollständigen muss die Schachengine "Stockfish" durch eine Node angesprochen und alle notwendigen Informationen der Schachengine zur Verfügung gestellt werden. Nachfolgend muss das mapping der Koordinaten durch eine Node und die Robotersteuerung durch eine Node programmiert werden.
  • Weiterverfolgung des V-Modells: Nach Vervollständigung der Programmierung kann dann mit dem Intrgrations-, Systems- und Abnahmetest fortgefahren werden

Probleme und Lösungen

Literaturverzeichnis

  1. TortoiseSVN Client
  2. Anforderungsdefinition
  3. funktionaler Systementwurf
  4. technischer Systementwurf
  5. Komponentenspezifikation
  6. UR3Roboter: UniversalRobots- UR3Roboter. 2022. Online im Internet: https://www.i-botics.de/wp-content/uploads/2016/08/ur3_de.pdf; Abruf: 08.01.2022
  7. DGT: DGT - DGT Smart Board. 2022. Online im Internet: https://digitalgametechnology.com/products/home-use-e-boards/smart-board-with-indices; Abruf: 08.01.2022
  8. DGT: DGT - DGT3000. 2022. Online im Internet: https://digitalgametechnology.com/products/chess-clocks/dgt3000-fide-approved; Abruf: 08.01.2022
  9. www.docs.ros.org
  10. www.docs.ros.org/en/foxy/Tutorials.html
  11. ROS: ROS 2 nodes. 2022. Online im Internet: https://docs.ros.org/en/foxy/Tutorials/Understanding-ROS2-Nodes.html#nodes-in-ros-2; Abruf: 08.01.2022
  12. ROS: ROS 2 topics. 2022. Online im Internet: https://docs.ros.org/en/foxy/Tutorials/Topics/Understanding-ROS2-Topics.html; Abruf: 08.01.2022
  13. ROS: ROS 2 services. 2022. Online im Internet: https://docs.ros.org/en/foxy/Tutorials/Services/Understanding-ROS2-Services.html; Abruf: 08.01.2022
  14. ROS: ROS 2 actions. 2022. Online im Internet: https://docs.ros.org/en/foxy/Tutorials/Understanding-ROS2-Actions.html; Abruf: 08.01.2022
  15. RViz and MoveIt: Getting started with MoveIT and RViz. 2022. Online im Internet: https://ros-planning.github.io/moveit_tutorials/; Abruf: 08.01.2022
  16. Entwicklung
  17. mbedded.ninja
  18. sonstige Literatur