1Load a STEP file and simulate a robot (demo_CAS_robot.cpp)  {#tutorial_demo_robot}
2==========================
3
4
5Tutorial that teaches how to use the
6[CASCADE module](group__cascade__module.html)
7to load a 6-DOF robot saved in a STEP file as an assembly, exported from a CAD model.
8
9
10This is an advanced tutorial that shows how to load complex 3D models that have been saved in
11[STEP file format](http://en.wikipedia.org/wiki/ISO_10303) from professional 3D CAD software.
12
13Most high-end 3D CAD software can save assemblies and parts in STEP format.
14Among the most used CAD software, we cite
15[CATIA](http://www.3ds.com/products/catia/welcome/),
16[SolidEdge](http://www.solidedge.com),
17[SolidWorks](http://www.solidworks.com/),
18[PTC Pro/E](http://www.ptc.com), etc.
19The following tutorial is based on **SolidEdge**, but it can be adapted to other CADs with minor modifications.
20
21# Prepare a STEP file
22
23The CASCADE module is able to directly parse sub-assemblies and sub-parts that have been saved into a single STEP file. However, it is better to prepare the assembly with certain guidelines, before saving it: noticeably, we will put some 'auxiliary' objects in the assembly (the markers) that we will use from the C++ programming side in order to retrieve useful coordinates for building the constraints between the parts. This process is explained in the folowing example.
24
25<div class="ce-info">
26Creating a demo mechanism (a car, a robot, etc.) might take hours. To make things simplier, we load a ready-to-use model that can be downloaded from the website of a manufaturer of industrial robots, see [download page](http://www.abb.com/product/seitp327/5356453900282c5cc1256efc0028d55d.aspx?productLanguage=us&country=00&tabKey=7 ) from the [ABB](www.abb.com) website. We downloaded the 3D model for the IRB 7600 robot: by the way it is already in STEP format, so it could be loaded directly by the CASCADE unit, but we prefer to mofify it in SolidEdge and save it again.
27</div>
28
29- Start SolidEdge (we use the v18 version in this example)
30
31- Menu File / Open...
32
33- Choose the STEP (.stp or .step) file of the robot, as downloaded from the ABB site.
34
35- In the 'New' window, in the 'General' tab, select 'Normal.asm' to let SolidEdge create an assembly from the STEP file
36
37- Press OK. After the conversion, SolidEdge created the assembly. Look into the directory of your STEP file: SolidEdge created its .asm and many .part files. The Assembly PathFinder panel, to the right, shows all the parts in the assembly:
38
39  ![](http://projectchrono.org/assets/manual/Tutorial_robot_01.jpg)
40
41- Note that the assembly is made of many parts. Maybe that there is not a one-to-one correspondence from rigid bodies for our simulation, and CAD parts, so we want to organize N sub-assemblies, that represent our N rigid bodies in the simulation. That is, it would be nice if each part stays in a separate sub-assebly that represents a 'rigid body', and such subassemblies can optionally contain some auxiliary objects (we call them 'markers') that can be used later on the C++ side to find the position of the joints.
42
43- To make the sub assembles:
44	- Select the 'Parts library' panel,
45	- press button 'Create in Place' to open the create window,
46	- set 'Normal.asm' as Template
47	- set 'Base' (or 'Forearm', or other meaningful name) in 'New file name',
48	- browse to your directory where you have all other assembly files, in 'New file location',
49	- menu File / Close and return, to go back to general assembly.
50	- Repeat the last steps to create the other subassemblies, named for example 'Bicep', 'Forearm', 'Wrist', etc.
51
52- The created subassemblies are still empty. So we must move the imported parts into them. Drag and drop a part from parent assembly to a child asembly does not work in SolidEdge v.18, yet a simple way to do this is to
53	- select the part in the parent assembly,
54	- press Ctrl+C to copy,
55	- then select the sublevel in the Assembly PathFinder,
56	- use 'Edit' from popup-menu,
57	- press Ctrl-V to paste it,
58	- then go back to parent assembly with menu 'File / Close and return'.
59
60- Repeat this until you have all the parts in their separate subassemblies. Some subassembly might have multiple parts. Look our example:
61
62  ![](http://projectchrono.org/assets/manual/Tutorial_robot_02.jpg)
63
64- Now we add an auxiliary part in all subassemblies, to represent the coordinates where you want the constraints (links, motors, ..) to be created using C++ functions. These are like 'placeholders'. To do so, we create a 'marker.par' part, such as the one in the following figure:
65
66  ![](http://projectchrono.org/assets/manual/Tutorial_robot_03.jpg)
67  [marker.par](http://projectchrono.org/assets/manual/marker.par)
68
69- We insert this marker part in all subassemblies, properly aligned to all the joints:
70
71  ![](http://projectchrono.org/assets/manual/Tutorial_robot_04.jpg)
72
73- At the end, the Assembly PathFinder panel should show something like the following:
74
75  ![](http://projectchrono.org/assets/manual/Tutorial_robot_05.jpg)
76
77- Select the base assembly, use the menu File / Save as.. and choose STEP as file format, then save the entire assembly.
78
79- Quit the SolidEdge software.
80
81
82# Write C++ code to load the model
83
84The key of the remaining process is the functionality of the ChCascadeDoc class. Such class has the functionality of loading sub-assemblies from a STEP file by using the function `mydoc.GetNamedShape(...)` that takes, as argument, the ASCII name of the subassembly (or sub part).
85
86A small inconvenience happens here: because of a SolidEdge-specific issue, the names of the subassemblies in the STEP file are not always the same names that you read in the Assembly PAthFinder window. In detail, all the names of the assemblies are automatically translated to `Assem1`, `Assem2`, etc., whereas you would expect the names of the assemblies that you created, such as `Base`, `Turret`, etc.
87
88A workaround to this inconvenience is the following: you use the `mydoc.Dump(GetLog())` function to print the hierarchy on the console and take note of the STEP names on a piece of paper (or just use the demo_converter.exe to show that hierarchy), you will see something like:
89
90~~~{.txt}
91 -Name :Assem10 (root)
92      pos at: 0 0 0 (absolute)
93      pos at: 0 0 0 (.Location)
94  -Name :Assem8
95        pos at: 0 0 0 (absolute)
96        pos at: 0 0 0 (.Location)
97    -Name :IRB7600_23_500_m2000_rev1_01-1
98          pos at: 0 0 0 (absolute)
99          pos at: 0 0 0 (.Location)
100    -Name :marker
101          pos at: 2.29901e-035 -2.99071e-036 0.2185 (absol
102          pos at: 2.29901e-035 -2.99071e-036 0.2185 (.Loca
103  -Name :Assem4
104        pos at: 0 0 0 (absolute)
105        pos at: 0 0 0 (.Location)
106    -Name :IRB7600_23_500_m2000_rev1_01-2
107          pos at: 0 0 0 (absolute)
108          pos at: 0 0 0 (.Location)
109    -Name :marker
110          pos at: 3.88578e-015 -2.66454e-015 0.2135 (absol
111          pos at: 3.88578e-015 -2.66454e-015 0.2135 (.Loca
112    -Name :marker
113          pos at: 0.41 -0.049 0.78 (absolute)
114          pos at: 0.41 -0.049 0.78 (.Location)
115    -Name :marker
116          pos at: -0.38 -0.03 0.6545 (absolute)
117          pos at: -0.38 -0.03 0.6545 (.Location)
118  -Name :Assem1
119          .... etc. etc. .... ........
120~~~
121
122From the example above, you see that `Base` has become `Assem8`, `Turret` has become `Assem4`, and so on. (luckily enough, SolidEdge did not change the name of the parts, only the assembly names were changed). Take note of this on a sheet of paper.
123
124Now, let's develop the C++ program that loads the robot model and simulates it.
125
126First of all, include the needed libraries (note the unit_CASCADE/... headers) and use the proper namespaces:
127
128~~~{.cpp}
129#include "physics/CHapidll.h"
130#include "core/CHrealtimeStep.h"
131#include "irrlicht_interface/CHirrAppInterface.h"
132#include "irrlicht_interface/CHbodySceneNodeTools.h"
133#include "unit_CASCADE/CHcascadeDoc.h"
134#include "unit_CASCADE/CHCascadeMeshTools.h"
135#include "unit_CASCADE/CHirrCascadeMeshTools.h"
136#include "unit_CASCADE/CHirrCascade.h"
137#include "irrlicht_interface/CHbodySceneNode.h"
138#include <irrlicht.h>
139
140
141// Use the namespace of Chrono
142using namespace chrono;
143
144// Use the main namespaces of Irlicht
145using namespace irr;
146using namespace core;
147using namespace scene;
148using namespace video;
149using namespace io;
150using namespace gui;
151
152// Use the namespace with OpenCascade stuff
153using namespace cascade;
154~~~
155
156
157Here is the program (a simple demo where the robot is created from the STEP file, constraints are added, and the robot simulation is displayed while moving on a simple trajectory).
158
159
160~~~{.cpp}
161int main(int argc, char* argv[])
162{
163
164	ChGlobals* GLOBAL_Vars = DLL_CreateGlobals();
165
166	// 1- Create a ChronoENGINE physical system: all bodies and constraints
167	//    will be handled by this ChSystem object.
168	ChSystem my_system;
169
170	// Create the Irrlicht visualization (open the Irrlicht device,
171	// bind a simple user interface, etc. etc.)
172	ChIrrAppInterface application(&my_system, L"Load a robot model from STEP file",core::dimension2d<u32>(800,600),false, true, video::EDT_OPENGL);
173
174	// Easy shortcuts to add logo, camera, lights and sky in Irrlicht scene:
175	//ChIrrWizard::add_typical_Logo(application.GetDevice());
176	ChIrrWizard::add_typical_Sky(application.GetDevice());
177	ChIrrWizard::add_typical_Lights(application.GetDevice(), core::vector3df(30,100,30), core::vector3df(30,-80,-30),200,130);
178	ChIrrWizard::add_typical_Camera(application.GetDevice(), core::vector3df(0.2,1.6,-3.5));
179
180~~~
181
182Create the ChCascadeDoc, a container that loads the STEP model and manages its subassembles. Also, prepare some pointers for bodies that will be created.
183
184~~~{.cpp}
185	ChCascadeDoc mydoc;
186~~~
187
188
189Also, prepare some pointers for bodies that will be created.
190
191~~~{.cpp}
192	ChBodySceneNodeAuxRef* mrigidBody_base	= 0;
193	ChBodySceneNodeAuxRef* mrigidBody_turret = 0;
194	ChBodySceneNodeAuxRef* mrigidBody_bicep = 0;
195	ChBodySceneNodeAuxRef* mrigidBody_elbow = 0;
196	ChBodySceneNodeAuxRef* mrigidBody_forearm = 0;
197	ChBodySceneNodeAuxRef* mrigidBody_wrist = 0;
198	ChBodySceneNodeAuxRef* mrigidBody_hand = 0;
199	ChBodySceneNodeAuxRef* mrigidBody_cylinder = 0;
200	ChBodySceneNodeAuxRef* mrigidBody_rod = 0;
201~~~
202
203Load the STEP model using this command: (be sure to have the STEP file on the hard disk)
204
205~~~{.cpp}
206	bool load_ok = mydoc.Load_STEP("..\\data\\cascade\\IRB7600_23_500_m2000_rev1_01_decorated.stp");
207~~~
208
209Print the contained shapes, showing the assembly hierarchy:
210
211~~~{.cpp}
212	mydoc.Dump(GetLog());
213
214	ChCollisionModel::SetDefaultSuggestedEnvelope(0.002);
215	ChCollisionModel::SetDefaultSuggestedMargin(0.001);
216
217	// In most CADs the Y axis is horizontal, but we want it vertical.
218	// So define a root transformation for rotating all the imported objects.
219	ChQuaternion<> rotation1;
220	rotation1.Q_from_AngAxis(-CH_C_PI/2, VECT_X); // 1: rotate 90° on X axis
221	ChQuaternion<> rotation2;
222	rotation2.Q_from_AngAxis(CH_C_PI, VECT_Y);	 // 2: rotate 180° on vertical Y axis
223	ChQuaternion<> tot_rotation = rotation2 % rotation1;  // rotate on 1 then on 2, using quaternion product
224	ChFrameMoving<> root_frame( ChVector<>(0,0,0), tot_rotation);
225~~~
226
227
228Retrieve some sub shapes from the loaded model, using the GetNamedShape() function, that can use path/subpath/subsubpath/part syntax and * or ? wldcards, etc.
229Using the / slash is like addressing a Unix directory (in fact the STEP file is organized like a directory with subdirectory, each representing a subassembly).
230
231~~~{.cpp}
232	if (load_ok)
233	{
234
235		TopoDS_Shape shape_base;
236		if (mydoc.GetNamedShape(shape_base, "Assem10/Assem8" ))
237		{
238				// Add the shape to the Irrlicht system, to get also visualization.
239			mrigidBody_base = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
240									&my_system, application.GetSceneManager(),
241									shape_base);
242
243				// The base is fixed to the ground
244			mrigidBody_base->GetBody()->SetBodyFixed(true);
245
246				// Move the body as for global displacement/rotation by pre-transform its coords.
247				// Note, it could be written also as   mrigidBody_base->GetBody() %= root_frame;
248			mrigidBody_base->GetBody()->ConcatenatePreTransformation(root_frame);
249		}
250		else GetLog() << "Warning. Desired object not found in document \n";
251
252
253		TopoDS_Shape shape_turret;
254		if (mydoc.GetNamedShape(shape_turret, "Assem10/Assem4" ))
255		{
256				// Add the shape to the Irrlicht system, to get also visualization.
257			mrigidBody_turret = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
258									&my_system, application.GetSceneManager(),
259									shape_turret);
260
261				// Move the body as for global displacement/rotation
262			mrigidBody_turret->GetBody()->ConcatenatePreTransformation(root_frame);
263		}
264		else GetLog() << "Warning. Desired object not found in document \n";
265
266
267		TopoDS_Shape shape_bicep;
268		if (mydoc.GetNamedShape(shape_bicep, "Assem10/Assem1" ))
269		{
270				// Add the shape to the Irrlicht system, to get also visualization.
271			mrigidBody_bicep = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
272									&my_system, application.GetSceneManager(),
273									shape_bicep);
274
275				// Move the body as for global displacement/rotation
276			mrigidBody_bicep->GetBody()->ConcatenatePreTransformation(root_frame);
277		}
278		else GetLog() << "Warning. Desired object not found in document \n";
279
280
281		TopoDS_Shape shape_elbow;
282		if (mydoc.GetNamedShape(shape_elbow, "Assem10/Assem5" ))
283		{
284				// Add the shape to the Irrlicht system, to get also visualization.
285			mrigidBody_elbow = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
286									&my_system, application.GetSceneManager(),
287									shape_elbow);
288
289				// Move the body as for global displacement/rotation
290			mrigidBody_elbow->GetBody()->ConcatenatePreTransformation(root_frame);
291		}
292		else GetLog() << "Warning. Desired object not found in document \n";
293
294
295		TopoDS_Shape shape_forearm;
296		if (mydoc.GetNamedShape(shape_forearm, "Assem10/Assem7" ))
297		{
298				// Add the shape to the Irrlicht system, to get also visualization.
299			mrigidBody_forearm = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
300									&my_system, application.GetSceneManager(),
301									shape_forearm);
302
303				// Move the body as for global displacement/rotation
304			mrigidBody_forearm->GetBody()->ConcatenatePreTransformation(root_frame);
305		}
306		else GetLog() << "Warning. Desired object not found in document \n";
307
308
309		TopoDS_Shape shape_wrist;
310		if (mydoc.GetNamedShape(shape_wrist, "Assem10/Assem6" ))
311		{
312				// Add the shape to the Irrlicht system, to get also visualization.
313			mrigidBody_wrist = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
314									&my_system, application.GetSceneManager(),
315									shape_wrist);
316
317				// Move the body as for global displacement/rotation
318			mrigidBody_wrist->GetBody()->ConcatenatePreTransformation(root_frame);
319		}
320		else GetLog() << "Warning. Desired object not found in document \n";
321
322
323		TopoDS_Shape shape_hand;
324		if (mydoc.GetNamedShape(shape_hand, "Assem10/Assem9" ))
325		{
326				// Add the shape to the Irrlicht system, to get also visualization.
327			mrigidBody_hand = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
328									&my_system, application.GetSceneManager(),
329									shape_hand);
330
331			//mrigidBody_hand->GetBody()->SetBodyFixed(true);
332
333				// Move the body as for global displacement/rotation
334			mrigidBody_hand->GetBody()->ConcatenatePreTransformation(root_frame);
335		}
336		else GetLog() << "Warning. Desired object not found in document \n";
337
338
339		TopoDS_Shape shape_cylinder;
340		if (mydoc.GetNamedShape(shape_cylinder, "Assem10/Assem3" ))
341		{
342				// Add the shape to the Irrlicht system, to get also visualization.
343			mrigidBody_cylinder = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
344									&my_system, application.GetSceneManager(),
345									shape_cylinder);
346
347				// Move the body as for global displacement/rotation
348			mrigidBody_cylinder->GetBody()->ConcatenatePreTransformation(root_frame);
349		}
350		else GetLog() << "Warning. Desired object not found in document \n";
351
352
353		TopoDS_Shape shape_rod;
354		if (mydoc.GetNamedShape(shape_rod, "Assem10/Assem2" ))
355		{
356				// Add the shape to the Irrlicht system, to get also visualization.
357			mrigidBody_rod = (ChBodySceneNodeAuxRef*)addChBodySceneNode_Cascade_C(
358									&my_system, application.GetSceneManager(),
359									shape_rod);
360
361				// Move the body as for global displacement/rotation
362			mrigidBody_rod->GetBody()->ConcatenatePreTransformation(root_frame);
363		}
364		else GetLog() << "Warning. Desired object not found in document \n";
365
366
367	}
368	else GetLog() << "Warning. Desired STEP file could not be opened/parsed \n";
369
370
371
372	if (!mrigidBody_base ||
373		!mrigidBody_turret ||
374		!mrigidBody_bicep ||
375		!mrigidBody_elbow ||
376		!mrigidBody_forearm ||
377		!mrigidBody_wrist ||
378		!mrigidBody_hand )
379	{
380		DLL_DeleteGlobals();
381		return 0;
382	}
383~~~
384
385Create joints between two parts.
386To understand where is the axis of the joint, we can exploit the fact that in the STEP file that we prepared for this demo, we inserted some objects called 'marker' and we placed them aligned to the shafts, so now we can fetch them and get their position/rotation.
387
388Important! In the STEP file, some subassemblies have multiple instances of the marker, so there could be two or more shapes with the same name **marker**... how to select the desired one? The GetNamedShape() function has a feature for addressing this: you can use the # character followed by a number, so for example Assem10/Assem8/marker#2 means: get the 2nd instance of the shape called "marker" from the subassembly "Assem8" of assembly "Assem10".
389
390~~~{.cpp}
391	TopoDS_Shape shape_marker;
392
393	ChFrame<> frame_marker_base_turret;
394	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem8/marker#1" ))
395		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_base_turret);
396	else GetLog() << "Warning. Desired marker not found in document \n";
397		// Transform the abs coordinates of the marker because everything was rotated/moved by 'root_frame' :
398	frame_marker_base_turret %= root_frame;
399
400	ChSharedPtr<ChLinkLockRevolute>  my_link1(new ChLinkLockRevolute);
401	ChSharedBodyPtr mb1 = mrigidBody_base->GetBody();
402	ChSharedBodyPtr mb2 = mrigidBody_turret->GetBody();
403	my_link1->Initialize(mb1, mb2, frame_marker_base_turret.GetCoord() );
404	my_system.AddLink(my_link1);
405
406
407	ChFrame<> frame_marker_turret_bicep;
408	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem4/marker#2" ))
409		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_turret_bicep);
410	else GetLog() << "Warning. Desired marker not found in document \n";
411	frame_marker_turret_bicep %= root_frame;
412
413	ChSharedPtr<ChLinkLockRevolute>  my_link2(new ChLinkLockRevolute);
414	mb1 = mrigidBody_turret->GetBody();
415	mb2 = mrigidBody_bicep->GetBody();
416	my_link2->Initialize(mb1, mb2, frame_marker_turret_bicep.GetCoord() );
417	my_system.AddLink(my_link2);
418
419
420	ChFrame<> frame_marker_bicep_elbow;
421	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem1/marker#2" ))
422		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_bicep_elbow);
423	else GetLog() << "Warning. Desired marker not found in document \n";
424	frame_marker_bicep_elbow %= root_frame;
425
426	ChSharedPtr<ChLinkLockRevolute>  my_link3(new ChLinkLockRevolute);
427	mb1 = mrigidBody_bicep->GetBody();
428	mb2 = mrigidBody_elbow->GetBody();
429	my_link3->Initialize(mb1, mb2, frame_marker_bicep_elbow.GetCoord() );
430	my_system.AddLink(my_link3);
431
432
433	ChFrame<> frame_marker_elbow_forearm;
434	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem5/marker#2" ))
435		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_elbow_forearm);
436	else GetLog() << "Warning. Desired marker not found in document \n";
437	frame_marker_elbow_forearm %= root_frame;
438
439	ChSharedPtr<ChLinkLockRevolute>  my_link4(new ChLinkLockRevolute);
440	mb1 = mrigidBody_elbow->GetBody();
441	mb2 = mrigidBody_forearm->GetBody();
442	my_link4->Initialize(mb1, mb2, frame_marker_elbow_forearm.GetCoord() );
443	my_system.AddLink(my_link4);
444
445
446	ChFrame<> frame_marker_forearm_wrist;
447	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem7/marker#2" ))
448		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_forearm_wrist);
449	else GetLog() << "Warning. Desired marker not found in document \n";
450	frame_marker_forearm_wrist %= root_frame;
451
452	ChSharedPtr<ChLinkLockRevolute>  my_link5(new ChLinkLockRevolute);
453	mb1 = mrigidBody_forearm->GetBody();
454	mb2 = mrigidBody_wrist->GetBody();
455	my_link5->Initialize(mb1, mb2, frame_marker_forearm_wrist.GetCoord() );
456	my_system.AddLink(my_link5);
457
458
459	ChFrame<> frame_marker_wrist_hand;
460	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem6/marker#2" ))
461		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_wrist_hand);
462	else GetLog() << "Warning. Desired marker not found in document \n";
463	frame_marker_wrist_hand %= root_frame;
464
465	ChSharedPtr<ChLinkLockRevolute>  my_link6(new ChLinkLockRevolute);
466	mb1 = mrigidBody_wrist->GetBody();
467	mb2 = mrigidBody_hand->GetBody();
468	my_link6->Initialize(mb1, mb2, frame_marker_wrist_hand.GetCoord() );
469	my_system.AddLink(my_link6);
470
471
472	ChFrame<> frame_marker_turret_cylinder;
473	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem4/marker#3" ))
474		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_turret_cylinder);
475	else GetLog() << "Warning. Desired marker not found in document \n";
476	frame_marker_turret_cylinder %= root_frame;
477
478	ChSharedPtr<ChLinkLockRevolute>  my_link7(new ChLinkLockRevolute);
479	mb1 = mrigidBody_turret->GetBody();
480	mb2 = mrigidBody_cylinder->GetBody();
481	my_link7->Initialize(mb1, mb2, frame_marker_turret_cylinder.GetCoord() );
482	my_system.AddLink(my_link7);
483
484
485	ChFrame<> frame_marker_cylinder_rod;
486	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem3/marker#2" ))
487		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_cylinder_rod);
488	else GetLog() << "Warning. Desired marker not found in document \n";
489	frame_marker_cylinder_rod %= root_frame;
490
491	ChSharedPtr<ChLinkLockCylindrical>  my_link8(new ChLinkLockCylindrical);
492	mb1 = mrigidBody_cylinder->GetBody();
493	mb2 = mrigidBody_rod->GetBody();
494	my_link8->Initialize(mb1, mb2, frame_marker_cylinder_rod.GetCoord() );
495	my_system.AddLink(my_link8);
496
497
498	ChFrame<> frame_marker_rod_bicep;
499	if (mydoc.GetNamedShape(shape_marker, "Assem10/Assem2/marker#2" ))
500		ChCascadeDoc::FromCascadeToChrono(shape_marker.Location(), frame_marker_rod_bicep);
501	else GetLog() << "Warning. Desired marker not found in document \n";
502	frame_marker_rod_bicep %= root_frame;
503
504	ChSharedPtr<ChLinkLockCylindrical>  my_link9(new ChLinkLockCylindrical);
505	mb1 = mrigidBody_rod->GetBody();
506	mb2 = mrigidBody_bicep->GetBody();
507	my_link9->Initialize(mb1, mb2, frame_marker_rod_bicep.GetCoord() );
508	my_system.AddLink(my_link9);
509~~~
510
511
512Add a couple of markers for the 'lock' constraint between the hand and the absolute reference: when we will move the marker in absolute reference, the hand will follow it.
513
514This is a very simple way of performing the IK (Inverse Kinematics) of a robot, and it can be used to whatever type of robot, even parallel manipulators or complex kinematic chains, without the need of knowing the analytic expression of the IK.
515
516~~~{.cpp}
517	ChSharedMarkerPtr  my_marker_hand(new ChMarker);
518	ChSharedMarkerPtr  my_marker_move(new ChMarker);
519
520	mrigidBody_hand->GetBody()->AddMarker(my_marker_hand);
521	mrigidBody_base->GetBody()->AddMarker(my_marker_move);
522
523	ChQuaternion<> rot_on_x; rot_on_x.Q_from_AngAxis(CH_C_PI/2, VECT_X);
524	ChFrame<> frame_marker_move = ChFrame<>(VNULL, rot_on_x) >> frame_marker_wrist_hand ;
525
526	my_marker_hand->Impose_Abs_Coord( frame_marker_wrist_hand.GetCoord() );
527	my_marker_move->Impose_Abs_Coord( frame_marker_move.GetCoord() );
528
529	ChSharedPtr<ChLinkLockLock>  my_link_teacher(new ChLinkLockLock);
530	my_link_teacher->Initialize(my_marker_hand, my_marker_move);
531	my_system.AddLink(my_link_teacher);
532~~~
533
534Set motions for Z and Y coordinates of the 'my_link_teacher' marker, so that the hand will follow it. To do so, we create four segments of motion for Z coordinate and four for Y coordinate, we join them with ChFunction_Sequence and we repeat sequence by ChFunction_Repeat
535
536~~~{.cpp}
537    ChFunction_ConstAcc* motlaw_z1 = new ChFunction_ConstAcc();
538	motlaw_z1->Set_h(-0.7);
539	motlaw_z1->Set_end(1);
540	ChFunction_Const*	 motlaw_z2 = new ChFunction_Const();
541	ChFunction_ConstAcc* motlaw_z3 = new ChFunction_ConstAcc();
542	motlaw_z3->Set_h( 0.7);
543	motlaw_z3->Set_end(1);
544	ChFunction_Const*	 motlaw_z4 = new ChFunction_Const();
545	ChFunction_Sequence* motlaw_z_seq = new ChFunction_Sequence();
546	motlaw_z_seq->InsertFunct(motlaw_z1, 1,  1, true);
547	motlaw_z_seq->InsertFunct(motlaw_z2, 1,  1, true);  // true = force c0 continuity, traslating fx
548	motlaw_z_seq->InsertFunct(motlaw_z3, 1,  1, true);
549	motlaw_z_seq->InsertFunct(motlaw_z4, 1,  1, true);
550	ChFunction_Repeat* motlaw_z = new ChFunction_Repeat();
551	motlaw_z->Set_fa(motlaw_z_seq);
552	motlaw_z->Set_window_length(4);
553
554	ChFunction_Const*	 motlaw_y1 = new ChFunction_Const();
555	ChFunction_ConstAcc* motlaw_y2 = new ChFunction_ConstAcc();
556	motlaw_y2->Set_h(-0.6);
557	motlaw_y2->Set_end(1);
558	ChFunction_Const*	 motlaw_y3 = new ChFunction_Const();
559	ChFunction_ConstAcc* motlaw_y4 = new ChFunction_ConstAcc();
560	motlaw_y4->Set_h(0.6);
561	motlaw_y4->Set_end(1);
562	ChFunction_Sequence* motlaw_y_seq = new ChFunction_Sequence();
563	motlaw_y_seq->InsertFunct(motlaw_y1, 1,  1, true);
564	motlaw_y_seq->InsertFunct(motlaw_y2, 1,  1, true);  // true = force c0 continuity, traslating fx
565	motlaw_y_seq->InsertFunct(motlaw_y3, 1,  1, true);
566	motlaw_y_seq->InsertFunct(motlaw_y4, 1,  1, true);
567	ChFunction_Repeat* motlaw_y = new ChFunction_Repeat();
568	motlaw_y->Set_fa(motlaw_y_seq);
569	motlaw_y->Set_window_length(4);
570
571	my_marker_move->SetMotion_Z(motlaw_z);
572	my_marker_move->SetMotion_Y(motlaw_y);
573
574
575	// Create a large cube as a floor.
576
577	ChBodySceneNode* mfloor = (ChBodySceneNode*)addChBodySceneNode_easyBox(
578											&my_system, application.GetSceneManager(),
579											1000.0,
580											ChVector<>(0,-0.6,0),
581											ChQuaternion<>(1,0,0,0),
582											ChVector<>(20,1,20) );
583	mfloor->GetBody()->SetBodyFixed(true);
584	mfloor->GetBody()->SetCollide(true);
585	video::ITexture* cubeMap = application.GetVideoDriver()->getTexture("../data/blu.png");
586	mfloor->setMaterialTexture(0,	cubeMap);
587~~~
588
589
590
591Modify the settings of the solver.
592By default, the solver might not have sufficient precision to keep the robot joints 'mounted'. Expecially, the SOR, SSOR and other fixed point methods cannot simulate well this robot problem because the mass of the last body in the kinematic chain, i.e. the hand, is very low when compared to other bodies, so the convergence of the solver would be bad when 'pulling the hand' as in this 'teaching mode' IK. So switch to a more precise solver; this SOLVER_ITERATIVE_MINRES is fast and precise (although it is not fit for frictional collisions):
593
594~~~{.cpp}
595	my_system.SetLcpSolverType(ChSystem::SOLVER_MINRES);
596~~~
597
598Now, finally, run the loop of the simulator: here are snapshots from the real-time simulator:
599
600![](http://projectchrono.org/assets/manual/Tutorial_robot_06.jpg)
601
602
603# Here is the full source code:
604
605\include demo_CAS_robot.cpp