Jump to content

mts75

Members
  • Gesamte Inhalte

    8
  • Benutzer seit

  • Letzter Besuch

mts75's Achievements

Newbie

Newbie (1/14)

0

Reputation in der Community

  1. Hallo Marco, das mit den Steppern, Schrittwinkeln etc. ist mir schon soweit alles klar. Ich habe z.Z. ein Programm, mit dem ich interaktiv mit Menüs (im 20x4-Display) und über Joststick-Bricklets Positionen manuell anfahren und quasi lernen kann. Der Roboterarm fährt später die gelernten Punkte nacheinander an. Dabei ist halt blöd, dass die Motoren nicht schön gleichzeitig ankommen (was eleganter aussähe), sondern je nach Weg auf den 3 Achsen beispielsweise 2 Motoren schon stehen und der letzte noch läuft. Das wirkt dann irgenwie nicht geschmeidig. Mir fehlt jetzt einfach der mathematische Ansatz, die Stepper-Bricks so mit Parametern zu steuern, dass sie (annähernd) gleichzeitig ankommen. Wenn man die Formel im Stepper-Brick kennen würde, wäre das wohl am einfachsten, deshalb die Frage hier im Forum. Wir haben ja als fest eingestellte Werte: Step-Mode (m.E. unwichtig??), MaxVelocity, die beiden SpeedRamping-Werte (bestehend aus beschleunigen und bremsen) Dann weiß ich aus der Anlernphase, zu welcher absoluten Position die drei Achsen laufen müssen, um den Punkt anzufahren und setze sie mit setTargetPosition. (z.B. x=1845, y=345, z=1344) Also weiß ich, wieviele Steps jeder Motor laufen wird um dort hin zu gelangen. Wenn ich nun gleichzeitig ankommen will, müsste ich erstmal berechnen, wie lange eine Motor-Fahrt unter den o.g. Bedingungen dauern *würde*. Dann könnte man den Zeitwert des langsamsten Motors nehmen und die anderen beiden im Wert MaxVelocity so relativieren, dass deren Zeitdauer für die Positionierung genau so lange dauern wird, wie mit dem langsamsten Motor. Ist hoffe, das ist irgendwie verständlich. Zuerst müsste ich also eine Methode schreiben: ... berechneLaufdauerMotorfahrtInMillisekunden(maxGeschwindigkeit, beschleunigungswert, bremswert, anzahlSteps) Aber was könnte ich da reinschreiben? ... ;-) Vielleicht geht das ja auch einfacher und ich übersehe was? Keiner soll das für mich Lösen aber ich wäre für einen Denkanstoß dankbar ...
  2. Hallo Zusammen, ich steuere einen dreiachsigen Roboter mit drei Schrittmotoren, die jeweils an einem Stepperbrick hängen. Nun möchte ich erreichen, dass alle Motoren mit relativen Geschwindigkeiten laufen, um möglichst gleichzeitig die jeweilige Endposition in X/Y/Z zu erreichen. Nun besitzt der Stepper-Brick ja zusätzlich zur Position die Eigenschaften für Beschleunigung, Endgeschwindigkeit und Abbremsen, die ich pro Fahrt relativieren müsste, damit alle Motoren gleichzeitig ankommen. Dazu bräuchte man aber eine Formel, mit der man die Dauer der Motoraktion vorhersagen kann, um die MaxDuration auf dem aufgrund des Weges langsamsten Motor so anzupassen, dass der zusammen mit dem schnellsten dort ankommt. Irgendeine Idee, wie ich da vorgehen könnte? (Da ich den Algorithmus im Stepper nicht genau kenne, bliebe ja nur, eine Art selbstlernendes System zu bauen, dass die Zeiten bis zum Erreichen stoppt, und je nach Duration eine Tabelle mit Anpassungsfaktoren pflegt und bei jedem Lauf verfeinert, aber das muss doch einfacher gehen!??) Viele Grüße Markus
  3. Habt Ihr bei TF schon mal darüber nachgedacht, das IO4-Bricklet mit leistungsfähigen Ausgängen aufzulegen? Ich schalte z.Z. ein paar TIP 110 Leistungsstufen hinterher die Ausgänge und habe ziemlich viel Kabelwirwar. Damit könnte man 4 kleinere Motoren oder Spulen etc. direkt ansteuern, ohne direkt in 4 DC-Bricks zu investieren. Und eine Schutzdiode für induktive Lasten könnte direkt mit verlötet sein. (ist bei TIP 110 sogar schon eingebaut) Viele machen so etwas vermutlich mit dem DualRelais-Brick, aber die Klackern nervig und machen bei induktiven Lasten ja schon diverse Probleme ...
  4. Nach dem ich ein paar Stepper-Bricks gekauft habe, spiele ich zur Zeit auch mit Schrittmotoren herum, die ich noch in der Elektro-Kiste liegen hatte. Nicht jeder Motor unterscheidet allerdings die 1/8-Schritte absolut zuverlässig voneinander und einige machen generell bei Microsteps auch ziemlich fiese Dauerfiep-Geräusche. Du hast hoffentlich kein Haustier und stellst die Konstruktion nicht ans Bett?
  5. So, habe mich mal durchgekämpft und das in Java versucht. Funktionieren tuts aber die Api ist so m.E. noch nicht wirklich Endanwenderfreundlich. Vielleicht kann man ja noch mal was komfortableres vor die eigentliche RED-API hängen mit High-Level Funktionen wie "sendFile" "getFile" "startProgram" etc. Jeden String so blockweise abzuholen und an diverse Resourcenfreigaben denken zu müssen sollte vor den Nutzern am besten versteckt werden. Vielleicht kann ein Wissender von Euch Profis das mal qualitätssichern und als temporäre Musterlösung in die Java-Doku zum RED stellen ... dann haben es bestimmt auch die C#-Leute einfacher. Ich werden mir zum Programme starten aber vermutlich einen Launcher mit Joystick- und Display-Bricklet schreiben, dann kann man Programme schön direkt wählen und diesen Launcher immer mit dem RED starten und dauerhaft laufen lassen. Wie ich die eigentlichen Programme von Java aus starte, weiß ich ja jetzt in etwa ... import com.tinkerforge.*; import java.util.HashMap; /** * Demonstrates, how to start a Program on RED Brick by name. * Created by Markus Arndt, 01.06.2017 */ public class StartProgram { private final static HashMap<Integer, String> ERROR_CODES = new HashMap<Integer, String>(); static { ERROR_CODES.put(0, "Success"); ERROR_CODES.put(1, "UnknownError"); ERROR_CODES.put(2, "InvalidOperation"); ERROR_CODES.put(3, "OperationAborted"); ERROR_CODES.put(4, "InternalError"); ERROR_CODES.put(5, "UnknownSessionID"); ERROR_CODES.put(6, "NoFreeSessionID"); ERROR_CODES.put(7, "UnknownObjectID"); ERROR_CODES.put(8, "NoFreeObjectID"); ERROR_CODES.put(9, "ObjectIsLocked"); ERROR_CODES.put(10, "NoMoreData"); ERROR_CODES.put(11, "WrongListItemType"); ERROR_CODES.put(12, "ProgramIsPurged"); ERROR_CODES.put(128, "InvalidParameter"); ERROR_CODES.put(129, "NoFreeMemory"); ERROR_CODES.put(130, "NoFreeSpace"); ERROR_CODES.put(131, "AccessDenied"); ERROR_CODES.put(131, "AlreadyExists"); ERROR_CODES.put(133, "DoesNotExist"); ERROR_CODES.put(134, "Interrupted"); ERROR_CODES.put(135, "IsDirectory="); ERROR_CODES.put(136, "NotADirectory"); ERROR_CODES.put(137, "WouldBlock"); ERROR_CODES.put(138, "Overflow"); ERROR_CODES.put(139, "BadFileDescriptor"); ERROR_CODES.put(140, "OutOfRange"); ERROR_CODES.put(141, "NameTooLong"); ERROR_CODES.put(142, "InvalidSeek"); ERROR_CODES.put(143, "NotSupported"); ERROR_CODES.put(144, "TooManyOpenFiles"); } private final static String HOST = "192.168.178.33"; // Change to IP width BrickDeamon private final static int PORT = 4223; private final static String UID_RED = "2SBmHu"; // Change to UID from RED-Brick private final static String PROGRAM_NAME = "Robi"; // Change to Name from Program to start public static void main(String[] args) throws Exception { IPConnection ipConnection = new IPConnection(); BrickRED red = new BrickRED(UID_RED, ipConnection); ipConnection.connect(HOST, PORT); boolean started = startProgram(ipConnection, red, PROGRAM_NAME); ipConnection.disconnect(); if(! started) System.out.printf("Program " + PROGRAM_NAME + " could not be found/started."); } public static boolean startProgram(IPConnection ipConnection, BrickRED brickRED, String programName) throws TimeoutException, NotConnectedException { BrickRED.CreateSession session = brickRED.createSession(10); checkError(session.errorCode); BrickRED.Programs listPrograms = brickRED.getPrograms(session.sessionId); checkError(listPrograms.errorCode); BrickRED.ListLength listProgramsSize = brickRED.getListLength(listPrograms.programsListId); checkError(listProgramsSize.errorCode); // Iterate over Program-List from RED Brick boolean startet = false; for(int i = 0; i < listProgramsSize.length; i++) { BrickRED.ListItem currentProgram = brickRED.getListItem(listPrograms.programsListId, i, session.sessionId); checkError(currentProgram.errorCode); BrickRED.ProgramIdentifier programIdentifier = brickRED.getProgramIdentifier(currentProgram.itemObjectId, session.sessionId); checkError(programIdentifier.errorCode); BrickRED.StringLength programIdentifierLength = brickRED.getStringLength(programIdentifier.identifierStringId); checkError(programIdentifierLength.errorCode); // Request all Blocks with 63-Bytes String currentProgramName = ""; while (currentProgramName.length() < programIdentifierLength.length) { BrickRED.StringChunk stringPart = brickRED.getStringChunk(programIdentifier.identifierStringId, currentProgramName.length()); checkError(stringPart.errorCode); currentProgramName += stringPart.buffer; } checkError(brickRED.releaseObject(programIdentifier.identifierStringId, session.sessionId)); System.out.println("Found Programm: " + currentProgramName); // Program found? if(currentProgramName.equalsIgnoreCase(programName)) { checkError(brickRED.startProgram(currentProgram.itemObjectId)); System.out.println("Program started: " + currentProgramName); startet = true; } checkError(brickRED.releaseObject(currentProgram.itemObjectId, session.sessionId)); } checkError(brickRED.releaseObject(listPrograms.programsListId, session.sessionId)); checkError(brickRED.expireSession(session.sessionId)); return startet; } private static void checkError(int errorCode) { if(errorCode != 0) throw new RuntimeException("RED-Brick responsed folowing Error " + errorCode + "-" + ERROR_CODES.get(errorCode)); } }
  6. Wie starte ich ein Java-Programm auf dem RED, wenn ich keinen Rechner mit BrickV am Laufen habe habe? Gibt's da ne technische Möglichkeit? Ein standardisierter URL-Aufruf wäre z.B. nicht schlecht. Oder geht nur, per SSH zu verbinden und das irgendwie als Befehl abzusenden? (Ich würde das entweder auf dem Handy, lieber aber über IP-Symcon/Homematic über Hausautomation scripten wollen. Dann würde ein Klick auf eine Fernbedienung reichen, weil das ja alles ständig in der Nähe verfügbar ist.)
  7. Vielen Dank zunächst, dass du über das Problem so ausführlich nachgedacht hast ... Ich werde den Wait-Notify-Ansatz mal austesten und berichten.
  8. Hallo Zusammen, mir fehlen aktuell gute Ideen, wie ich von den Hello-World-Beispielen bei den einzelnen Bricks zu einem komplexeren Programm komme, weil mir das bevorzugte asynchrone Eventhandling ständig wild im Programm herumspringt und Multithreading-Fragen aufwirft. Leider habe ich keine Beispiele für komplexere Programme auf den Seiten von TF oder hier im Forum gefunden. Um die Probleme überhaupt diskutieren zu können, hier mal ein konkretes Beispiel: Steuerung einer fiktive Hardware, ein 3-achsiger Roboter-Arm: 2 x Schrittmotoren jeweils am Stepper-Brick für den Arm 1 x ein einfacher Motor am DC-Brick zur Drehung der Bodenplatte Der normale Motor hat eine Art Taktimpuls (z.B. Lichtschranke) zum "mitzählen" von Impulsen am IO16-Bricklet zur Positionserkennung. 1 x Ein Taster am IO16, um einen Bewegungsablauf zu starten. (Es geht mir hier nur um die Programmierung und nicht um die Frage, ob die Hardware sinnvoll aufgebaut ist) Um einfache Bewegungsfolgen laufen zu lassen, brauche ich wohl eine Komfort-Methode in der Form "geheZuPosition(x,y,z)", die erst zurückkehrt, wenn die jeweilige Position vollständig erreicht ist. Darin muss nach Start der drei Motoren auf die folgenden 3 'Events' gewartet werden: Stepper 1 ist angekommen, Stepper 2 ist angekommen, (geht ja Dank der Bricks weitesgehend automatisch) IO16-Zähler hat die richtige Anzahl Impulse gezählt, so das auch die Position erreicht ist, um den DC-Motor abzuschalten. Die einzelnen, kurzen Demo-Codestrecken der Bricks würden nun jeweils "Position-Erreicht"-Listener an die Stepper und ein "Impuls wurde gezählt" Event an das IO16 zu binden, um nicht ständig die Hardware "pollen" zu müssen und damit Last auf den beteiligen Bussen zu sparen. (USB, Wifi etc.) Das IO16 hat nun die Doppelaufgabe -> Zunächst Warten auf Tastendruck / dann Warten auf nächsten Zählimpuls zur Positionsbestimmung und vielleicht weitere Aufgaben. Wie verknüpfe ich nun temporär solche Events dynamisch zu einer größeren Gesamtaufgabe? Ich würde vermutlich 3 globale Variablen PositionX/Y/Z-erreicht einführen (in Java Volatile wegen Multithreading Problematik) und in den asynchronen Event-Listenern nur diesen Status pflegen. Dann könnte ich den Haupt-Thread in der Methode mit Thread.sleep periodisch schlafen legen und von Zeit zu Zeit prüfen, ob alle Variablen true geworden sind, sie für's nächste Mal zurücksetzen und dann die Methode verlassen. Aber ich hätte ggf. einen Zeitverlust bis zum Aufwachend es Main-Threads, auch wenn ich jetzt schon die BUS-Last schone. Vor dem eigentlichen Lauf muss ich ja auch noch auf den Tastendruck warten, der im gleichen Listener vom IO16 behandelt werden könnte, wie das Zählevent, aber auch da ist die Frage, wohin in der Zwischenzeit mit dem Main-Thread. Wenn ich das alles mit statischen Variablen in einer Klasse baue, mag es funktionieren, passt aber so garnicht gut zu meinem persönlichen Anspruch an eleganten und robusten Code ... ;-) Die Erfahrung aus prozeduralen Programmiersprachen mit Nutzung vieler globalen Variablen zeigt, dass man da irgendwann nicht mehr durchblickt, wenn das Projekt wächst, weil immer schlechter vorhersagbar ist, welche Variable zu welchem Zeitpunkt welchen Zustand hat und von wo dieser zuletzt kam. Nun die Fragen an die Profis, wie eine solche Steuerung 'schön' aufgebaut werden könnte. Teilt Ihr solche Logik sinnvoll auf mehrere Klassen auf? Wie vermeidet man die ganzen "globalen" oder sogar statischen Variablen/Zustände, falls möglich? Wie pausiert oder beschäftigt Ihr den Main-Thread, während Ihr auf Events wartet? Nehmt ihr einen großen Listener pro Brick oder viele kleine, die je nach aktueller Aufgabe kurz gebunden und sofort wieder entfernt werden? Ich bin für jeden Denkanstoß dankbar ... ;-)
×
×
  • Neu erstellen...