Hi,
das
wird so nicht funktionieren ...
Da wirst Du so was
machen müssen. Eventuell noch mit typecast
cheers,
-ds-
Hi,
das
wird so nicht funktionieren ...
Da wirst Du so was
machen müssen. Eventuell noch mit typecast
cheers,
-ds-
Entwicklung: RoPi - Autonomer Roboter mit RaspberryPI? Schau mal ob du hier fündig wirst!
Hm jetzt hab ich aber erst noch ein anderes Problem, und zwar beim übermitteln der Grid-Map...
Hab ein Sketch zum testen:
#include <Wire.h>
#define SERIAL_BAUD 38400 // Serial Baudrate to communicate with RaspberryPI, max 115200
// for Grid-Map and Path-Finding
const int GridSize = 15;
int Map[10][10] =
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 0, 0, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 254, 0, 255, 0, 1, 0, 0, 255},
{255, 0, 0, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 0, 0, 255, 255, 255, 0, 0, 255},
{255, 0, 255, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 255, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 255, 255, 255, 0, 255, 255, 255, 255},
{255, 0, 0, 0, 0, 0, 0, 0, 0, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
};
void printMap() {
Serial.println("StartMAP");
for (int X = 0; X < GridSize; X++) {
for (int Y = 0; Y < GridSize; Y++) {
Serial.println(Map[X][Y]);
Serial.flush();
}
}
Serial.println("EndMAP");
}
void setup() {
Serial.begin(SERIAL_BAUD);
Serial.println("Serial connection started, waiting for instructions...");
Serial.flush();
delay(1000); // give it time to init..
printMap();
}
void loop() {;}
Alles anzeigen
Wenn ich das nun flashe kriege ich über den Serial-Monitor von Arduino-IDE folgende Ausgabe:
Serial connection started, waiting for instructions...
StartMAP
255
255
255
255
255
255
255
255
255
255
255
0
0
0
255
255
0
0
0
255
0
0
0
0
255
255
0
254
0
255
255
0
254
0
255
0
1
0
0
255
255
0
0
0
255
255
0
0
0
255
0
0
0
0
255
255
0
0
0
255
255
0
0
0
255
255
255
0
0
255
255
0
255
0
255
255
0
255
0
255
0
0
0
0
255
255
0
255
0
255
255
0
255
0
255
0
0
0
0
255
255
0
255
255
255
255
0
255
255
255
0
255
255
255
255
255
0
0
0
0
255
0
0
0
0
0
0
0
0
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
255
0
0
318
269
198
0
0
318
269
198
207
228
245
0
0
1380
1545
1274
1323
1291
1380
1545
1274
1323
1291
1364
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
531
0
1000
0
EndMAP
Alles anzeigen
..nicht nur am Ende sondern auch mitten drin stimmt die Übergabe nicht mit der Map die ich definiert habe =(
//EDIT: argh! Erst jetzt beim Posten ist mir aufgefallen das ich vergessen hab GridSize auf 10 runter zu stellen
Nu passt die Ausgabe auch..
Serial connection started, waiting for instructions...
StartMAP
255
255
255
255
255
255
255
255
255
255
255
0
0
0
255
0
0
0
0
255
255
0
254
0
255
0
1
0
0
255
255
0
0
0
255
0
0
0
0
255
255
0
0
0
255
255
255
0
0
255
255
0
255
0
255
0
0
0
0
255
255
0
255
0
255
0
0
0
0
255
255
0
255
255
255
0
255
255
255
255
255
0
0
0
0
0
0
0
0
255
255
255
255
255
255
255
255
255
255
255
EndMAP
Alles anzeigen
Ich werd das aber letztlich so nutzen:
Nachteil wie bei allen Flash Chips ist aber auch hier das diese Teile nicht unendlich viele Schreibzyklen vertragen. Ab 100000 soll es wohl Probleme geben.
ich weiss das will keiner wissen, aber ein Blick ins Datenblatt vom Atmel m328p oder m2560 sagt:
Write/Erase Cycles: 10,000 Flash/100,000 EEPROM
nur mal so am Rande
Ich hab zZt ein seltsames Problem mit meinem WebInterface und einer Tabelle die ich via CSS erzeuge ... :s
Und zwar nutze ich für <div>'s den CSS Eintrag "display: table" usw um meine Tabellen zu erzeugen, in denen ich dann Sachen ausrichten und anordnen kann...
Dabei wird erst eine Box um Alles, mit Schatten und Rahmen angelegt worin sich dann weitere Boxen befinden. Also zB links oben eine "Connection" in der sich Connection Status usw befindet, rechts daneben noch eine Box mit Pan/Tilt und dem RaspiCam Stream - und rechts davon das Problemkind mit einem Kompass und der Grid-Map.. Genau diese richtet sich aber nicht wie alle anderen nach oben aus sondern seltsamerweise nach unten aber ich weiß nicht wieso
Screenshot: http://www11.pic-upload.de/06.11.14/c28ulqy66je.png
PHP Code: http://codepad.org/JAKtkViY
CSS Code: http://codepad.org/0j90jao9
Hoffentlich kann mir jemand helfen
//EDIT: Ach mist - denken müsste man können...
Ein Nachtrag von
in der style.css und schon gehts
//EDIT2: Gerade ist mir aufgefallen das der RaspberryPI meinen CMPS10 Kompass stört - also vermutlich das Magnetfeld beeinflusst... Wenn ich das Module weiter hinten beim Arduino platziere passen die Werte - allerdings nicht 0 bzw 360° = Norden, sondern Süden was aber korrekt ist, dort wo er hinzeigt ist wirklich Süden und alle anderen Himmelsrichtungen passen auch ... Muss mir jetzt nur was einfallen lassen wie ich den CMPS10 weiter hinten befestige
Kleines Update:
Bin derzeit noch immer am finetunen des WebInterfaces und der generellen Kommunikation zwischen Arduino und RaspberryPI.
Habe nun alle Werte die der Arduino übermittelt ins RoPi_Socket.py eingebunden und lasse es dort hinterlegen sowie teilweise auch schon verarbeiten (Rules).
Dabei ist mir aufgefallen das die RoPi_Socket.py mittlerweile eine CPU-Last von ca. 40% erzeugt, was ich aber zZt noch auf die Debugausgabe zurückführe - hab ich noch nicht ohne getestet, aber er gibt halt zZt alles mögliche noch auf der Konsole aus, was später aber nicht mehr sein muss (printD).. Aber insbesondere da ich im Arduino Sketch komplett auf Delay's verzichten möchte, überfluten teilweise die Messwerte den RaspberryPI wodurch dann die Auslastung rapide ansteigt (je nach Mode: AutoDrive, Explore oder Follow). Hoffentlich hält sich das in Grenzen wenn ich erst das eigentliche Brain einbaue und um weitere Rules erweitere
Mir wurde jetzt auch schon von einigen nahegelegt den Code in den nächsten Entwicklungsstufen nicht mehr offen zu legen - mit der Begründung das andere damit Geld verdienen könnten aber ich das lieber selber vermarkten solle... Das widerspricht allerdings meiner bisherigen Auffassung, schließlich hab ich auch extreme Probleme etwas passendes zu dem Thema zu finden und das bremst enorm aus. Wenn also mein Code anderen dabei hilft etwas ähnliches umzusetzen treibt das doch den Fortschritt voran? Davon profitiere ich dann später vielleicht auch
Ich bin derzeit aber auch am Überlegen den derzeit verbauten RaspberryPI Model-B durch den kommenden A+ zu ersetzen, da dessen Stromverbrauch aber auch die PCB Größe geringer ist... Oder einen anderen RaspberryPI-Clone wie zB den ODROID-W
Die RaspiCam will ich halt weiter benutzen können, damit bin ich eigentlich recht zu frieden, vorallem aber weil die so schön klein is
Stellt sich allerdings die allgemeine Frage wie ich die Drahtlose Kommunikation sicherstelle :s
Darüber habe ich auch schon aus anderen Gründen nachgedacht: Wenn das Gefährt später auch draussen herum fahren soll, hätte WiFi nur eine begrenzte Reichweite, man möchte aber ggf weiterhin auch Mobil Zugriff haben zB übers Smartphone oder ein Tablet...
Allgemein Funk würde wegen letzterem also auch nicht passend sein, da es denk ich ein größerer Aufwand wäre zB ein RFM12B Modul an einen PC zu koppeln, als sich einfach mit einem WiFI Hotspot zu verbinden.
Es gibt WiFI Module die sich über SPI anbinden lassen, wie zB das CC3000 WiFi module, allerdings weiß ich nicht inwiefern die kompatibel zum normalen Netzwerk sind und ob damit überhaupt Ad-hoc möglich ist
Odroid W wird ja leider nicht mehr produziert, ich "forsche" gerade mit dem Arietta G25 Modul rum, da hängen wir aber gerade ein bisschen beim Entfernungsmesser. Aber auch ich will die Kamera nutzen und die CSi schnittstelle fehlt da. Und die Kamera vom pcDuino ist mit 2MP unterlegen, ausserdem gibt es die nicht als "Nachtsichtkamera".
Ich würde es auch gut finden, wenn der Code offen bleibt. Wer wirklich Geld verdienen will macht das über Zubehör. Ich habe zum Beispiel ab übernächste Woche Roboterteile im Shop und will mal versuchen eine Bausatz für ein Fahrgestell anzubieten. Erstens interessiert es mich selbst und ich hatte mich geärgert, dass ich wieder viel rumsuchen musste und zweitens kommen seit dem ich eine Motorsteuerung für den RasPi anbiete echt viele Nachfragen. Raspberry Pi sei dank
Ja hey ...
...
Mir wurde jetzt auch schon von einigen nahegelegt den Code in den nächsten Entwicklungsstufen nicht mehr offen zu legen - mit der Begründung das andere damit Geld verdienen könnten aber ich das lieber selber vermarkten solle...
...
zunächst mal, denke ich, ist Open Source sicher der bessere Weg. Allein schon, wenn Du Dir vorstellst, dass alles, was Du Dir bisher im Web zusammen gesucht hast, statt dessen in irgendeiner Schublade verschlossen wäre ...
Zum zweiten ist das mit closed Source unter Linux nicht so einfach, wie unter anderen sog. Betriebssystemen ... und das ist auch gut so.
In dem Moment, in dem Du anderen Code oder andere Libs verwendest, bist Du an deren Nutzungsbedingungen gebunden. In der Regel heisst das, dass der Source mit ausgeliefert werden muss.
Das heisst aber nicht zwangsläufig, dass jeder Deinen Code einfach so verwenden oder evtl. sogar kommerziell nutzen darf. Ein entsprechener Hinweis auf die Nutzungsbedingungen reicht da schon.
Und verhindern kannst Du es i.d.R. eh nicht, dass jemand den Source kommerziell nutzt. Bestes Beispiel dafür ist das (afaik mittlerweile belegte) "Ausleihen" der BSD IP-Stacks durch eine sog. "Softwareschmiede" aus Redmond.
Wie gesagt ... ich würde das, in Anbetracht Deines Nutzens und dem nicht zu unterschätzenden Aufwand der Absicherung - wobei die Frage ist, ob das überhaupt (noch) möglich ist - einfach so lassen ...
...
Es gibt WiFI Module die sich über SPI anbinden lassen, wie zB das CC3000 WiFi module, allerdings weiß ich nicht inwiefern die kompatibel zum normalen Netzwerk sind und ob damit überhaupt Ad-hoc möglich ist
Ich habe gestern -> so eins <- geliefert bekommen.
Alles, was ich dazu bisher so gelesen habe, deutet darauf hin, dass das Teil recht gut funktionieren sollte. Wenn ich damit durch bin, poste ich mal einen Erfahrungsbericht.
Fastinierend finde ich, dass bei dem Preis trotzdem die TCP/IP Stacks im Modul sind und es sich nicht um einen simplen Controller sondern ein SoC handelt.
Wie gesagt ... ich bau mal das Breadboard auf und dann sehen wir weiter ...
cu,
-ds-
Das liest sich wirklich sehr gut, ist aber für den Arduino gedacht, oder? Allerdings ist das Module auch nicht 5V tolerant, kann also nicht direkt an den Mega2560 angeschlossen werden - aber da brauch zumindest Ich das eh nicht
Der Stromverbrauch ist auch bemerkenswert niedrig: https://nurdspace.nl/ESP8266#Power
Auch die Eigenschaften lesen sich faszinierend: https://github.com/esp8266/esp8266-wiki/wiki
Naja, bin mal auf Dein Erfahrungsbericht gespannt
Du hast ja nun Erster Eindruck: ESP8266 - WLAN-Modul mit rs232 Schnittstelle gepostet - Das WLAN-SoC Module ist wirklich sehr sehr interessant!
Werde ich mir glatt auch mal eins bestellen und meinen Roboter etwas umbauen - dann bräuchte ich nämlich nur noch einen USB-Port um den Arduino an den PI zu koppeln (und direkt flashen zu können)
Jetzt bin ich allerdings ernsthaft am überlegen welche Alternative ich für den RaspberryPI in Betracht ziehen kann... Generell muss ich wohl auch etwas mehr umbauen, alleine schon um meine Stromversorgung nun endlich irgendwo auf dem Gefährt unterbringen zu können und diese auch direkt zugänglich machen - also vom PowerPack (USB) auf ein Breadboard um von dort 5V für Bauteile usw zu beziehen, und von dort dann auch zum Minicomputer (derzeit dem PI) sowie Arduino.
Ich will die Stromversorgung nämlich auch noch Messbar haben, also aktuellen Ladezustand und die gelieferte Spannung etc. Damit ich frühzeitig erkennen kann wann er wieder aufgeladen werden muss usw
Der ODROID-W sah auf den ersten Blick eigentlich perfekt dafür aus, klein und genug Features... Da ich aber noch nicht genau weiß inwiefern die Auslastung aussehen wird wenn alle Rules fertig implementiert sind, könnte evtl. der SoC des PI's generell zu lahm sein
Der Edison sah auf den ersten Blick auch gut aus, hat aber leider zu wenig Digital I/O's um PI&Arduino zu ersetzen. Zusätzlich zum Arduino is der mir wiederum zu overkilled und teuer (also wenn sowas wie Edison dann nur beides Ersetzen)
Tja und weitere geeignete Alternativen hab ich noch nicht gefunden
Bin aber derzeit auch nebenbei noch am bereinigen des Codes: viele Leichen raus schmeißen, aufräumen und sortieren, teilweise optimieren und bisschen kommentieren.
Zum Wochenende werde ich dann mal eine Vorläufige Anleitung sowie den Code versuchen zu posten - hoffentlich krieg ich das verständlich hin
Ich hab mir am 12.11.2014 bei Sparkfun ein paar Teile bestellt um meinen RoPi über Sprache zu steuern sowie Töne/Musik abspielen zu können. Am gleichen Tag bestellte ich dafür auch etwas in China... Heute kam alles an:
Von Sparkfun:
Über eBay:
* Alle Teile sehen sehr gut aus - auch das aus China.
* Das Mikrophone ist ziemlich klein, bin gespannt ob das auch empfindlich genug ist. Erst später hab ich das möglicherweise besseren (und günstigere) Electret Microphone Amplifier - MAX4466 with Adjustable Gain von Adafruit gefunden, aber naja...
* Der Audio AMP (Verstärker) ist ebenfalls sehr klein - und muss soweit ich das gelesen habe so nah wie möglich an den Lautsprecher angebracht werden, also möglichst kurze Kabel. Da weiß ich nocht nicht inwiefern der Magnet vom Lautsprecher stören könnte... Es gibt auch Module zum abspielen von MP3's aber die sind ziemlich teuer. Deshalb hab ich mich für eines entschieden welches nur (uncompressed) WAV (8bit 16Khz mono) Dateien abspielen kann (bzw nicht das Module kann das sondern der Arduino bzw siehe dazu >hier<), schön billig und für mein Vorhaben ausreichend
Ausserdem hat das Module einen Shutdown Pin, über den man die Power des Modules abschalten kann um Strom zu sparen. Ich kann das Module also nur dann ein schalten wenn ichs auch wirklich benötige
Eigentlich sollte man Lautsprecher mit mehr Watt Leistung nehmen als der AMP liefern kann, um sowohl eine bessere Klangqualität zu haben aber auch keine Gefahr ihn zu überlasten.. Hab aber auf die schnelle keinen passenden kleinen gefunden.
* Das AMP Module benötigt bei voller Lautstärke 280mA, da sollte man halt drauf achten wenn mans mit 3V3 oder 5V betreiben möchte (der PI kann auf 3V3 bei weitem nicht so viel ausgeben, auch der Arduino kann auf 3V3 nur 50mA ausgeben)
* Die SD Karte muss mit FAT16 formatiert werden damit der Arduino darauf zugreifen kann.
Ich bin jetzt erst mal dabei alles anzuschließen und Kabels dran zu löten etc. Dabei werde ich mich nach >> dieser << Anleitung richten.
Melde mich später noch mal wenn ich den Code zurecht bastle
//EDIT: Zum testen habe ich die wav Dateien von hier verwendet: https://github.com/FellowRobotici…rExamples/piwav
Diese muss man aber noch umwandeln - habe ich mit WinAMP gemacht - auf:
PCM ; 16,000 kHz ; 8 Bit ; Mono
Zum testen habe ich zudem erst mal einen Arduino Nano v3 genutzt. Die Verkabelung sieht wie folgt aus:
Wie ihr seht hab ich kein " IN - " belegt da es ansonsten kratzt/rauscht/Störgeräusche gibt.
Die SD wie gesagt mit FAT16 formatieren und die umgewandelten WAV Dateien direkt auf die SD kopieren.
Dann benötigt man noch eine Lib: https://github.com/TMRh20/TMRpcm/
Den Nano hab ich dann mit folgendem Sketch geflasht:
[code=php]
/*
http://arduino.cc/en/pmwiki.php?n=Reference/SDCardNotes
Filenames on SD must be 8.3
To play it use uppercase Filenames.
Quality must be PCM ; 16,000 kHz ; 8 Bit ; Mono
SD card attached to SPI bus as follows:
MOSI - pin 11
MISO - pin 12
CLK - pin 13
CS - pin 4
*/
#include <SD.h> // need to include the SD library
#define SD_ChipSelectPin 4 // using digital pin 4 on arduino Nano
File root;
#include <TMRpcm.h> // also need to include this library...
#define SpeakerPin 9 //11 on Mega, 9 on Uno, Nano, etc
TMRpcm tmrpcm; // create an object for use in this sketch
#define PowerAMP 6 // digital pin 6 to control AMPs power
#define TurnOfAfterPlay 0 // 0 to disable
// this handy function will return the number of bytes currently free in RAM, great for debugging!
int freeRam(void) {
extern int __bss_end;
extern int *__brkval;
int free_memory;
if ((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__bss_end);
} else {
free_memory = ((int)&free_memory) - ((int)__brkval);
}
return free_memory;
}
void setup() {
tmrpcm.speakerPin = SpeakerPin;
Serial.begin(9600);
if (!SD.begin(SD_ChipSelectPin)) { // see if the card is present and can be initialized:
// Using F("...") to avoid wasting RAM
Serial.println(F("SD fail"));
return; // don't do anything more if not
}
Serial.println("Listing Files on SD:");
root = SD.open("/");
printDirectory(root, 0);
Serial.println("done!");
pinMode(PowerAMP, OUTPUT);
if (TurnOfAfterPlay == 0) {
digitalWrite(PowerAMP, 1); // turn AMP on
}
PlayWave("STAR_W~1.WAV");
Serial.print("FreeRAM: "); Serial.println(freeRam());
}
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
void PlayWave(char *file) {
if (tmrpcm.isPlaying()) { // already playing something, so stop it!
Serial.println("A wav file is being played, stopping it!");
tmrpcm.stopPlayback();
}
Serial.print("Playing: "); Serial.println(file);
if (TurnOfAfterPlay == 1) {
digitalWrite(PowerAMP, 1); // turn AMP on
}
tmrpcm.play(file);
if (TurnOfAfterPlay == 1) {
delay(500);
digitalWrite(PowerAMP, 0); // turn AMP off
}
}
void serialReceive() {
if (Serial.available() > 0) {
char InputString = Serial.read();
Serial.flush();
int Valid = 0;
if (InputString == '2') {
PlayWave("2.WAV");
} else if (InputString == '3') {
PlayWave("3.WAV");
} else if (InputString == '.') {
PlayWave("P.WAV");
} else if (InputString == 'a') {
PlayWave("ANVIL_~1.WAV");
} else if (InputString == 'b') {
PlayWave("PINKY_~1.WAV");
} else if (InputString == 'z') {
PlayWave("ZAK_MC~1.WAV");
} else if (InputString == 'i') {
PlayWave("STAR_W~1.WAV");
} else if (InputString == 'o') {
Serial.println("Turning AMP OFF");
digitalWrite(PowerAMP, 0); // turn AMP off
} else if (InputString == 'O') {
Serial.println("Turning AMP ON");
digitalWrite(PowerAMP, 1); // turn AMP on
} else if (InputString == 'p') {
Serial.println("Pause");
tmrpcm.pause();
} else if (InputString == '?') {
if (tmrpcm.isPlaying()) {
Serial.println("A wav file is being played");
} else {
Serial.println("Nothing is played");
}
} else if (InputString == 'S') {
Serial.println("Stop");
tmrpcm.stopPlayback();
} else if (InputString == '+') {
Serial.println("Valume UP");
tmrpcm.volume(1);
} else if (InputString == '-') {
Serial.println("Valume DOWN");
tmrpcm.volume(0);
} else if (InputString == '0') {
Serial.println("Quality DOWN");
tmrpcm.quality(0);
} else if (InputString == '1') {
Serial.println("Quality UP");
tmrpcm.quality(1);
}
}
}
// the loop routine runs over and over again forever:
void loop() {
if (Serial.available() > 0) { serialReceive(); }
}
[/php]
Die von mir verwendeten WAV Dateien könnt ihr >> hier << laden.
Wirklich lauter machen kann ich das aber leider nicht ohne das es anfängt zu schrabbeln - da ist vermutlich der Lautsprecher doch schon zu schwach für. Aber ansonsten funktioniert das schon wirklich sehr gut, ist auch laut genug
Als nächstes mach ich mich an die Mikrophone Steuerung (Voice Control)
Ich muss leider noch mal wegen der Grid-Map Geschichte nerven =(
Momentan mache ich das so:
Im Arduino Sketch hinterlege ich zZt. ein statisches Koordinaten-Array:
int Map[10][10] =
{
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
{255, 0, 0, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 254, 0, 255, 0, 1, 0, 0, 255},
{255, 0, 0, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 0, 0, 255, 255, 255, 0, 0, 255},
{255, 0, 255, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 255, 0, 255, 0, 0, 0, 0, 255},
{255, 0, 255, 255, 255, 0, 255, 255, 255, 255},
{255, 0, 0, 0, 0, 0, 0, 0, 0, 255},
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
};
Alles anzeigen
Dieses wird wie folgt an das 'the Brain' Script auf dem PI übermittelt:
void printMap() {
Serial.println("STARTMAP");
for (int X = 0; X < GridSize; X++) {
Serial.print("MAP: ");
for (int Y = 0; Y < GridSize; Y++) {
Serial.print(Map[X][Y]);
Serial.print(",");
}
Serial.println();
}
}
Alles anzeigen
Die Ausgabe sieht dann so aus:
STARTMAP
MAP: 255,255,255,255,255,255,255,255,255,255,
MAP: 255,0,0,0,255,0,0,0,0,255,
MAP: 255,0,254,0,255,0,1,0,0,255,
MAP: 255,0,0,0,255,0,0,0,0,255,
MAP: 255,0,0,0,255,255,255,0,0,255,
MAP: 255,0,255,0,255,0,0,0,0,255,
MAP: 255,0,255,0,255,0,0,0,0,255,
MAP: 255,0,255,255,255,0,255,255,255,255,
MAP: 255,0,0,0,0,0,0,0,0,255,
MAP: 255,255,255,255,255,255,255,255,255,255,
Alles anzeigen
Im Python Script verarbeite ich das dann wie folgt:
def ParseSerialInput(line):
global MapIndex
line = line.strip()
prefix = awk_it(line, 1)
if (prefix == "STARTMAP"):
MapIndex = 0;
elif (prefix == "MAP:"):
Values = awk_it(line, 2)
MapCoords.update({ MapIndex: Values });
MapIndex = MapIndex + 1;[/php]
Und ans WebSocketControl.py Script bzw das Web-Interface (das wird 1:1 durchgereicht) übergebe ich das dann so:
[code=php]
elif command == "get.Map":
if any(MapCoords):
for key in MapCoords:
returnlist += "\n get.Map:" + str(key) + ":" + MapCoords.get(key)
returnlist += "\n get.Map:END:END" #terminate list
else:
returnlist += "\n get.Map:NONE:NONE"[/php]
Das Web-Interface wiederum empfängt das so:
[code]\n get.Map:0:255,255,255,255,255,255,255,255,255,255, \n get.Map:1:255,0,0,0,255,0,0,0,0,255, \n get.Map:2:255,0,254,0,255,0,1,0,0,255, \n get.Map:3:255,0,0,0,255,0,0,0,0,255, \n get.Map:4:255,0,0,0,255,255,255,0,0,255, \n get.Map:5:255,0,255,0,255,0,0,0,0,255, \n get.Map:6:255,0,255,0,255,0,0,0,0,255, \n get.Map:7:255,0,255,255,255,0,255,255,255,255, \n get.Map:8:255,0,0,0,0,0,0,0,0,255, \n get.Map:9:255,255,255,255,255,255,255,255,255,255, \n get.Map:END:END
Alles anzeigen
(in einer Zeile)
Die Verarbeitung im Javascript wiederum sieht dann so aus:
[code=php]parseResponse(message.split("\n"));
function parseResponse(requestlist) {
for (var i=0; i<requestlist.length; i++) {
var requestsplit = requestlist[i].strip().split(':')
requestsplit[requestsplit.length] = "dummy";
command = requestsplit[0];
value = requestsplit[1];
value2 = requestsplit[2];
if( command == "get.Map" ) {
if (value == "NONE" && value2 == "NONE") {
mylog("..Currently no Grid Map Data available!..");
} else {
if (value == "END" && value2 == "END") {
drawMap(GridMapArray);
} else {
//add to array..
GridMapArray[value] = value2;
}
}
}
}
}
[/php]
Und zu guter letzt die Darstellung dieser Daten:
[code=php]
var lightgrey = "rgb(184,184,184)"; // background/unknown
var black = "rgb(0,0,0)"; // wall/barrier
var red = "rgb(255,0,0)"; // barrier
var green = "rgb(0,255,0)"; // goal
var blue = "rgb(0,0,255)"; // robot
var white = "rgb(255,255,255)"; // nothing/free
var grid = "rgb(255,250,205)"; // grid lines
function Init_Map() {
var canvas = document.getElementById('map');
//Canvas supported?
if (canvas.getContext){
var context = canvas.getContext('2d');
context.fillStyle = lightgrey;
context.fillRect( 0, 0, canvas.width, canvas.height );
}
}
function drawMap(GridMapArray) {
var canvas = document.getElementById('map');
//Y is vertical, X is horizontal
for (var Y = 0; Y < GridMapArray.length; Y++) {
var Coords = GridMapArray[Y].strip().split(",");
for (var X = 0; X < Coords.length; X++) {
if (Coords[X] == "") { continue; }
if (Coords[X] == ",") { continue; }
if (Coords[X] == 0) { // nothing, white
var r = 255;
var g = 255;
var b = 255;
} else if (Coords[X] == 1) { // goal, green
var r = 0;
var g = 255;
var b = 0;
} else if (Coords[X] == 254) { // robot, blue
var r = 0;
var g = 0;
var b = 255;
} else if (Coords[X] == 255) { // wall, black
var r = 0;
var g = 0;
var b = 0;
}
drawPixel(canvas, X, Y, r, g, b);
}
}
}
function drawPixel(canvas, x, y, r, g, b) {
if (canvas.getContext){
var context = canvas.getContext('2d');
var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);
var PixelSize = 4;
x *= PixelSize;
y *= PixelSize;
var index;
for (var i = 0; i < PixelSize; i++) {
for (var j = 0; j < PixelSize; j++) {
index = (x + (y + j) * canvas.width) * 4;
canvasData.data[index + 0] = r;
canvasData.data[index + 1] = g;
canvasData.data[index + 2] = b;
canvasData.data[index + 3] = 255; //Alpha Channel
}
++x;
}
context.putImageData(canvasData, 0, 0);
}
}
[/php]
...Das funktioniert soweit auch sehr gut... Nur gefällt mir das eben noch nicht
Zum einen glaub ich ist das zu viel Aufwand - der Arduino brauch glaub ich gar keine Map im Speicher haben. Und zum anderen sieht mir das zu banal aus, ich möchte das eigentlich so haben wie hier zu sehen:
Dabei stelle ich mir das so vor, dass der Roboter sich in der Mitte der Map befindet.
Also angenommen die Karte ist 100 x 100 Pixel groß, dann befindet sich der Roboter auf den Koordinaten 50 x 50.
Die Karte ist standardmäßig grau. Hindernisse sollen Schwarz dargestellt werden und der Roboter selbst blau.
Durch den Kompass kenne ich die Richtung in die der Ultraschall zielt, was z.B. Oben (Norden) wäre.
Nun verschickt der Roboter einen Ping und empfängt in einem Meter Entfernung etwas.
Da ich aber keinen Meter auf der Karte darstellen kann nehme ich einfach an das 1m = 1cm ist und auf der Karte 10 Pixel entsprechen würde.
Jetzt muss ich mit canvas eine Weiße Linie zeichnen die von den Koordinaten 50x50 nach oben bis 50 x 41 geht und 50 x 40 einen Schwarzen Pixel setzen...
Hab ich das soweit richtig verstanden
Woran ich jetzt allerdings zu knabbern habe ist der CODE.... Wie müsste der canvas Code dafür aussehen :s
...
... der Arduino brauch glaub ich gar keine Map im Speicher haben.
...
ach ne, oder ??
Zitat
...
... ein kleiner Ausschnitt oder gar nur das nächste Segment da vollkommen ausreichen.
...
cu,
-ds-
Und was soll mir dieser Post jetzt sagen? Darf ich von vorherigen Meinungen, die durch andere Forenmitglieder beeinflusst wurde, nicht abweichen?
Es gab im Chat als auch hier unzählige Diskussionen dazu, in denen mir geraten wurde ein MAP array auf dem Arduino anzulegen usw - auch andere Projekte dieser Art stützen sich darauf... Aber da ich hieran bereits seit einigen Monaten knabbere will ich was anderes ausprobieren.
Wenn du aber sonst nix weiter dazu zu sagen hast, dann verkneif dir bitte einen solchen Kommentar wie gerade
...
Wenn du aber sonst nix weiter dazu zu sagen hast, dann verkneif dir bitte einen solchen Kommentar wie gerade
warum sollte ich ...
cu,
-ds-
Kann ich vielleicht den, auch in canvas dargestellten, Kompass als Vorlage verwenden
Da sieht es wie folgt aus:
Es wird alle 500ms der bearing Wert abgefragt. Beim erhalten des Wertes wird folgendes aufgerufen:
[code=php]
if( command == "get.bearing" ) {
document.getElementById("DriveAnglenum").innerHTML = value+"°";
document.getElementById("DriveAngleperc").value=50+parseFloat(value)/2;
drawCompass(value);
}
[/php]
Zum erstellen des Kompass gehören folgende Javascript Anweisungen:
[code=php]function Init_Compass() {
var canvas = document.getElementById('compass');
if (canvas.getContext){
var context = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var FontSize = 15;
var NorthPos = w / 2 - FontSize; // when w = 200 and FontSize = 15 -> NorthPos = 85
var OstPos = h / 2 - FontSize;
var SouthPos = w / 2 - FontSize;
var WestPos = h / 2 - FontSize;
context.font = FontSize+"px Georgia";
context.fillStyle = 'black';
// "text", horizontal, vertical
context.fillText("N", NorthPos, FontSize);
context.fillText("O", (w - FontSize), OstPos);
context.fillText("S", SouthPos, h);
context.fillText("W", 0, WestPos);
}
}
function resetCompass() {
// clear canvas
var canvas = document.getElementById('compass');
if (canvas.getContext){
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
Init_Compass();
}
}
// http://www.dhtmlgoodies.com/tutorials/canvas-clock/
function drawCompass(degrees) {
var canvas = document.getElementById('compass');
if (canvas.getContext){
resetCompass();
var context = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var FontSize = 15;
var HandSize = w / 2 - FontSize;
context.save();
context.fillStyle = 'green';
context.strokeStyle = '#555';
// Move registration point to the center of the canvas
context.translate(w/2-FontSize, h/2-FontSize);
// Rotate degrees
context.rotate(degreesToRadians(degrees));
context.beginPath();
context.moveTo(0, 0) // this will actually be (85,85) in relation to the upper left corner
context.lineTo(0, HandSize) // (250,250)
context.stroke();
// Move registration point back to the top left corner of canvas
//context.translate(-w/2, -h/2);
context.restore();
}
}
function degreesToRadians(degrees) {
return (Math.PI / 180) * degrees
}[/php]
Stehe leider weiterhin etwas auf dem Schlauch
Hm mit der Kartenerstellung bin ich jetzt zwar noch nicht viel weiter - habe aber freundlicherweise einen (ziemlich professionellen) Code von > diesem Projekt < (Vorname: Will) erhalten der auch den Rover5+PCB verwendet und der mich dazu veranlasst hat meinen bisherigen Code noch mal komplett zu überarbeiten, da die Prozessorauslastung inkl. WebServer doch irgendwie zu hoch ist
Werde jetzt also daher gehen und das eigentlich Optionale aber trotzdem benötigte Web-Interface auf meinen anderen PI auslagern um zumindest die 20-40% Auslastung, die hauptsächlich durch den WebSocket und dessen Requests verursacht werden, nicht mehr direkt auf dem Roboter zu haben. Leider muss ich dann auch den Stream der RaspiCam übers Netzwerk schicken - das Script ist aber zum Glück schon dafür vorgesehen..
Besagtes Projekt ist beeindruckend umgesetzt:
Der macht alles über den PI, selbst die Pinbelegung bzw Funktion der Pins des Arduino's wird vom PI gesteuert bzw initialisiert. Ansprechen der Sachen etc macht auch alles der PI.
Auch die Kartenerstellung und Navigation geschieht in Python, wobei er nicht canvas nutzt sondern einfach eine Bilddatei über Python erzeugt und dann auf den Webserver hochläd.
Ersteres kommt mir etwas zu komisch vor, kann mir nicht vorstellen dass das schnell genug läuft (der PI weißt den Arduino an den einen Ping zu senden und anschließend sagt der PI das der Echo-Pin ausgelesen werden soll...).
Ist aber trotzdem beeindruckend zu sehen was man so alles machen kann
Allerdings habe ich nicht vor das auch so zu machen - möchte schon an meinem Konzept festhalten, nur muss ich Aufgrund von Befehls-Abarbeitung sowie "was passiert wenn die Verbindung zwischen den Scripts verloren geht" mehr auf ein Queue Verfahren setzen und deshalb den Kern meines Codes umschreiben... 'Will' macht das ähnlich, nutzt aber eine 3 Jahre alte Classe die mittlerweile discontinued ist.
Auch werde ich vermutlich dazu übergehen zumindest die Pan/Tilt Servos (und den einen Ultraschall Sensor) direkt über den PI zu steueren, um dem Arduino etwas Arbeit und somit Verzögerung abzunehmen...
Denn um so mehr der zu tun hat um so langsamer kann er andere Sachen ausführen und die Pan/Tilt Geschichte knallt mir einiges an Delay in den Ablauf rein
Da ich kleine Servo's sowie einen neuen Raspberry A+ verwende, sollte die Stromversorgung eigentlich kein Problem darstellen - wenn jemand anderes große Servos nutzt muss derjenige halt seine Spannung von einer anderen Quelle herholen da die Servos recht viel Ziehen können, aber das soll nicht mein Problem sein
Nochmal eine Übersicht der zZt. benötigten I/O's, um zu verdeutlichen wieso ich den Mega2560 weiterhin benötige:
/*
RoPi I/O pin definitions for Arduino Mega 2560
http://arduino.cc/en/Hacking/PinMapping2560
Rover 5 Explorer with Arduino Mega or DAGU Spider.
This page tells the controller which pin is connected to which sensor, switch, motor etc.
You can re-define the pins here to suit your robot. This is your wiring diagram!
Pins are usually chosen by their function but in some cases by physical location (shorter wires).
You may not require all functions listed here, ignore those you do not need.
*/
// https://forum-raspberrypi.de/forum/thread/13681-arduino-reboot/
#define PIN2RESET 33 // digital input D33
// HC-SR04
//5V on Arduino to VCC of HC-SR04
//Pin 30 of Arduino to TRIG of HC-SR04
//Pin 31 of Arduino to ECHO of HC-SR04
//GND of Arduino to GND of HC-SR04
#define ULTRASONIC_TRIG 30 // Ultrasonic HC-SR04 Sensor TRIGGER - digital output D30
#define ULTRASONIC_ECHO 31 // Ultrasonic HC-SR04 Sensor ECHO - digital input D31
#define ScannerServoPan 40 // PAN left or right - digital output D40
#define ScannerServoTilt 41 // TILT up or down - digital output D41
#define LMDpin 53 // Left Motor Direction - digital output D53
#define LMSpin 5 // Left Motor Speed PWM - digital output D4
#define LMCpin A6 // Left Motor Current - analog input A6
#define LMApin 2 // Left Motor Encoder A - external Interrupt0 D2
#define LMBpin 3 // Left Motor Encoder B - external Interrupt1 D3
#define RMDpin 52 // Right Motor Direction - digital output D52
#define RMSpin 4 // Right Motor Speed PWM - digital output D5
#define RMCpin A7 // Right Motor Current - analog input A7
#define RMApin 18 // Right Motor Encoder A - external interrupt5 D18
#define RMBpin 19 // Right Motor Encoder B - external interrupt4 D19
#define FRSpin A12 // Front Right IR Sensor - analog input A12
#define FLSpin A13 // Front Left IR Sensor - analog input A13
#define RLSpin A14 // Rear Left IR Sensor - analog input A14
#define RRSpin A15 // Rear Right IR Sensor - analog input A15
#define FRLpin 8 // Front Right IR LEDs - digital output D8
#define FLLpin 9 // Front Left IR LEDs - digital output D9
#define RLLpin 10 // Rear Left IR LEDs - digital output D10
#define RRLpin 11 // Rear Right IR LEDs - digital output D11
#define pingLED 12 // Ultrasonic activity LED - digital output D12
#define motorLED 49 // Motor activity LED - digital output D49
#define ErrorLED 22 // Error LED - digital output D22
// Note: optional speaker should have a series capacitor of between 10uF and 100uF
#define Speaker 24 // Speaker - digital output D24
Alles anzeigen
Ich werde also 5 Digitale Pins vom RaspberryPI verwenden, vermutlich aber auch noch den Speaker..
In der Liste fehlen aber auch noch 3 andere Ultraschall Sensoren, wobei die einen gemeinsamen Trigger-Pin verwenden sollen.
Dh. das erstellen der Karte ist jetzt erst mal in den Hintergrund gerückt - das neu organisieren des Codes wird erst mal genug Nerven kosten
So langsam komme ich auch an die Grenzen des Arduino's in Punkto Stromversorgung - viel mehr als das da oben kann der nicht versorgen. Dh ich muss auch hierfür noch eine externe 5V Stromversorgung anzapfen, also meine PowerBank, sodass nur noch 3V3 Sachen direkt über den Arduino laufen würden aber das sind zZt eh nur LEDs
Habt ihr fotos oder videos von euren Robotern ?
Kommt drauf an, was Du haben möchtest ... ich persönlich möchte nicht den x-tausendsten Nachbau eines fertigen Teil zusammen basteln.
Und wenn's anschliessend nicht so professionell aussieht ... mir zumindest egal.
Hallo Meigrafd,
interessante Studien, die du da treibst. Bin pensioniert und fange wieder an mit basteln und programmieren in PYTHON.
Ich habe mir auch schon Gedanken gemacht zu einem beweglichen Roboter. ich würde es vorziehen wenn die Programmierung in PYTHON erfolgen könnte, bin nicht so vertraut mit C oder Java.
Wie ist denn der Stand heute bei dir?
Du beschreibst in deiner Installation des Pi zwei Webserver: nginx und Tornado. Warum 2 Webserver?
Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!