Experimente
Mehr oder weniger sinnvolle Experimente über Programmierung und Robot-Game

Präzise Ausgänge
Ziel war es für die kommende Saison Outputs mit erhöhter Präzision anzusteuern.

Linear Motion - Test Aufbaute
Ziel des ersten Test Aufbaus war es, den weißen Indikator präzise zu steuern. Dazu wurden Gearracks verwendet. Jedoch konnte man es durch das Getriebe erstmal nicht Präzise steuern.
Dieses Problem lösen wir software-technisch:
import color as col
from ..gsgr.enums import Attachment
from ..gsgr.movement import run_attachment
import motor
import time
from ..gsgr.config import cfg
display_as = "P"
color = col.RED
def run():
    run_attachment(Attachment.FRONT_RIGHT, -300, 0.5, stall=True) #1. gegen eine Blockade fahren
    run_attachment(Attachment.FRONT_RIGHT, 500, 60, stall=True, when_i_say_duration_i_mean_degrees=True) #2. Wieder positionieren
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True) #3. Bewegung
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, -300, 45, stall=True, when_i_say_duration_i_mean_degrees=True) #4. Kompensation des Richtungswechels
    run_attachment(Attachment.FRONT_RIGHT, -500, 85, stall=True, when_i_say_duration_i_mean_degrees=True) #5. Bewegung
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 300, 45, stall=True, when_i_say_duration_i_mean_degrees=True) #6. Kompensation des Richtungswechels
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True) #7. Bewegung
Um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) an einander zu drehen
Um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) auf die andere Seite an einander zu drehen
Bewegung auf erste Position
Bei Richtungswechsel muss um 45 Grad gedreht werden, um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) auf die andere Seite an einander zu drehen
Bewegung auf vierte Position
Bei Richtungswechsel muss um 45 Grad gedreht werden, um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) auf die andere Seite an einander zu drehen
Bewegung auf fünfte Position
Das Problem kann man auch hardware-technisch lösen:
import color as col
from ..gsgr.enums import Attachment
from ..gsgr.movement import run_attachment
import motor
import time
from ..gsgr.config import cfg
display_as = "P"
color = col.RED
def run():
    run_attachment(Attachment.FRONT_RIGHT, -300, 0.5, stall=True)
    run_attachment(Attachment.FRONT_RIGHT, 500, 60, stall=True, when_i_say_duration_i_mean_degrees=True)
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, 85, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, -500, 85, stall=True, when_i_say_duration_i_mean_degrees=True
Es muss nicht mehr der Richtungswechsel einkalkuliert werden, da durch die Spannung des Gummis die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) schon an einander gedrückt werden.

Rotary Motion - Test Aufbaute
Ziel des ersten Test Aufbaus war es, den weißen Indikator präzise zu drehen. Dazu wurde eine simple 90°-Übersetzung verwendet. Jedoch konnte man es durch das Getriebe erstmal nicht Präzise drehen.
Dieses Problem lösen wir software-technisch:
import color as col
from ..gsgr.enums import Attachment
from ..gsgr.movement import run_attachment
import motor
import time
from ..gsgr.config import cfg
display_as = "P"
color = col.RED
def run():
    run_attachment(Attachment.FRONT_RIGHT, -300, 0.5, stall=True) #1. gegen eine Blockade drehen
    run_attachment(Attachment.FRONT_RIGHT, 300, 60, stall=True, when_i_say_duration_i_mean_degrees=True) #2. Wieder positionieren 
    run_attachment(Attachment.FRONT_RIGHT, 500, 90, stall=True, when_i_say_duration_i_mean_degrees=True) #3. erste Bewegung
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, 180, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 300, -45, stall=True, when_i_say_duration_i_mean_degrees=True) #4. Kompensation des Richtungswechels
    run_attachment(Attachment.FRONT_RIGHT, 500, -90, stall=True, when_i_say_duration_i_mean_degrees=True) #5. dritte Bewegung
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 500, -90, stall=True, when_i_say_duration_i_mean_degrees=True)
    
Um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) an einander zu drehen
Um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) auf die andere Seite an einander zu drehen
Bewegung auf erste Position
Bei Richtungswechsel muss um 45 Grad gedreht werden, um die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) auf die andere Seite an einander zu drehen
Bewegung auf dritte Position
Das Problem kann man auch hardware-technisch lösen:
import color as col
from ..gsgr.enums import Attachment
from ..gsgr.movement import run_attachment
import motor
import time
from ..gsgr.config import cfg
display_as = "P"
color = col.RED
def run():
    
    run_attachment(Attachment.FRONT_RIGHT, -300, 0.5, stall=True)
    run_attachment(Attachment.FRONT_RIGHT, 300, 90, stall=True, when_i_say_duration_i_mean_degrees=True)
    run_attachment(Attachment.FRONT_RIGHT, 100, 90, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 1000, 180, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 1000, -100, stall=True, when_i_say_duration_i_mean_degrees=True)
    time.sleep(1)
    run_attachment(Attachment.FRONT_RIGHT, 1000, -90, stall=True, when_i_say_duration_i_mean_degrees=True)
    
Es muss nicht mehr der Richtungswechsel einkalkuliert werden, da durch die Spannung des Gummis die Zähne des Getriebecontainer (18947) und des Getriebezahnrads (35185) schon an einander gedrückt werden.

Fazit
Verwendungszwecke:
Drehungen, die nur in eine Richtung gehen
Linear Motion
Bei Drehungen mit weniger Kraft
Wenn man präzise Bewegungen braucht
Probleme:
Gummi-Spannung ist unterschiedlich und oft groß
Verzug bei zurücksetzen des Spiels
Rating: ⭐⭐⭐⭐ von 5

Plotten von Motordaten
Um interessante Korrelationen hervorzuheben. So kann man Gyro-Werte, Grad-Zahlen von Motoren, Geschwindigkeiten von Motoren oder Messwerte der Lichtsensoren graphisch anzeigen.

Wie funktioniert der Plot?
Es geht darum, wie man es einrichten kann, Daten auf einem Plot anzuzeigen. Um gesetzt wurde das ganze erstmal über Matplotlib und Tigerente.
import numpy as np
import matplotlib.pyplot as plt
import os
import time
plt.style.use('dark_background') #am wichtigsten ;)
fig, ax = plt.subplots()
ts, dt = [], []
with open('C://Users//Finn//.config//tigerente//info.log', 'r') as f: #öffnen der .log Datei
    while f.readline() != "": ... #alten Linien "überlesen"
    while True:
        last_line = f.readline() #neue Linie einlesen
        print(last_line.strip()) #nur der Wert; muss angepasst werden, je nach dem, wie man die Daten schickt
        if last_line[:11] == "INFO:root:>": #nach dem > kommen die Daten
            print(dt)
            dt.append(int(last_line[11:].strip())) #nur der Wert; muss angepasst werden, je nach dem, wie man die Daten schickt
            ts.append(time.time()) #timestamp für die x-Achse
            if len(dt)>10*5: #alten Werte werden wieder gelöscht
                dt.pop(0)
                ts.pop(0)
        ax.clear()
        ax.set_ylim(-100, 100) #je nach dem Was man sich anzeigen will, kann man das hier ändern
        ax.plot(ts, dt) #Einstellen der Werte
        plt.pause(0.05) #Anzeigen der Werte
    plt.show()
Auf der Seite des Spikes braucht man nur:
print(">", <dein_Wert>, sep="")
Und natürlich die Verbindung via Tigerente
 

Auslesen des Motorspiels
Der Motor hat ein gewisses Spiel, dieses kann man aber auslesen.
Man sieht also, dass der Motor ein Spiel von circa 8° hat.

Plotten von Geschwindigkeitsänderungen und Stop on Resistance
Hierbei geht es darum, die Geschwindigkeit von Motoren auszulesen und Veränderungen z.B. bei Blockaden zu erkennen.
import hub
import motor
import device
import time
async def loop():
    motor.run(hub.port.A, 1000) #Geschwindigkeit des Motors auf 1000 stellen
    while not hub.button.pressed(hub.button.POWER):
        print(">", device.data(hub.port.A)[0], sep="") #Übertragung der Geschwindigkeit
        time.sleep(0.2) #Damit es möglichst live, ist. Wenn zu niedrig kommt die BT-Übertragung nicht hinterher
    while hub.button.pressed(hub.button.POWER):
        ...
Das ist ein einfach Aufbau, der die Geschwindigkeit des Motors ausließt. Die gemessene Geschwindigkeit ist immer 1/10 so groß, wie die eingestellte.
Damit kann man jetzt zum Beispiel für präzise Outputs (Zum Artikel) richtig nullen, ohne unterschiedlich am Ende zu stehen und zu stark zu verziehen.
import hub
import motor
import device
import time
def until_stalled(speed, limfuck=0.8): #Funktion: speed: Geschwindigkeit vom Motor, limfuck: Prozent der Zielgeschwindigkeit, ab der gestoppt werden soll
    lim = abs(speed) / 10 * limfuck #limfuck * 10, weil die Geschwindigkeit nur 1/10 so groß ist
    motor.run(hub.port.A, speed)
    time.sleep(0.5) #Kann man noch besser machen, damit der Motor Zeit hat zu beschleunigen
    while not hub.button.pressed(hub.button.POWER):
        print(">", device.data(hub.port.A)[0], sep="") #Für BT-Übertragung
        
        sped = device.data(hub.port.A)[0] #gemessene Geschwindigkeit
        if lim > sped > -lim: #Überprüfun, ob die Geschwingigkeit zu niedrig ist
            break
        time.sleep(0.2) #Damit nicht zu viel via BT übertragen wird, sollte man aus dem Fenster schmeißen, wenn man keine BT-Übertragung macht
        
    
    motor.run(hub.port.A, 0) Motor wieder  ausschalten
    return
async def loop():
    while not hub.button.pressed(hub.button.POWER): #Unendlich vor und zurück
        until_stalled(500)
        until_stalled(-500)
    while hub.button.pressed(hub.button.POWER): #Debounce
        ...

Fazit - Stop on Resistance
Verwendungszwecke:
Wenn man präzise Ausgänge braucht (Zum Artikel)
Um zu Überprüfen, ob eine Motorbewegung geklappt hat:
wenn nicht nochmal irgendwas machen, z.B.: Wackeln
Für Motorbewegungen die nach einer bestimmten Kraft Verwendung aufhören sollen
Probleme:
Verzieht immer noch bisschen
einfach nur 0.5 Sekunden warten, vor Überprüfung
ToDo:
am echten Roboter testen
Rating: ⭐⭐⭐⭐⭐ von 5

Fazit - Plotten
Verwendungszwecke:
Motordaten - z.B.: um Stop on Resistance zu konfigurieren
Lichtsensordaten - z.B.: für Sonar oder C3PO
Gyrodaten - z.B.: um PID-Werte zu konfigurieren (oder LQR)
Probleme:
gewisse Zeitverzögerung durch BT
man braucht ein extra Programm
ToDo:
ohne print zu machen
Rating: ⭐⭐⭐⭐⭐ von 5