Plane2D - A new ODE joint type for 2D simulations ################################################# psero@gmx.de Wed Apr 23 19:36:19 MET DST 2003 Last Change: Wed Nov 5 12:49:12 MET 2003 Purpose ======= A Plane2D joint restricts an ODE body in the following way: - its position stays as z=0 - its z-axis stays aligned to the world's z-axis The remaining three degrees of freedom are: - x and y positions. Two linear motors are supplied to control dynamics along x and y axes, respective. - rotation around z-axis. A linear motor is supplied to control rotation dynamics. Limitations: - Motor limits are not supported on the three linear motors. (Would that make sense?) - Though the Plane2D joint is fully operative with respect to the position as well as the orientation, the inavoidable, small(!) drift due to the numeric computation is compensated ("c term") only for the position. The application has to take of the rotational drift part by itself, see the example code below. (The ODE hinge joint has this working, and so should the Plane2D joint. Any ideas?) - The plane equation is fixed to z = 0. Benefits: - Much faster than a helper construction made of two sliders (x,y) and a hinge (z) for each body. (Approved.) - Much more stable than putting 3D objects tightly in between two "sandwich" planes and having the collision system enforce the constraint. (Also approved.) - 2D dynamics can by used within a 3D world: 2D-restricted bodies will have 3D shapes (geometries) and can interact with unrestricted 3D bodies. C-style interface ================= Creation: extern dJointID dJointCreatePlane2D (dWorldID, dJointGroupID); Motor params (note: limits are not supported): extern void dJointSetPlane2DXParam (dJointID, int parameter, dReal value); extern void dJointSetPlane2DYParam (dJointID, int parameter, dReal value); extern void dJointSetPlane2DAngleParam (dJointID, int parameter, dReal value); Example code ============ Creation and application: dJointID my_joint = dJointCreatePlane2D (my_world.id(), 0); // Note: second body is not used: dJointAttach (my_joint, my_body.id(), 0); dJointSetPlane2DXParam (plane2d_joint_ids[0], dParamFMax, 10); dJointSetPlane2DYParam (plane2d_joint_ids[0], dParamFMax, 10); Note: attach the usual 3D geometries to bodies. After each simulation step, we need to correct the small angular drift, keep the angular velocity and the rotation axis aligned to the z-axis (for each body connected with a Plane2D joint): const dReal *rot = dBodyGetAngularVel (my_body.id())); const dReal *quat_ptr; dReal quat[4], quat_len; quat_ptr = dBodyGetQuaternion (my_body.id())); quat[0] = quat_ptr[0]; quat[1] = 0; quat[2] = 0; quat[3] = quat_ptr[3]; quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]); quat[0] /= quat_len; quat[3] /= quat_len; dBodySetQuaternion (my_body.id()), quat); dBodySetAngularVel (my_body.id()), 0, 0, rot[2]); A working example is in my distribution, see Installation below. Implementation ============== New data type: struct dxJointPlane2D; New enum value: dJointTypePlane2D Mathematics: from the implementation code of: void plane2dGetInfo2 (dxJointPlane2D *joint, dxJoint::Info2 *info) This refers to Russell's explanation of "How to make new joint in ODE" (http://opende.sourceforge.net/joints.pdf) v = v1, w = omega1 (v2, omega2 not important (== static environment)) constraint equations: xz = 0 wx = 0 wy = 0 <=> ( 0 0 1 ) (vx) ( 0 0 0 ) (wx) ( 0 ) ( 0 0 0 ) (vy) + ( 1 0 0 ) (wy) = ( 0 ) ( 0 0 0 ) (vz) ( 0 1 0 ) (wz) ( 0 ) J1/J1l Omega1/J1a Installation ============ As five files of ODE code had to modified for the implementation I didn't find a good way to put my code into a 'contrib'ution. Therefore I recommend starting with an ODE 0.035 or 0.039 source tree and patch by hand as follows. Unpacking Plane2D.tar (into the ODE toplevel directory, with is ode-0.039/ on my disk) you get: ode-0.039/ode/src/joint_pserocka.h ode-0.035/ode/src/joint_pserocka.cpp ode-0.039/ode/src/ode_pserocka.cpp ode-0.039/include/ode/objects_pserocka.h ode-0.039/include/ode/common_enum_pserocka.h ode-0.039/test.pserocka/ ode-0.039/test.pserocka/GNUmakefile ode-0.039/test.pserocka/go ode-0.039/test.pserocka/test_plane2d.cc The former files contain code snippets that are to be put into the corresponding ODE files. (corresponding means: ODE file names without the "_pserocka" part, see the comments in my files.) Beware: common_enum_pserocka.h contains only one line, a new enum value, to be added to the right enum{} definition in common.h (see comment in file). Sorry for the inconvencience, diff/patch was not an option for some reason. The code in the test.pserocka/ directory is a small application, using ODE "drawstuff" for graphics: A bunch of objects is created. One of them ([0]) is "driven" (with the x,y linear motors) to follow some moving "tracking" position to get some interesting action. Have fun!