1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
21 * Created by: Remi Ricard *
22 * (remi.ricard@simlog.com or papaDoc@videotron.ca) *
23 * Creation date: 2007/05/04 *
24 *************************************************************************/
27 This program demonstrates how the Piston joint works.
29 A Piston joint enables the sliding of a body with respect to another body
30 and the 2 bodies are free to rotate about the sliding axis.
32 - The yellow body is fixed to the world.
33 - The yellow body and the blue body are attached by a Piston joint with
34 the axis along the x direction.
35 - The purple object is a geometry obstacle.
36 - The red line is the representation of the prismatic axis
37 - The orange line is the representation of the rotoide axis
38 - The light blue ball is the anchor position
40 N.B. Many command options are available type -h to print them.
44 #include <drawstuff/drawstuff.h>
47 #include "texturepath.h"
50 #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
52 // select correct drawing functions
54 #define dsDrawBox dsDrawBoxD
55 #define dsDrawCylinder dsDrawCylinderD
56 #define dsDrawCapsule dsDrawCapsuleD
57 #define dsDrawSphere dsDrawSphereD
61 const dReal VEL_INC
= 0.01; // Velocity increment
64 const dReal PI
= 3.14159265358979323846264338327950288419716939937510;
65 const dReal BODY1_LENGTH
= 1.5; // Size along the X axis
67 const dReal RADIUS
= 0.2;
68 const dReal AXIS_RADIUS
= 0.01;
87 const int catBits
[NUM_PARTS
+1] =
89 0x0001, ///< Ext Cylinder category
90 0x0002, ///< Int Cylinder category
91 0x0004, ///< Int_Rect Cylinder category
92 0x0008, ///< Box category
93 0x0010, ///< Obstacle category
94 0x0020, ///< Ground category
95 ~0L ///< All categories
103 static float xyz
[3] = {2.0f
,-3.5f
,2.0000f
};
104 static float hpr
[3] = {90.000f
,-25.5000f
,0.0000f
};
107 //world,space,body & geom
108 static dWorldID world
;
109 static dSpaceID space
;
110 static dJointGroupID contactgroup
;
111 static dBodyID body
[NUM_PARTS
];
112 static dGeomID geom
[NUM_PARTS
];
114 // Default Positions and anchor of the 2 bodies
119 static dJoint
*joint
;
122 const dReal BODY2_SIDES
[3] = {0.4, 0.4, 0.4};
123 const dReal OBS_SIDES
[3] = {1,1,1};
124 const dReal RECT_SIDES
[3] = {0.3, 0.1, 0.2};
127 int type
= dJointTypePiston
;
129 //#pragma message("tc to be changed to 0")
131 int tc
= 0; // The test case choice;
134 //collision detection
135 static void nearCallback (void *, dGeomID o1
, dGeomID o2
)
139 dBodyID b1
= dGeomGetBody (o1
);
140 dBodyID b2
= dGeomGetBody (o2
);
141 if (b1
&& b2
&& dAreConnectedExcluding (b1
,b2
,dJointTypeContact
) ) return;
144 n
= dCollide (o1
,o2
,N
,&contact
[0].geom
,sizeof (dContact
) );
149 contact
[i
].surface
.mode
= (dContactSlip1
| dContactSlip2
|
150 dContactSoftERP
| dContactSoftCFM
|
152 contact
[i
].surface
.mu
= 0.1;
153 contact
[i
].surface
.slip1
= 0.02;
154 contact
[i
].surface
.slip2
= 0.02;
155 contact
[i
].surface
.soft_erp
= 0.1;
156 contact
[i
].surface
.soft_cfm
= 0.0001;
157 dJointID c
= dJointCreateContact (world
,contactgroup
,&contact
[i
]);
158 dJointAttach (c
,dGeomGetBody (contact
[i
].geom
.g1
),dGeomGetBody (contact
[i
].geom
.g2
) );
163 static void printKeyBoardShortCut()
165 printf ("Press 'h' for this help.\n");
166 printf ("Press 'q' to add force on BLUE body along positive x direction.\n");
167 printf ("Press 'w' to add force on BLUE body along negative x direction.\n");
169 printf ("Press 'a' to add force on BLUE body along positive y direction.\n");
170 printf ("Press 's' to add force on BLUE body along negative y direction.\n");
172 printf ("Press 'z' to add force on BLUE body along positive z direction.\n");
173 printf ("Press 'x' to add force on BLUE body along negative z direction.\n");
175 printf ("Press 'e' to add torque on BLUE body around positive x direction \n");
176 printf ("Press 'r' to add torque on BLUE body around negative x direction \n");
178 printf ("Press 'd' to add torque on BLUE body around positive y direction \n");
179 printf ("Press 'f' to add torque on BLUE body around negative y direction \n");
181 printf ("Press 'c' to add torque on BLUE body around positive z direction \n");
182 printf ("Press 'v' to add torque on BLUE body around negative z direction \n");
184 printf ("Press 't' to add force on prismatic joint in the positive axis direction\n");
185 printf ("Press 'y' to add force on prismatic joint in the negative axis direction\n");
187 printf ("Press 'i' to add limits on the prismatic joint (0 to 0) \n");
188 printf ("Press 'o' to add limits on the rotoide joint (0 to 0)\n");
189 printf ("Press 'k' to add limits on the rotoide joint (-45 to 45deg) \n");
190 printf ("Press 'l' to remove limits on the rotoide joint \n");
193 printf ("Press '.' to increase joint velocity along the prismatic direction.\n");
194 printf ("Press ',' to decrease joint velocity along the prismatic direction.\n");
196 printf ("Press 'p' to print the Position of the joint.\n");
198 printf ("Press '+' Go to the next test case.\n");
199 printf ("Press '-' Go to the previous test case.\n");
201 printf ("Press '8' To remove one of the body. The blue body and the world will be\n");
202 printf (" attached to the joint (blue body at position 1)\n");
203 printf ("Press '9' To remove one of the body. The blue body and the world will be\n");
204 printf (" attached to the joint (body body at position 2)\n");
210 // start simulation - set viewpoint
213 dAllocateODEDataForThread(dAllocateMaskAll
);
215 dsSetViewpoint (xyz
,hpr
);
216 printf ("This program demonstrates how the Piston joint works.\n");
217 printf ("A Piston joint enables the sliding of a body with respect to another body\n");
218 printf ("and the 2 bodies are free to rotate about the sliding axis.\n\n");
219 printf ("The yellow body is fixed to the world\n");
220 printf ("The yellow body and the blue body are attached by a Piston joint with\n");
221 printf ("the axis along the x direction.\n");
222 printf ("The purple object is a geometry obstacle.\n");
224 printKeyBoardShortCut();
228 void setPositionBodies (int val
)
230 const dVector3 POS1
= {0,0,1.5,0};
231 const dVector3 POS2
= {0,0,1.5,0};
232 const dVector3 ANCHOR
= {0,0,1.5,0};
234 for (int i
=0; i
<3; ++i
)
238 anchor
[i
] = ANCHOR
[i
];
243 dBodySetLinearVel (body
[BODY1
], 0,0,0);
244 dBodySetAngularVel (body
[BODY1
], 0,0,0);
249 dBodySetLinearVel (body
[BODY2
], 0,0,0);
250 dBodySetAngularVel (body
[BODY2
], 0,0,0);
266 default: // This is also case 0
267 // Nothing to be done
280 dBodySetPosition (body
[BODY1
], pos1
[X
], pos1
[Y
], pos1
[Z
]);
281 dBodySetRotation (body
[BODY1
], R
);
286 dBodySetPosition (body
[BODY2
], pos2
[X
], pos2
[Y
], pos2
[Z
]);
287 dBodySetRotation (body
[BODY2
], R
);
294 joint
->attach (body
[BODY1
], body
[BODY2
]);
295 if (joint
->getType() == dJointTypePiston
)
296 dJointSetPistonAnchor(joint
->id(), anchor
[X
], anchor
[Y
], anchor
[Z
]);
302 // function to update camera position at each step.
305 // static FILE *file = fopen("x:/sim/src/libode/tstsrcSF/export.dat", "w");
307 // static int cnt = 0;
309 // sprintf(str, "%06d",cnt++);
311 // dWorldExportDIF(world, file, str);
315 // called when a key pressed
316 static void command (int cmd
)
323 printKeyBoardShortCut();
329 dBodyAddForce (body
[BODY1
],4,0,0);
333 dBodyAddForce (body
[BODY1
],-4,0,0);
338 dBodyAddForce (body
[BODY1
],0,40,0);
342 dBodyAddForce (body
[BODY1
],0,-40,0);
347 dBodyAddForce (body
[BODY1
],0,0,4);
351 dBodyAddForce (body
[BODY1
],0,0,-4);
357 dBodyAddTorque (body
[BODY1
],0.1,0,0);
361 dBodyAddTorque (body
[BODY1
],-0.1,0,0);
366 dBodyAddTorque (body
[BODY1
],0, 0.1,0);
370 dBodyAddTorque (body
[BODY1
],0,-0.1,0);
375 dBodyAddTorque (body
[BODY1
],0.1,0,0);
379 dBodyAddTorque (body
[BODY1
],-0.1,0,0);
384 if (joint
->getType() == dJointTypePiston
)
385 dJointAddPistonForce (joint
->id(),1);
387 dJointAddSliderForce (joint
->id(),1);
391 if (joint
->getType() == dJointTypePiston
)
392 dJointAddPistonForce (joint
->id(),-1);
394 dJointAddSliderForce (joint
->id(),-1);
399 dJointAttach(joint
->id(), body
[0], 0);
402 dJointAttach(joint
->id(), 0, body
[0]);
407 joint
->setParam (dParamLoStop
, 0);
408 joint
->setParam (dParamHiStop
, 0);
413 joint
->setParam (dParamLoStop2
, 0);
414 joint
->setParam (dParamHiStop2
, 0);
419 joint
->setParam (dParamLoStop2
, -45.0*3.14159267/180.0);
420 joint
->setParam (dParamHiStop2
, 45.0*3.14159267/180.0);
424 joint
->setParam (dParamLoStop2
, -dInfinity
);
425 joint
->setParam (dParamHiStop2
, dInfinity
);
432 dReal vel
= joint
->getParam (dParamVel
) - VEL_INC
;
433 joint
->setParam (dParamVel
, vel
);
434 std::cout
<<"Velocity = "<<vel
<<" FMax = 2"<<'\n';
441 dReal vel
= joint
->getParam (dParamVel
) + VEL_INC
;
442 joint
->setParam (dParamVel
, vel
);
443 std::cout
<<"Velocity = "<<vel
<<" FMax = 2"<<'\n';
450 switch (joint
->getType() )
452 case dJointTypeSlider
:
454 dSliderJoint
*sj
= reinterpret_cast<dSliderJoint
*> (joint
);
455 std::cout
<<"Position ="<<sj
->getPosition() <<"\n";
458 case dJointTypePiston
:
460 dPistonJoint
*rj
= reinterpret_cast<dPistonJoint
*> (joint
);
461 std::cout
<<"Position ="<<rj
->getPosition() <<"\n";
465 {} // keep the compiler happy
472 setPositionBodies (tc
);
476 setPositionBodies (tc
);
483 static void drawBox (dGeomID id
, int R
, int G
, int B
)
488 const dReal
*pos
= dGeomGetPosition (id
);
489 const dReal
*rot
= dGeomGetRotation (id
);
493 dGeomBoxGetLengths (id
, l
);
494 dsDrawBox (pos
, rot
, l
);
499 static void simLoop (int pause
)
505 switch (joint
->getType() )
507 case dJointTypeSlider
:
508 ( (dSliderJoint
*) joint
)->getAxis (ax
);
509 l
= ( (dSliderJoint
*) joint
)->getPosition();
511 case dJointTypePiston
:
512 ( (dPistonJoint
*) joint
)->getAxis (ax
);
513 l
= ( (dPistonJoint
*) joint
)->getPosition();
516 {} // keep the compiler happy
522 double simstep
= 0.01; // 1ms simulation steps
523 double dt
= dsElapsedTime();
525 int nrofsteps
= (int) ceilf (dt
/simstep
);
529 for (int i
=0; i
<nrofsteps
&& !pause
; i
++)
531 dSpaceCollide (space
,0,&nearCallback
);
532 dWorldStep (world
, simstep
);
534 dJointGroupEmpty (contactgroup
);
540 dReal radius
, length
;
542 dsSetTexture (DS_WOOD
);
544 drawBox (geom
[BODY2
], 1,1,0);
546 drawBox (geom
[RECT
], 0,0,1);
550 const dReal
*pos
= dGeomGetPosition (geom
[BODY1
]);
551 rot
= dGeomGetRotation (geom
[BODY1
]);
554 dGeomCapsuleGetParams (geom
[BODY1
], &radius
, &length
);
555 dsDrawCapsule (pos
, rot
, length
, radius
);
559 drawBox (geom
[OBS
], 1,0,1);
562 // Draw the prismatic axis
565 const dReal
*pos
= dGeomGetPosition (geom
[BODY1
]);
566 rot
= dGeomGetRotation (geom
[BODY2
]);
568 p
[X
] = pos
[X
] - l
*ax
[X
];
569 p
[Y
] = pos
[Y
] - l
*ax
[Y
];
570 p
[Z
] = pos
[Z
] - l
*ax
[Z
];
572 dsDrawCylinder (p
, rot
, 3.75, 1.05*AXIS_RADIUS
);
576 if (joint
->getType() == dJointTypePiston
)
579 dJointGetPistonAnchor(joint
->id(), anchor
);
581 // Draw the rotoide axis
582 rot
= dGeomGetRotation (geom
[BODY2
]);
583 dsSetColor (1,0.5,0);
584 dsDrawCylinder (anchor
, rot
, 4, AXIS_RADIUS
);
588 rot
= dGeomGetRotation (geom
[BODY1
]);
589 dsDrawSphere (anchor
, rot
, 1.5*RADIUS
);
596 void Help (char **argv
)
598 printf ("%s ", argv
[0]);
599 printf (" -h | --help : print this help\n");
600 printf (" -s | --slider : Set the joint as a slider\n");
601 printf (" -p | --piston : Set the joint as a Piston. (Default joint)\n");
602 printf (" -1 | --offset1 : Create an offset between the 2 bodies\n");
603 printf (" Offset one of the body by z=-0.5 and keep the anchor\n");
604 printf (" point in the middle of the fixed body\n");
605 printf (" -2 | --offset2 : Create an offset between the 2 bodies\n");
606 printf (" Offset one of the body by z=-0.5 and set the anchor\n");
607 printf (" point in the middle of the movable body\n");
608 printf (" -3 | --offset3 : Create an offset between the 2 bodies\n");
609 printf (" Offset one of the body by z=-0.5 and set the anchor\n");
610 printf (" point in the middle of the 2 bodies\n");
611 printf (" -t | --texture-path path : Path to the texture.\n");
612 printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH
);
613 printf (" -n | --notFixed : In free space with no gravity mode");
614 printf ("-notex : Don't use texture\n");
615 printf ("-noshadow : No shadow\n");
616 printf ("-noshadows : No shadows\n");
617 printf ("-pause : Initial pause\n");
618 printf ("--------------------------------------------------\n");
619 printf ("Hit any key to continue:");
625 int main (int argc
, char **argv
)
630 // setup pointers to drawstuff callback functions
632 fn
.version
= DS_VERSION
;
635 fn
.command
= &command
;
637 fn
.path_to_textures
= DRAWSTUFF_TEXTURE_PATH
;
640 dSetZero (offset
, 4);
646 for (int i
=1; i
< argc
; ++i
)
648 //static int tata = 0;
652 if ( 0 == strcmp ("-h", argv
[i
]) || 0 == strcmp ("--help", argv
[i
]) )
655 if ( 0 == strcmp ("-s", argv
[i
]) || 0 == strcmp ("--slider", argv
[i
]) )
656 type
= dJointTypeSlider
;
658 if ( 0 == strcmp ("-t", argv
[i
]) || 0 == strcmp ("--texture-path", argv
[i
]) )
661 if ( j
>= argc
|| // Check if we have enough arguments
662 argv
[j
][0] == '\0' || // We should have a path here
663 argv
[j
][0] == '-' ) // We should have a path not a command line
666 fn
.path_to_textures
= argv
[++i
]; // Increase i since we use this argument
671 if ( 0 == strcmp ("-1", argv
[i
]) || 0 == strcmp ("--offset1", argv
[i
]) )
674 if ( 0 == strcmp ("-2", argv
[i
]) || 0 == strcmp ("--offset2", argv
[i
]) )
677 if ( 0 == strcmp ("-3", argv
[i
]) || 0 == strcmp ("--offset3", argv
[i
]) )
680 if (0 == strcmp ("-n", argv
[i
]) || 0 == strcmp ("--notFixed", argv
[i
]) )
685 world
= dWorldCreate();
686 dWorldSetERP (world
, 0.8);
688 space
= dSimpleSpaceCreate (0);
689 contactgroup
= dJointGroupCreate (0);
690 geom
[GROUND
] = dCreatePlane (space
, 0,0,1,0);
691 dGeomSetCategoryBits (geom
[GROUND
], catBits
[GROUND
]);
692 dGeomSetCollideBits (geom
[GROUND
], catBits
[ALL
]);
698 // Create the Obstacle
699 geom
[OBS
] = dCreateBox (space
, OBS_SIDES
[0], OBS_SIDES
[1], OBS_SIDES
[2]);
700 dGeomSetCategoryBits (geom
[OBS
], catBits
[OBS
]);
701 dGeomSetCollideBits (geom
[OBS
], catBits
[ALL
]);
702 //Rotation of 45deg around y
703 dRFromAxisAndAngle (R
, 1,1,0, -0.25*PI
);
704 dGeomSetRotation (geom
[OBS
], R
);
705 dGeomSetPosition (geom
[OBS
], 1.95, -0.2, 0.5);
708 //Rotation of 90deg around y
709 // Will orient the Z axis along X
710 dRFromAxisAndAngle (R
, 0,1,0, -0.5*PI
);
713 // Create Body2 (Wiil be attached to the world)
714 body
[BODY2
] = dBodyCreate (world
);
715 // Main axis of cylinder is along X=1
716 dMassSetBox (&m
, 1, BODY2_SIDES
[0], BODY2_SIDES
[1], BODY2_SIDES
[2]);
717 dMassAdjust (&m
, Mass1
);
718 geom
[BODY2
] = dCreateBox (space
, BODY2_SIDES
[0], BODY2_SIDES
[1], BODY2_SIDES
[2]);
719 dGeomSetBody (geom
[BODY2
], body
[BODY2
]);
720 dGeomSetOffsetRotation (geom
[BODY2
], R
);
721 dGeomSetCategoryBits (geom
[BODY2
], catBits
[BODY2
]);
722 dGeomSetCollideBits (geom
[BODY2
], catBits
[ALL
] & (~catBits
[BODY1
]) );
723 dBodySetMass (body
[BODY2
], &m
);
726 // Create Body 1 (Slider on the prismatic axis)
727 body
[BODY1
] = dBodyCreate (world
);
728 // Main axis of capsule is along X=1
729 dMassSetCapsule (&m
, 1, 1, RADIUS
, BODY1_LENGTH
);
730 dMassAdjust (&m
, Mass1
);
731 geom
[BODY1
] = dCreateCapsule (space
, RADIUS
, BODY1_LENGTH
);
732 dGeomSetBody (geom
[BODY1
], body
[BODY1
]);
733 dGeomSetOffsetRotation (geom
[BODY1
], R
);
734 dGeomSetCategoryBits (geom
[BODY1
], catBits
[BODY1
]);
735 dGeomSetCollideBits (geom
[BODY1
], catBits
[ALL
] & ~catBits
[BODY2
] & ~catBits
[RECT
]);
738 dMassSetBox (&mRect
, 1, RECT_SIDES
[0], RECT_SIDES
[1], RECT_SIDES
[2]);
739 dMassAdd (&m
, &mRect
);
740 // TODO: translate m?
741 geom
[RECT
] = dCreateBox (space
, RECT_SIDES
[0], RECT_SIDES
[1], RECT_SIDES
[2]);
742 dGeomSetBody (geom
[RECT
], body
[BODY1
]);
743 dGeomSetOffsetPosition (geom
[RECT
],
744 (BODY1_LENGTH
-RECT_SIDES
[0]) /2.0,
746 -RADIUS
-RECT_SIDES
[2]/2.0);
747 dGeomSetCategoryBits (geom
[RECT
], catBits
[RECT
]);
748 dGeomSetCollideBits (geom
[RECT
], catBits
[ALL
] & (~catBits
[BODY1
]) );
750 dBodySetMass (body
[BODY1
], &m
);
754 setPositionBodies (tc
);
759 // Attache external cylinder to the world
760 dJointID fixed
= dJointCreateFixed (world
,0);
761 dJointAttach (fixed
, NULL
, body
[BODY2
]);
762 dJointSetFixed (fixed
);
763 dWorldSetGravity (world
,0,0,-0.8);
767 dWorldSetGravity (world
,0,0,0);
773 // The static is here only to help debugging
776 case dJointTypeSlider
:
778 dSliderJoint
*sj
= new dSliderJoint (world
, 0);
779 sj
->attach (body
[BODY1
], body
[BODY2
]);
780 sj
->setAxis (1, 0, 0);
785 case dJointTypePiston
: // fall through default
788 dPistonJoint
*pj
= new dPistonJoint (world
, 0);
789 pj
->attach (body
[BODY1
], body
[BODY2
]);
790 pj
->setAxis (1, 0, 0);
792 dJointSetPistonAnchor(pj
->id(), anchor
[X
], anchor
[Y
], anchor
[Z
]);
801 dsSimulationLoop (argc
,argv
,400,300,&fn
);
804 dJointGroupDestroy (contactgroup
);
805 dSpaceDestroy (space
);
806 dWorldDestroy (world
);