- 12V Akku mit 280 Ah bauen         
Ergebnis 1 bis 6 von 6

Thema: RP6 mit Raspberry Pi verbinden

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    hm ok... der Einwand hat Hand und Fuß. Die Datenrichtung habe ich übersehen. Asche über mein Haupt. Aber beim senden von Daten vom RP6 auf den PC hatte ich auch schon solche Phänomene und ein PC mit BufferUART wie der 16550 steht bei 38,4 kbaud nicht im Verdacht Daten zu verlieren.

    Das Argument mit Anfänger und blockierend... hm... Ok ich sehe ein das es für Anfänger zunächst "durchsichtiger" ist. Tatsächlich schränkt es aber auch massiv ein, vor allem wenn man viele Daten vom RP6 auf den PC sendet.

    Code:
    void writeChar(char ch)
    {
        while (!(UCSRA & (1<<UDRE)));
        UDR = (uint8_t)ch;
    }
    Das Argument mit der Baudzahl ist übrigends interssant. Bedeutet es doch, daß je langsamer man die Baudzahl stellt, man sich um so mehr Probleme im Timing des Systems verschafft weil weniger Baud auch automatisch länger pollen von UDRE in UCSRA bedeutet. Wir reden bei 9600 baud gegen 38400 baud schon um den Faktor 4. Gibt man seitenweise Text wie im Beispiel aus, kommen da schon einige Sekündchen zusammen in denen die CPU nur UCSRA pollt und bestenfalls irqs bearbeitet.
    Der bestechende Vorteil der Methode... man braucht sich kein Kopf über volle Buffer zu machen, die bei viel Text sogar mit irq-senden ein Warten auf Platz im Buffer erzwingen würde.
    Spätestens da hatte ich damals beschlossen freeRTOS zu nutzen, da kann man die Warterei wenigstens anderen Tasks als Rechenzeit zuteilen.
    Allerdings verkompliziert das widerum _etwas_ das Interrupthandling
    Gruß
    Sind Sie auch ambivalent?

  2. #2
    Erfahrener Benutzer Roboter Genie Avatar von SlyD
    Registriert seit
    27.11.2003
    Ort
    Paderborn
    Alter
    40
    Beiträge
    1.516
    Zitat Zitat von RolfD Beitrag anzeigen
    Aber beim senden von Daten vom RP6 auf den PC hatte ich auch schon solche Phänomene und ein PC mit BufferUART wie der 16550 steht bei 38,4 kbaud nicht im Verdacht Daten zu verlieren.
    Tatsächlich ein echter Serialport und am RP6 ein RS232 Levelshifter?
    Oder doch nur per USB emuliert?
    (die echten sind selten geworden)
    Der FT232R hat z.B. "nur" 128 Byte Empfangspuffer und über USB gibts ja durchaus lange Latenzen bis in den 50ms Bereich...
    Der 16550 hat übrigens nur 16 Bytes Puffer... ist aber natürlich direkter angebunden daher reicht das i.d.R.


    Zitat Zitat von RolfD Beitrag anzeigen
    Das Argument mit Anfänger und blockierend... hm... Ok ich sehe ein das es für Anfänger zunächst "durchsichtiger" ist. Tatsächlich schränkt es aber auch massiv ein, vor allem wenn man viele Daten vom RP6 auf den PC sendet.
    Wer möchte kann mit ähnlicher Methode wie beim Empfangen auch beim Senden vorgehen.
    Wer soweit ist dass er das braucht, kann das auch selbst implementieren denke ich.


    Zitat Zitat von RolfD Beitrag anzeigen
    Wir reden bei 9600 baud gegen 38400 baud schon um den Faktor 4.
    Deswegen verwendet der RP6 38400 Baud und nicht 9600
    38400 wurde gewählt, weils noch langsam genug ist dass das mit den meisten anderen Gerätschaften die man daran anschließen könnte problemlos läuft
    (wie man an einigen Threads zu Funkmodulen sieht, ist aber selbst das oft noch zu hoch),
    aber schnell genug dass größere Textausgaben nicht allzu lange brauchen - das wurde bei der Entwicklung getestet und für gut genug befunden.
    Man kann wenn man mag mit eigener Software auch auf andere höhere Baudraten wechseln - wie es der Bootloader ja auch tut.
    Das WLAN Modul läuft z.B. auch direkt mit 500k Baud.


    MfG,
    SlyD

  3. #3
    Erst einmal danke für die Antworten. Das mit den Timeouts + Protokoll werde ich mal versuchen.

    Mittlerweile hab ich es geschafft, eine Steuerung für den RP6 über den PC zu bauen. Ein Protokoll ist hier denke ich nicht unbedingt notwendig, da nur hier und da ein paar Parameter versendet werden. Im Grunde sendet der PC die Parameter (Bewegungsart, Richtung, Distanz, Speed) an den Pi, der leitet die Parameter dann weiter zum RP6, der den Befehl dann verarbeitet. Hier der Quellcode, falls es jemanden interessiert:

    Auf dem PC wird eine normale HTML-Seite verwendet, über Ajax werden dann einfach die gewählten Parameter per HTTP GET Request an den Webserver auf dem Pi geschickt. Der Pi und der PC müssen sich nur im gleichen Netzwerk befinden, dann muss man noch die richtige IP-Adresse eintragen. Die Jsonp-Sache dient nur zu Debug-Zwecken, braucht man, um Daten auch wieder vom Pi an den PC zurückzuschicken.

    HTML-Code:
    <html>
    <head>
    <script src="jquery-1.10.2.min.js"></script>
    <title>RP6 Steuerung </title>
    </head>
    <body>
    <h1> RP6 Steuerung </h1>
    
    <script>
    function sendCommand()
    {
      var move = document.Formular.movement[document.Formular.movement.selectedIndex].value;
      var dir = document.Formular.direction[document.Formular.direction.selectedIndex].value;
      var dist = document.Formular.distance.value;
      var speed_ = document.Formular.speed.value
      $.ajax({
          type: 'GET',
          url:  'http://10.0.0.4',
          dataType: 'jsonp',
          jsonp: 'jsonp',
          jsonpCallback : 'parseResponse', 
          crossDomain: true,
          data: {movement: move, direction: dir, distance: dist, speed: speed_},
          error: function (data){
            $('#antwort').html("Befehl konnte nicht gesendet werden: " + data);
          },
          success: function (data){
            $('#antwort').html("Folgender Befehl wurde erfolgreich gesendet:<br>" + "Bewegung: " + data.movement + "<br>Richtung: " + data.direction + "<br>Distanz/Grad: " + data.distance + "<br>Geschwindigkeit: " + data.speed);
          }
       });
    }
    </script>
    <form name="Formular">
    Bewegung:<select name="movement">
    <option>Fahren</option>
    <option>Rotieren</option>
    </select><br>
    Richtung:<select name="direction">
    <option>Vor</option>
    <option>Zurueck</option>
    <option>Links</option>
    <option>Rechts</option>
    </select><br>
    Distanz/Grad:<input name="distance"><br>
    Geschwindigkeit:<input name="speed" value="100"><br>
    <a href="javascript:sendCommand()">Senden!</a>
    </form>
    
    <div id="antwort">
    
    </div>
    
    </body>
    </html>
    Auf dem Pi verwende ich das Framework Flask für den Webserver und die pylibftdi für die Kommunikation zum USB-Interface. Das Script verarbeitet HTTP-Anfragen und sendet die Parameter durch einen Strichpunkt getrennt an den RP6 weiter.

    Code:
    from flask import Flask
    from flask import request
    from pylibftdi import Device
    import time
    
    app = Flask(__name__)
    
    @app.route('/')
    def send_command():
    	if 'direction' in request.args and 'movement' in request.args and 'distance' in request.args and 'speed' in request.args:
    		with Device(mode='b') as dev:
    			dev.baudrate = 38400
    			dev.write(request.args.get('movement') + ';' + request.args.get('direction') + ';' + request.args.get('distance') + ';' + request.args.get('speed') + '\n')
    			time.sleep(1)
    			answer = dev.readline()
    			print repr(answer)
    		return request.args.get('jsonp') + '({"text": "Kommando wurde erfolgreich gesendet",' + '"direction":"' + request.args.get('direction') + '","movement":"' + request.args.get('movement') + '","distance":"' + request.args.get('distance') + '","speed":"' + request.args.get('speed') + '"})'; 
    	else:
    		return 'Willkommen zur RP6-Steuerung!'
    if __name__ == '__main__':
    	app.run(host='0.0.0.0', port=80, debug=True)

    Auf dem RP6 habe ich zum Einlesen im Grunde das Beispielprogramm genommen. Die Parameter werden in ein Struct geschrieben, welches dann einer Funktion übergeben wird, die den Befehl ausführt.

    Code:
    #include "RP6RobotBaseLib.h" 
    #include <stdint.h>
    
    #define MAX_SIZE 70 // maximum UART buffer size
    
    typedef struct command
    {
    	char movement_ [20];
    	char direction_ [20];
    	char distance_string_ [20];
    	char speed_string_ [20];
    	int16_t distance_; // also degrees for rotation
    	int16_t speed_;
    } Command;
    
    void executeCommand (Command* command)
    {
    	uint8_t direction = 0;
    	if (strcmp(command->direction_,"Vor") == 0)
    	{
    		direction = FWD;
    	}
    	else if (strcmp(command->direction_,"Zurueck") == 0)
    	{
    		direction = BWD;
    	}
    	else if (strcmp(command->direction_,"Links") == 0)
    	{
    		direction = LEFT;
    	}
    	else if (strcmp(command->direction_,"Rechts") == 0)
    	{
    		direction = RIGHT;
    	}
    
    	//fortunately the functions move and rotate have the same signature
    	void (*movement_function) (uint8_t, uint8_t, uint16_t, uint8_t) = 0;
    
    	if (strcmp(command->movement_,"Fahren") == 0 && (direction == FWD || direction == BWD) && command->speed_ <= 200)
    	{
    		command->distance_ = DIST_CM(command->distance_);
    		movement_function = move;
    		setLEDs(0b111000);
    	}
    	else if (strcmp(command->movement_,"Rotieren") == 0 && (direction == LEFT || direction == RIGHT))
    	{
    		movement_function = rotate;
    		setLEDs(0b000111);
    	}
    
    	// execute the function, either move or rotate
    	if (movement_function)
    	{
    		movement_function(command->speed_,direction,command->distance_,true);
    	}
    }
    
    void readInput(void)
    {
    	char receiveBuffer [MAX_SIZE+1];
    	clearReceptionBuffer();
    	uint8_t buffer_pos = 0;
    	while (1)
    	{
    		if(getBufferLength())
    		{
    			receiveBuffer[buffer_pos] = readChar();
    			if (receiveBuffer[buffer_pos] == '\n')
    			{
    				break;
    			}
    			buffer_pos++;
    			if (buffer_pos >= MAX_SIZE)
    			{
    				writeString_P("Too many characters entered!\n");
    				return;
    			}
    		}
    	}
    	buffer_pos++;
    	receiveBuffer[buffer_pos] = '\0';
    
    	// parse the receive buffer and store the values to the Command struct, parameters are separated by a ';'
    	Command command;
    	char* string = command.movement_;
    	uint16_t i = 0;
    	uint16_t k = 0;
    	while (1)
    	{
    		if (receiveBuffer[i] == ';') // delimiter was found
    		{
    			string[k] = '\0'; 
    			string += 20; //set the pointer to the next char* in the Command struct
    			k = 0;
    			i++;
    			continue;
    		}
    		if (receiveBuffer[i] == '\n')
    		{
    			string[k] = '\0';
    			break;
    		}
    		string[k] = receiveBuffer[i];
    		k++;
    		i++;
    	}
    
    	// convert string to integer
    	command.distance_ = atoi(command.distance_string_);
    	command.speed_ = atoi(command.speed_string_);
    
    	// debug: send the values back to the Raspberry Pi
    	writeString(command.direction_);
    	writeString(command.movement_);
    	writeInteger(command.speed_,DEC);
    	writeInteger(command.distance_,DEC);
    
    	executeCommand(&command);
    }
    
    int main(void)
    {
    	initRobotBase(); 
    	powerON();
    
    	while(1)
    	{
    		readInput();
    		task_RP6System();
    	}
    	return 0;
    }

Ähnliche Themen

  1. RP6 mit Raspberry Pi
    Von ccontroller im Forum Robby RP6
    Antworten: 20
    Letzter Beitrag: 10.05.2018, 23:31
  2. 457 kHz - Empfänger mit Roboter (RP6?) verbinden
    Von NBPH im Forum Allgemeines zum Thema Roboter / Modellbau
    Antworten: 3
    Letzter Beitrag: 01.02.2011, 05:41
  3. Rp6 mit asuro verbinden?
    Von Philsuro im Forum Robby RP6
    Antworten: 2
    Letzter Beitrag: 28.08.2010, 16:56
  4. RN-Funk Bausatz mit PC und RP6 verbinden
    Von abugilgil im Forum Robby RP6
    Antworten: 12
    Letzter Beitrag: 10.04.2010, 11:12
  5. RP6 mit RS232 verbinden ohne max232/pegelwandler?
    Von -schumi- im Forum Robby RP6
    Antworten: 13
    Letzter Beitrag: 08.04.2010, 18:24

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress