morob:
Mit dem Stromverbrauch gebe ich Dir recht.
Die Echtzeitfähigkeit ist im Verbund mit einem kleineren Controller (ich mache Interruptgeschichten, Regelung, Reflexe … auf einem ATXMega) nicht mehr entscheidend.
Was mich allerdings abschreckt: 1MB RAM ist eine begrenzte Ressource. Bezüglich des Slams kann ich große Umgebungen zwar zwischen RAM und Flash rollen (die Sicht ist ja auf die Sensorreichweite begrenzt). Beim Pathfinder (der braucht ja im Zweifelsfall die gesamte Map, um den Weg von A nach B zu generieren) wird das allerdings kompliziert.
Frei nach https://www.heise.de/ct/artikel/An-d...ks-290662.html ein ganz einfacher SLAM (ohne Lösung für Closed loop oder kidnapped robot-Problem) für Lidaranwendungen
Eingangsseitig emmitiert die Hardware bei einer Sensormessung Abstandswert, Messwinkel und die aus den Odometriedaten ermittelte Pose des Roboters (X/Y/Orientation). Messungen werden auf dem Rechner bis zur vollständigen Umdrehung der Sensorplattform gesammelt und als ScanPackage an den SLAM-Algorithmus versendet (Es kommen also "viele" Messungen als Rundumblick gleichzeitig an).
Aufgabe 1: Der erste Scan wird anhand der subjektiven Roboterpose eingetragen (siehe obiger Artikel). Die Pose der letzten Messung im ScanPackage wird gepuffert. Eine zweite Pose (AlgPose) wird auf die Werte der subjektiven Pose initialisiert.
Aufgabe 2: Neues ScanPackage, neue letzte subjektive Pose. Bilde ein PoseChange (dx/dy, Blickwinkeländerung)
Aufgabe 3: Nimm einen Zufallsgenerator und variiere die drei Bestandteile von PoseChange um z.B. +/-20%. Bei 100 Variationen bekommst Du 100 leicht unterschiedliche PoseChanges zurück.
Aufgabe 4: Schlage jede generierte Variation von PoseChange einmal auf AlgPose auf und teste, wie die Sensorwerte in die bisherige Map passen (Test gibt einen Gewichtungswert (Anzahl der passenden Punkte frei-frei und besetzt-besetzt/Anzahl aller Punkte des Scans) für die Variation zurück)
Aufgabe 5: Trage die Sensorwerte der Variation mit dem größten Gewicht in Deine Map ein und schlage den dazugehörigen PoseChange auf die AlgPose auf.
That's it
Ohne Studium machbar, vielleicht etwas unbequem die Transformationen der Posen und Linien, aber auch nur Mittelstufenmathe.
Neben dem Raster und der Anzahl der Variationen darf man sicher noch den Test/Update verfeinern (z.B. messdistanzabhängige Fehler in der Gewichtung berücksichtigen und so eine Varianz um den gemessenen Punkt einführen). Auch kann man vielleicht mal am Zufallsgenerator spielen.
Sicher eine Menge Holz: Das testen von beispielsweise 100 Linien mit sagen wir durchschnittlich 30 Rasterpunkten in vielleicht 100 Variationen durch den Bresenham sind halt 300000 Rasterpunkte und Vergleiche zur Bearbeitung eines Scan-Paketes. Bei einem RPLidar mit 5 U/s und 360 Messungen/U wird das noch enger. Aber man muss ja nicht alle Messwerte im SLAM berücksichtigen. Für einen schneckigen Staubsauger erst recht nicht.
Code:public double Test(Pose pose, LidarScanData scan) { int mulSum = 0; int pointSum = 0; //Create absolute points from pose and scan data List<Line> transformed = TransformScanToPoints(scan, pose); //for each scan line foreach (Line ln in transformed) { if (ln != null) { int x0 = (int)Math.Round(ln.P1.X / Raster); int y0 = (int)Math.Round(ln.P1.Y / Raster); int x1 = (int)Math.Round(ln.P2.X / Raster); int y1 = (int)Math.Round(ln.P2.Y / Raster); int dx = Math.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1; int dy = Math.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1; int err = (dx > dy ? dx : -dy) / 2, e2; //rastering (Bresenham's line algorithm) for (; ; ) { int mul = (x0 == x1 && y0 == y1) ? this[x0, y0] : -this[x0, y0]; if (mul > 0) mulSum++; pointSum++; if (x0 == x1 && y0 == y1) break; e2 = err; if (e2 > -dx) { err -= dy; x0 += sx; } if (e2 < dy) { err += dx; y0 += sy; } } } } return (double)mulSum / (double)pointSum; } public List<Line> Add(Pose pose, LidarScanData scan) { //Create absolute points from pose and scan data List<Line> transformed = TransformScanToPoints(scan, pose); //for each scan line foreach (Line ln in transformed) { if (ln != null) { int x0 = (int)Math.Round(ln.P1.X / Raster); int y0 = (int)Math.Round(ln.P1.Y / Raster); int x1 = (int)Math.Round(ln.P2.X / Raster); int y1 = (int)Math.Round(ln.P2.Y / Raster); int dx = Math.Abs(x1 - x0), sx = x0 < x1 ? 1 : -1; int dy = Math.Abs(y1 - y0), sy = y0 < y1 ? 1 : -1; int err = (dx > dy ? dx : -dy) / 2, e2; for (; ; ) { //setPixel(x0, y0); this[x0, y0] = (SByte)Math.Max((int)this[x0, y0] - 1, -128); if (x0 == x1 && y0 == y1) { this[x0, y0] = (SByte)Math.Min((int)this[x0, y0] + 5, 127); break; } e2 = err; if (e2 > -dx) { err -= dy; x0 += sx; } if (e2 < dy) { err += dx; y0 += sy; } } } } return transformed; }
Geändert von Holomino (25.06.2020 um 23:53 Uhr) Grund: A1 Korrektur Init der ALgPose
das Problem ist, dass die Odometriedaten wegen Räder-Schlupf und Drift nicht zuverlässig genug sind, um die aktuellen Positionen zu ermitteln. Man kann u.U. noch nicht einmal öfters hintereinander exakte 90° Winkel fahren bei Teppichen, mit Teppichkanten, und wechselweise 1 Rad auch teilw. auf glattem Steinboden. Auch das Heading (Fahrtrichtung) lässt sich mit Gyro+Kompass indoors nicht sicher bestimmen (Kompass hat Fehlweisungen indoors durch metallische Störquellen, und der Gyro hat unvorhersehbare Drift in eine Richtung).
Daher kommt man mit dem obigen Beispiel nicht weit, das war ziemlich exakt genau das, bis wohin ich auch gekommen bin: nach ein paar Minuten steht der Robot irgendwo, aber nicht dort, wo er es berechnet hat, und in jede Richtung ausgerichtet, außer in die, in die er stehen soll. Die "Karte" entspricht also eher einer Phantasie gemalt von einem 3-jährigen als dem tatsächlichen Raum.
Folglich braucht man entweder super-getunete extended-Kalmanfilter oder externe Baken mit dm-Wellen für die Navigation.
(PS, Übrigens wird wschl Arduino C++ Code benötigt, aber das nur nebenbei)
Geändert von HaWe (25.06.2020 um 22:09 Uhr) Grund: PS
Was Du denkst, interessiert mich nicht.
Was mich aber interessiert, sind Leute wie Moppi oder Morob, die fragend oder prüfend einen Blick auf die Sache werfen. Und ich gehe jetzt einmal als im Eingangspost erwähnte Person davon aus, dass die bislang von mir eingestellten "Kinderkritzeleien" genug Neugier erweckt haben, dass es sich auch lohnt, Rückfragen zu beantworten.
Und denen gegenüber ist an Deinen Äußerungen aus meiner Sicht eine Menge Korrekturarbeit zu leisten.
Geändert von Holomino (26.06.2020 um 01:59 Uhr)
Irgendwie muss man einen Roboter zielgerichtet steuern. Ich bin noch nicht sicher, welcher Ansatz, der mir einfällt, dabei vielleicht auch nicht zuende gedacht ist. Da mangelt es an Erfahrung. Das Erstellen von Karten ist eine naheliegende Sache, auf die man von selbst auch immer wieder mal kommt. Interessant ist vor allem, wenn schon jemand mit selbst erstellten Karten gearbeitet hat, weil der weiß, ob sich der Aufwand lohnt. Es besteht auch die Möglichkeit, das so jemand sagt: ist alles gut und schön, aber im Grunde kann man das, was ich an Nutzen darin sehe, einfach auch mit anderen Algorithmen lösen, wie dass ein Roboter in der Wohnung zuverlässig von A nach B fährt. An anderer Stelle hatte ich schon beschrieben, wie ich mir so etwas auch vorstellen kann.
Wie geht denn SLAM mit sich ortsveränderlichen Objekten um, wie Haustieren, oder Schuhe, Spielzeug, die in der Wohnung zufällig herumstehen und von einer Minute auf die andere verschwinden und an anderer Stelle auftauchen können? Deshalb ist es doch wichtig, dass ein Roboter solche Objekte erkennen und umfahren kann, auch dass ein Roboter damit rechnen muss, dass die Objekte kurze Zeit später verschwunden sind. Wenn diese Aufgabe gelöst ist und zum Beispiel ein Algorithmus eingesetzt wird, der Räume Bahn um Bahn abfährt (um mal beim Staubsauger zu bleiben) und wenn der Roboter in der Lage ist, einzelne Räume auch ohne richtige Karte zu finden, eben zum Beispiel immer an der Außenwand lang fährt, braucht es dann SLAM, wie in Wikipedia beschrieben? Was ist denn an SLAM offenbar und macht es damit unabdingbar?
MfG
PS: ich finde das mit den Bildern von Holomino eine gute und brauchbare Sache, weil man daraus auch sicher Dinge ablesen kann, wenn man sich selbst näher damit beschäftigt.
In welcher Sprache ein Code verfasst ist, ist für Beschreibungszwecke nicht so wichtig. Solang es ein Code für irgendeine Hochsprache bzw. irgendein "Basic" ist, kann man dann schon sehen, was im Code passiert. So Sachen wie "foreach" kann man nochmal nachschlagen.
Geändert von Moppi (26.06.2020 um 06:09 Uhr)
ich bin jetzt sogar am denken mir einen preiswerten lidar zu besorgen und das ganze mit noch ein paar Sensoren mit einem teensy 4.1 zu testen. ich habe laminat in der wohnung. ich kann meine modellraketen zur zeit nicht starten![]()
danke für den artikel, mal einen artikel als basis, den man versteht
ich bin kein fan von ros, ich habe es mir angesehen und mir auch das Buch besorgt, welches hier im forum angesprochen wird. auf den punkt es ist mir zu "kompliziert" das ros.
ja, ich abeite arduino software, nicht alles optimal, aber was ist schon optimal.
Geändert von morob (26.06.2020 um 08:31 Uhr) Grund: typo
das leben ist hart, aber wir müssen da durch.
Grundsätzlich ist aber auch die Frage, was man von seinem "Modell" erwartet, und worauf man bereit ist zu verzichten.
Wenn man bereit ist, dauerhafte Schmutzecken zu akzeptieren, die ständig "vergessen" werden, kann man sicher auch mit sehr einfachen Konsruktionen leben.
Lesezeichen