wtorek, 17 czerwca 2014

FreeCAD: animacja ruchu tłoka i korbowodu sterowana szkicem

Poniżej widoczna jest prosta, sterowana szkicem animacja tłoka i korbowodu. Nie używa ona w ogóle modułu złożeń. Pozycja tłoka oraz pozycja i kąt obrotu korbowodu bazują na pozycji punktów zawartych w pomocniczym szkicu.



Szybka demonstracja

Otwórz plik conrod-piston-anim.fcstd w FreeCAD-zie i wklej do konsoli Pythona następujący skrypt:

import FreeCAD as App, FreeCADGui as Gui, Part, time, sys, math, Draft
from PyQt4 import QtGui,QtCore

class Animation(object):
    def __init__(self):
        App.Console.PrintMessage('init')

        App.ActiveDocument.recompute()

        self.timer = QtCore.QTimer()
        QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.my_update)
        self.timer.start(50)

        self.an = 0.1

    def my_update(self):
        string = '{0}'.format(self.an)
        self.an = self.an + 0.01 if self.an < (2 * math.pi) else 0.0

        angle = math.degrees(self.an)
        App.Console.PrintMessage(str(angle)+" ")
        App.ActiveDocument.getObjectsByLabel("drivingskt")[0].setDatum(5,App.Units.Quantity(str(angle)+' deg'))
        App.ActiveDocument.recompute()
        p1 = App.ActiveDocument.getObjectsByLabel("drivingskt")[0].Shape.Vertexes[0].Point
        p2 = App.ActiveDocument.getObjectsByLabel("drivingskt")[0].Shape.Vertexes[1].Point
        p1t = p1 + App.Vector(0, 37, 0)
        conrodangle = math.degrees(Draft.DraftVecUtils.angle(App.Vector(0, 1, 0),(p1-p2)))
        App.ActiveDocument.getObjectsByLabel("Piston")[0].Placement = App.Placement(p1t,App.Rotation(App.Vector(0, 1, 0), 90))
        App.ActiveDocument.getObjectsByLabel("Conrod")[0].Placement = App.Placement(p2,App.Rotation(App.Vector(0, 0, 1),conrodangle))

    def stop(self):
        self.timer.stop()
       

animation = Animation() 


Powinieneś zobaczyć animację. Możesz ją zatrzymać wpisując:

animation.stop()

Jak to zostało zrobione?

Potrzebne są pliki z modelami korbowodu (conrod) i tłoka (piston):
Otwórz je w FreeCAD-zie i utwórz trzeci, pusty plik. Następnie skopiuj ostatnie cechy z drzew cech tłoka i korbowodu. Wklej je do nowo utworzonego pliku - nazwy cech to odpowiednio "Fusion" i "Pocket002". Potwierdź skopiowanie plików zależnych.

W nowym pliku powinieneś zobaczyć obie części (jak na poniższym zrzucie). Jest kilka drobnych problemów: nie znasz długości korbowodu, pozycji otworu na sworzeń w tłoku, w końcu sam tłok jest obrócony wokół pionowej osi o 90 stopni.
Spróbuj zmienić obrót tłoka regulując wartość "Placement" z karcie Data tab i obserwuj konsolę Pythona. Ustawiając oś obrotu na Y i obracając tłok i 90 stopni powinieneś zobaczyć coś podobnego do:
App.Placement((App.Vector(0, 1, 0),App.Rotation(App.Vector(0, 1, 0), 90))
Pierwszym argumentem jest pozycja tłoka (X, Y, Z), kolejny opisuje oś obrotu (0, 1, 0 to Y), trzecim argumentem jest kąt w stopniach.


Długość korbowodu może zostać zmierzona przy użyciu narzędzi pomiarowych Warsztatu Part. Wybierz dolną ścianę (na stopie) i tworzącą walca otworu na sworzeń.


Jak znaleźć pozycję otworu sworznia w tłoku? Wróć do oryginalnego pliku z tłokiem i poszukaj szkicu użytego do wycięcia otworu lub utworzenia gniazda sworznia.


Zanotuj pozycję szkicu (Sketch004).  Jest on przesunięty -37 mm w kierunku Y. Zauważ, w naszym skrypcie, następującą linię:
p1t = p1 + App.Vector(0, 37, 0)


No koniec, najważniejszy etap, czyli szkic sterujący.Utwórz szkic na płaszczyźnie XY. 


Naszkicuj polilinie jak na powyższym zrzucie (punkt 0, 0 jest środkiem wyimaginowanego wału korbowego, oś pionowa jest osią symetrii cylindra). Zmień więz kąta i obserwuj konsolę Pythona Powinieneś zobaczyć coś takiego:
App.ActiveDocument.Sketch.setDatum(5,App.Units.Quantity('60.000000 deg'))
Zapisz numer więzu (5). Został on użyty w skrypcie w linii:
App.ActiveDocument.getObjectsByLabel("drivingskt")[0].setDatum(5,App.Units.Quantity(str(angle)+' deg'))

Zmień nazwy korbowodu, tłoka i szkicu odpowiednio na Conrod, Piston i drivingskt. Użyjemy wygodnej metody getObjectsByLabel() Ważne: metoda zwraca listę (jeden lub kilka obiektów). Użyj [0] by wybrać pierwszy obiekt, w skrypcie wygląda to następująco:
App.ActiveDocument.getObjectsByLabel("drivingskt")[0].setDatum(5,App.Units.Quantity(str(angle)+' deg'))
App.ActiveDocument.getObjectsByLabel("Piston")[0].Placement = App.Placement(p1t,App.Rotation(App.Vector(0, 1, 0), 90))
App.ActiveDocument.getObjectsByLabel("Conrod")[0].Placement = App.Placement(p2,App.Rotation(App.Vector(0, 0, 1),conrodangle))

Musisz znać nazwy wierzchołków szkicu. Po prostu najedź kursorem na interesujący wierzchołek i obserwuj pasek stanu. Powinieneś zobaczyć jago nazwę i pozycję.

Pozycja tłoka bazuje na górnym wierzchołku (Vertex1 w moim przykładzie - Vertexes[0], bo lista liczona jest od zera):
        p1 = App.ActiveDocument.getObjectsByLabel("drivingskt")[0].Shape.Vertexes[0].Point
        p1t = p1 + App.Vector(0, 37, 0)

        App.ActiveDocument.getObjectsByLabel("Piston")[0].Placement = App.Placement(p1t,App.Rotation(App.Vector(0, 1, 0), 90))

Pozycja korbowodu bazuje na środkowym wierzchołku (Vertex2, Vertexes[1]):
        p2 = App.ActiveDocument.getObjectsByLabel("drivingskt")[0].Shape.Vertexes[1].Point
        App.ActiveDocument.getObjectsByLabel("Conrod")[0].Placement = App.Placement(p2,App.Rotation(App.Vector(0, 0, 1),conrodangle))


Kąt obrotu korbowodu jest obliczony z wykorzystaniem pozycji wierzchołków (Vertex1 i Vertex2) oraz wektora (0, 1, 0)  (kierunku Y):
        p1 = App.ActiveDocument.getObjectsByLabel("drivingskt")[0].Shape.Vertexes[0].Point
        p2 = App.ActiveDocument.
getObjectsByLabel("drivingskt")[0].Shape.Vertexes[1].Point
        conrodangle = math.degrees(Draft.DraftVecUtils.angle(App.Vector(0, 1, 0),(p1-p2)))
        App.ActiveDocument.getObjectsByLabel("Conrod")[0].Placement = App.Placement(p2,App.Rotation(App.Vector(0, 0, 1),conrodangle))



Jak jest zmieniany kąt w szkicu?
Użyłem regulatora czasowego (timera) z bibliotek Qt. Limit czasu został ustawiony na 50 ms:
self.timer.start(50)

Po 50 ms zostaje wywołane my_update:
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.my_update)

self.an i angle jest kątem obrotu wału odpowiednio w radianach (self.an wynosi 0,01 do 6,28 z krokiem 0,01) i stopniach:

        self.an = self.an + 0.01 if self.an < (2 * math.pi) else 0.0
        angle = math.degrees(self.an)



To wszystko. Baw się dobrze i zaglądaj na forum FreeCAD-a i społeczność Google+!

Inspiracja
FreeCAD Python API

FreeCAD
Version: 0.14.3653 (Git)