1Make a spider robot in SolidWorks and simulate it {#tutorial_pychrono_demo_spider_robot}
2==========================
3
4This demo is about the simulation of a crawling spider robot with six legs,
5where we control the motion of the legs with 18 actuators.
6
7![](http://projectchrono.org/assets/manual/Tutorial_spider_robot.jpg)
8
9In deail, one performs the following steps:
10- Use SolidWorks to make a 3D CAD model of the crawling robot,
11- export it as a .pyfile using the Chrono::SolidWorks add-in; ex. use the name **spider\_robot.py**
12- create a Python program, ex. use the name **demo\_spider.py**, using the functions of [PyChrono](@ref pychrono_introduction) to load and simulate spider\_robot.py.
13
14For your convenience, the CAD model, the converted **spider\_robot.py** model, and the **demo\_spider.py** program are all available in the following archive:
15
16
17[spider_robot.zip](http://projectchrono.org/assets/downloads/spider_robot.zip).
18
19
20The following is the complete listing of **demo\_spider.py**  (it must stay in the same directory where you exported your CAD model with the name **spider\_robot.py**)
21
22Note how we used  **mybody = mysystem.SearchBody('...')**; and  **mymarker = mybody.SearchMarker('...');** to retrieve object pointers from their names in the 3D CAD model. Also note that a part that shows as *M-410iB-300 -1/ArmBase\<1\>* in the GUI of SolidWorks, becomes *M-410iB-300 -1/ArmBase-1* for the Python side; i.e. the \<N\> suffix becomes -N.
23
24Finally, note how we used ChFunction objects to build some basic loop motions for the actuators, in prescribed rotation mode.
25
26
27<span style="color:red;font-weight:bold">ATTENTION!</span> The source code listed below may not be compatible with your current version of PyChrono and may need to be slightly adjusted to reflect any recent API changes.
28
29~~~~~~~~~~~~~{.py}
30
31
32
33import os
34import math
35import pychrono as chrono
36import pychrono.postprocess as postprocess
37import pychrono.irrlicht as chronoirr
38
39# class to use ChLinkMotorRotationAngle given the markers from the CAD
40class SpiderRobotMotor(chrono.ChLinkMotorRotationAngle):
41    def __init__(self):
42        super().__init__()
43        self.bodylist = []
44    def Initialize(self, mark1, mark2):
45        body1 = mark1.GetBody()
46        body2 = mark2.GetBody()
47        self.bodylist.append([body1, body2])
48        frame = mark1.GetAbsFrame()
49        super().Initialize(body1, body2, frame)
50    def Set_rot_funct(self, rotfun):
51        super().SetAngleFunction(rotfun)
52
53print ("Load a model exported by SolidWorks")
54
55
56
57# ---------------------------------------------------------------------
58#
59#  Create the simulation system and add items
60#
61
62mysystem      = chrono.ChSystemNSC()
63chrono.ChCollisionModel.SetDefaultSuggestedEnvelope(0.05)
64chrono.ChCollisionModel.SetDefaultSuggestedMargin(0.05)
65
66parts = chrono.ImportSolidWorksSystem('./spider_robot')
67
68for ib in parts:
69    mysystem.Add(ib)
70
71# Retrieve objects from their name as saved from the SolidWorks interface
72# (look the spider_robot.py file to guess them, or look their name in SW)
73
74bbody    = mysystem.SearchBody('Part3^SPIDER_ROBOT-1')
75bbody.SetBodyFixed(False)
76b1base    = mysystem.SearchBody('M-410iB-300 -1/ArmBase-1')
77b1turret  = mysystem.SearchBody('M-410iB-300 -1/M-410iB-300-02-1')
78b1bicept  = mysystem.SearchBody('M-410iB-300 -1/M-410iB-300-03-1')
79b1forearm = mysystem.SearchBody('M-410iB-300 -1/M-410iB-300-06-1')
80m1_1B = b1base.   SearchMarker('marker_M1_B')
81m1_1A = b1turret. SearchMarker('marker_M1_A')
82m1_2B = b1turret. SearchMarker('marker_M2_B')
83m1_2A = b1bicept. SearchMarker('marker_M2_A')
84m1_3B = b1bicept. SearchMarker('marker_M3_B')
85m1_3A = b1forearm.SearchMarker('marker_M3_A')
86b2base    = mysystem.SearchBody('M-410iB-300 -2/ArmBase-1')
87b2turret  = mysystem.SearchBody('M-410iB-300 -2/M-410iB-300-02-1')
88b2bicept  = mysystem.SearchBody('M-410iB-300 -2/M-410iB-300-03-1')
89b2forearm = mysystem.SearchBody('M-410iB-300 -2/M-410iB-300-06-1')
90m2_1B = b2base.   SearchMarker('marker_M1_B')
91m2_1A = b2turret. SearchMarker('marker_M1_A')
92m2_2B = b2turret. SearchMarker('marker_M2_B')
93m2_2A = b2bicept. SearchMarker('marker_M2_A')
94m2_3B = b2bicept. SearchMarker('marker_M3_B')
95m2_3A = b2forearm.SearchMarker('marker_M3_A')
96b3base    = mysystem.SearchBody('M-410iB-300 -3/ArmBase-1')
97b3turret  = mysystem.SearchBody('M-410iB-300 -3/M-410iB-300-02-1')
98b3bicept  = mysystem.SearchBody('M-410iB-300 -3/M-410iB-300-03-1')
99b3forearm = mysystem.SearchBody('M-410iB-300 -3/M-410iB-300-06-1')
100m3_1B = b3base.   SearchMarker('marker_M1_B')
101m3_1A = b3turret. SearchMarker('marker_M1_A')
102m3_2B = b3turret. SearchMarker('marker_M2_B')
103m3_2A = b3bicept. SearchMarker('marker_M2_A')
104m3_3B = b3bicept. SearchMarker('marker_M3_B')
105m3_3A = b3forearm.SearchMarker('marker_M3_A')
106b7base    = mysystem.SearchBody('M-410iB-300 -7/ArmBase-1')
107b7turret  = mysystem.SearchBody('M-410iB-300 -7/M-410iB-300-02-1')
108b7bicept  = mysystem.SearchBody('M-410iB-300 -7/M-410iB-300-03-1')
109b7forearm = mysystem.SearchBody('M-410iB-300 -7/M-410iB-300-06-1')
110m7_1B = b7base.   SearchMarker('marker_M1_B')
111m7_1A = b7turret. SearchMarker('marker_M1_A')
112m7_2B = b7turret. SearchMarker('marker_M2_B')
113m7_2A = b7bicept. SearchMarker('marker_M2_A')
114m7_3B = b7bicept. SearchMarker('marker_M3_B')
115m7_3A = b7forearm.SearchMarker('marker_M3_A')
116b8base    = mysystem.SearchBody('M-410iB-300 -8/ArmBase-1')
117b8turret  = mysystem.SearchBody('M-410iB-300 -8/M-410iB-300-02-1')
118b8bicept  = mysystem.SearchBody('M-410iB-300 -8/M-410iB-300-03-1')
119b8forearm = mysystem.SearchBody('M-410iB-300 -8/M-410iB-300-06-1')
120m8_1B = b8base.   SearchMarker('marker_M1_B')
121m8_1A = b8turret. SearchMarker('marker_M1_A')
122m8_2B = b8turret. SearchMarker('marker_M2_B')
123m8_2A = b8bicept. SearchMarker('marker_M2_A')
124m8_3B = b8bicept. SearchMarker('marker_M3_B')
125m8_3A = b8forearm.SearchMarker('marker_M3_A')
126b9base    = mysystem.SearchBody('M-410iB-300 -9/ArmBase-1')
127b9turret  = mysystem.SearchBody('M-410iB-300 -9/M-410iB-300-02-1')
128b9bicept  = mysystem.SearchBody('M-410iB-300 -9/M-410iB-300-03-1')
129b9forearm = mysystem.SearchBody('M-410iB-300 -9/M-410iB-300-06-1')
130m9_1B = b9base.   SearchMarker('marker_M1_B')
131m9_1A = b9turret. SearchMarker('marker_M1_A')
132m9_2B = b9turret. SearchMarker('marker_M2_B')
133m9_2A = b9bicept. SearchMarker('marker_M2_A')
134m9_3B = b9bicept. SearchMarker('marker_M3_B')
135m9_3A = b9forearm.SearchMarker('marker_M3_A')
136
137
138
139period = 2
140mfunc_sineS   = chrono.ChFunction_Sine(0, 1.0/period,  0.2)  # phase, frequency, amplitude
141mfunc_swingSa = chrono.ChFunction_Repeat()
142mfunc_swingSa.Set_fa(mfunc_sineS)
143mfunc_swingSa.Set_window_length(period)
144mfunc_swingSa.Set_window_start(0)
145mfunc_swingSb = chrono.ChFunction_Repeat()
146mfunc_swingSb.Set_fa(mfunc_sineS)
147mfunc_swingSb.Set_window_length(period)
148mfunc_swingSb.Set_window_start(period/2.0)
149mfunc_sineD   = chrono.ChFunction_Sine(0, 1.0/period, -0.2)  # phase, frequency, amplitude
150mfunc_swingDb = chrono.ChFunction_Repeat()
151mfunc_swingDb.Set_fa(mfunc_sineD)
152mfunc_swingDb.Set_window_length(period)
153mfunc_swingDb.Set_window_start(period/2.0)
154mfunc_swingDa = chrono.ChFunction_Repeat()
155mfunc_swingDa.Set_fa(mfunc_sineD)
156mfunc_swingDa.Set_window_length(period)
157mfunc_swingDa.Set_window_start(0)
158
159
160mfunc_sigma  = chrono.ChFunction_Sigma()
161mfunc_sigma.Set_amp(-0.2)
162mfunc_sigma.Set_end(0.5)
163mfunc_const  = chrono.ChFunction_Const()
164mfunc_sigmb  = chrono.ChFunction_Sigma()
165mfunc_sigmb.Set_amp(0.2)
166mfunc_sigmb.Set_end(0.5)
167mfunc_seq    = chrono.ChFunction_Sequence()
168mfunc_seq.InsertFunct(mfunc_sigma, 0.5, 1, True) # fx, duration, weight, C0 continuity
169mfunc_seq.InsertFunct(mfunc_const, 1.0, 1, True) # fx, duration, weight, C0 continuity
170mfunc_seq.InsertFunct(mfunc_sigmb, 0.5, 1, True) # fx, duration, weight, C0 continuity
171mfunc_updownA = chrono.ChFunction_Repeat()
172mfunc_updownA.Set_fa(mfunc_seq)
173mfunc_updownA.Set_window_length(period)
174mfunc_updownB = chrono.ChFunction_Repeat()
175mfunc_updownB.Set_fa(mfunc_seq)
176mfunc_updownB.Set_window_length(period)
177mfunc_updownB.Set_window_phase(period/2.0)
178
179# Add actuators to Leg n.1
180
181motor1_1 = SpiderRobotMotor()
182motor1_1.Initialize(m1_1A, m1_1B)
183motor1_1.Set_rot_funct(mfunc_swingSa)
184mysystem.Add(motor1_1)
185
186motor1_2 = SpiderRobotMotor()
187motor1_2.Initialize(m1_2A, m1_2B)
188motor1_2.Set_rot_funct(mfunc_updownA)
189mysystem.Add(motor1_2)
190
191motor1_3 = SpiderRobotMotor()
192motor1_3.Initialize(m1_3A, m1_3B)
193motor1_3.Set_rot_funct(mfunc_const)
194mysystem.Add(motor1_3)
195
196# Add actuators to Leg n.2
197
198motor2_1 = SpiderRobotMotor()
199motor2_1.Initialize(m2_1A, m2_1B)
200motor2_1.Set_rot_funct(mfunc_swingSb)
201mysystem.Add(motor2_1)
202
203motor2_2 = SpiderRobotMotor()
204motor2_2.Initialize(m2_2A, m2_2B)
205motor2_2.Set_rot_funct(mfunc_updownB)
206mysystem.Add(motor2_2)
207
208motor2_3 = SpiderRobotMotor()
209motor2_3.Initialize(m2_3A, m2_3B)
210motor2_3.Set_rot_funct(mfunc_const)
211mysystem.Add(motor2_3)
212
213# Add actuators to Leg n.3
214
215motor3_1 = SpiderRobotMotor()
216motor3_1.Initialize(m3_1A, m3_1B)
217motor3_1.Set_rot_funct(mfunc_swingSa)
218mysystem.Add(motor3_1)
219
220motor3_2 = SpiderRobotMotor()
221motor3_2.Initialize(m3_2A, m3_2B)
222motor3_2.Set_rot_funct(mfunc_updownA)
223mysystem.Add(motor3_2)
224
225motor3_3 = SpiderRobotMotor()
226motor3_3.Initialize(m3_3A, m3_3B)
227motor3_3.Set_rot_funct(mfunc_const)
228mysystem.Add(motor3_3)
229
230# Add actuators to Leg n.9
231
232motor9_1 = SpiderRobotMotor()
233motor9_1.Initialize(m9_1A, m9_1B)
234motor9_1.Set_rot_funct(mfunc_swingDb)
235mysystem.Add(motor9_1)
236
237motor9_2 = SpiderRobotMotor()
238motor9_2.Initialize(m9_2A, m9_2B)
239motor9_2.Set_rot_funct(mfunc_updownB)
240mysystem.Add(motor9_2)
241
242motor9_3 = SpiderRobotMotor()
243motor9_3.Initialize(m9_3A, m9_3B)
244motor9_3.Set_rot_funct(mfunc_const)
245mysystem.Add(motor9_3)
246
247# Add actuators to Leg n.8
248
249motor8_1 = SpiderRobotMotor()
250motor8_1.Initialize(m8_1A, m8_1B)
251motor8_1.Set_rot_funct(mfunc_swingDa)
252mysystem.Add(motor8_1)
253
254motor8_2 = SpiderRobotMotor()
255motor8_2.Initialize(m8_2A, m8_2B)
256motor8_2.Set_rot_funct(mfunc_updownA)
257mysystem.Add(motor8_2)
258
259motor8_3 = SpiderRobotMotor()
260motor8_3.Initialize(m8_3A, m8_3B)
261motor8_3.Set_rot_funct(mfunc_const)
262mysystem.Add(motor8_3)
263
264# Add actuators to Leg n.7
265
266motor7_1 = SpiderRobotMotor()
267motor7_1.Initialize(m7_1A, m7_1B)
268motor7_1.Set_rot_funct(mfunc_swingDb)
269mysystem.Add(motor7_1)
270
271motor7_2 = SpiderRobotMotor()
272motor7_2.Initialize(m7_2A, m7_2B)
273motor7_2.Set_rot_funct(mfunc_updownB)
274mysystem.Add(motor7_2)
275
276motor7_3 = SpiderRobotMotor()
277motor7_3.Initialize(m7_3A, m7_3B)
278motor7_3.Set_rot_funct(mfunc_const)
279mysystem.Add(motor7_3)
280
281#
282# Create a floor
283
284mfloor = chrono.ChBody()
285mfloor.SetBodyFixed(True)
286mfloor.GetCollisionModel().ClearModel()
287mymat = chrono.ChMaterialSurfaceNSC()
288mymat.SetRestitution(0.0)
289mfloor.GetCollisionModel().AddBox(mymat, 10,0.5,10, chrono.ChVectorD(0,0.8,0))
290mfloor.GetCollisionModel().BuildModel()
291mfloor.SetCollide(True)
292mysystem.Add(mfloor)
293
294mfloorshape = chrono.ChBoxShape()
295mfloorshape.GetBoxGeometry().Size = chrono.ChVectorD(10,0.5,10)
296mfloorshape.GetBoxGeometry().Pos  = chrono.ChVectorD(0,0.8,0)
297mfloor.AddAsset(mfloorshape)
298
299mfloorcolor = chrono.ChColorAsset(0.2,0.2,0.2)
300mfloor.AddAsset(mfloorcolor)
301
302# ---------------------------------------------------------------------
303#
304#  Create an Irrlicht application to visualize the system
305#
306
307myapplication = chronoirr.ChIrrApp(mysystem, 'Test', chronoirr.dimension2du(1280,720))
308
309myapplication.AddTypicalSky('./data/skybox/')
310myapplication.AddTypicalCamera(chronoirr.vector3df(2.8,2.6,2.8),chronoirr.vector3df(0.0,2.6,0.0))
311myapplication.AddTypicalLights()
312myapplication.AddLightWithShadow(chronoirr.vector3df(10,20,10),chronoirr.vector3df(0,2.6,0), 10 ,10,40, 60, 512)
313
314            # ==IMPORTANT!== Use this function for adding a ChIrrNodeAsset to all items
315			# in the system. These ChIrrNodeAsset assets are 'proxies' to the Irrlicht meshes.
316			# If you need a finer control on which item really needs a visualization proxy in
317			# Irrlicht, just use application.AssetBind(myitem) on a per-item basis.
318
319myapplication.AssetBindAll()
320
321			# ==IMPORTANT!== Use this function for 'converting' into Irrlicht meshes the assets
322			# that you added to the bodies into 3D shapes, they can be visualized by Irrlicht!
323
324myapplication.AssetUpdateAll()
325
326			# ==IMPORTANT!== Use this function for enabling cast soft shadows
327
328myapplication.AddShadowAll()
329
330# ---------------------------------------------------------------------
331#
332#  Run the simulation
333#
334solver = chrono.ChSolverBB()
335solver.SetMaxIterations(200)
336mysystem.SetSolver(solver)
337myapplication.SetTimestep(0.001)
338
339
340while(myapplication.GetDevice().run()):
341    myapplication.BeginScene()
342    myapplication.DrawAll()
343    myapplication.DoStep()
344    myapplication.EndScene()
345
346~~~~~~~~~~~~~
347