Actors有時也會組合在一起形成層次結構,當其中的某個Actor運動時,會影響到其他Actor的位置。例如,一個機械手臂可能由上臂、前臂、手腕和末端等部分通過關節連接起來。當上臂繞着肩關節旋轉時,我們希望的是其他部分也會跟着運動。這種行為的實現就要用到Assembly,vtkAssembly是vtkActor的子類,它在構建機器人模型里非常有用。對串聯機器人或串並聯機器人來說,機構中存在着許多運動鏈,當前連桿的位置與姿態與它的父節點有關,父節點轉動一定的角度,子節點也必須轉動,否則模型就會斷開。
可以類比VREP中的三連桿機構,左側的層次結構圖中可以看到這樣一條父子關系鏈:J1→L1→J2→L2→J3→L3。即基座關節J1可以看成運動鏈的根節點,轉動J1剩下的兩根連桿L2和L3也會同樣旋轉。
下面我們在Python中實現用鍵盤控制三連桿機構的運動。首先在SolidWorks中繪制一個長度為100mm的連桿,然后創建裝配體,依次將3個連桿首尾相連。按照之前的方法將裝配體導出為3個STL模型文件。使用VTK的vtkSTLReader類讀入STL文件,並編寫事件處理的類處理鍵盤事件:
#!/usr/bin/env python import vtk import math from vtk.util.colors import * filenames = ["link-1.stl","link-2.stl","link-3.stl"] dt = 1.0 # degree step in rotation renWin = vtk.vtkRenderWindow() actor = list() # the list of links joint1 = vtk.vtkAssembly() joint2 = vtk.vtkAssembly() joint3 = vtk.vtkAssembly() # Customize vtkInteractorStyleTrackballCamera class MyInteractor(vtk.vtkInteractorStyleTrackballCamera): def __init__(self,parent=None): self.AddObserver("CharEvent",self.OnCharEvent) self.AddObserver("KeyPressEvent",self.OnKeyPressEvent) def OnCharEvent(self,obj,event): pass def OnKeyPressEvent(self,obj,event): global angle # Get the compound key strokes for the event key = self.GetInteractor().GetKeySym()
# Handle an arrow key if(key == "Left"): joint1.RotateY(-dt) if(key == "Right"): joint1.RotateY(dt) if(key == "Up"): joint2.RotateY(-dt) if(key == "Down"): joint2.RotateY(dt) if(key == "a"): joint3.RotateY(-dt) if(key == "d"): joint3.RotateY(dt) # Ask each renderer owned by this RenderWindow to render its image and synchronize this process renWin.Render() return def LoadSTL(filename): reader = vtk.vtkSTLReader() reader.SetFileName(filename) mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(reader.GetOutputPort()) actor = vtk.vtkLODActor() actor.SetMapper(mapper) return actor def CreateScene(): # Create a rendering window and renderer ren = vtk.vtkRenderer() renWin.AddRenderer(ren) # Create a renderwindowinteractor iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) style = MyInteractor() style.SetDefaultRenderer(ren) iren.SetInteractorStyle(style) for id, file in enumerate(filenames): actor.append(LoadSTL(file)) r = vtk.vtkMath.Random(.4, 1.0) g = vtk.vtkMath.Random(.4, 1.0) b = vtk.vtkMath.Random(.4, 1.0) actor[id].GetProperty().SetDiffuseColor(r, g, b) actor[id].GetProperty().SetDiffuse(.8) actor[id].GetProperty().SetSpecular(.5) actor[id].GetProperty().SetSpecularColor(1.0,1.0,1.0) actor[id].GetProperty().SetSpecularPower(30.0) joint1.AddPart(actor[0]) joint1.AddPart(joint2) joint2.AddPart(actor[1]) joint2.AddPart(joint3) joint3.AddPart(actor[2]) joint2.SetOrigin(100, 0, 0) # initial elbow joint position joint3.SetOrigin(200, 0, 0) # initial wrist joint position ren.AddActor(joint1)
# Set background color ren.GradientBackgroundOn() ren.SetBackground(.1, .1, .1) ren.SetBackground2(0.8,0.8,0.8) # Set window size renWin.SetSize(600, 600) # Enable user interface interactor iren.Initialize() iren.Start() if __name__ == "__main__": CreateScene()
運行結果如下圖所示。按鍵盤上的← →鍵可以控制連桿1,按↑ ↓鍵可以控制連桿2,按a、d鍵可以控制連桿3。在添加裝配體后能保證旋轉單個關節時其后面的子裝配體也能跟着一起旋轉。
參考: