I've been helping a JV-ODE user out with AMotor joints via email and thought that this info would be helpful to everyone, so here it is...
Creating and using AMotor joints:
Attach two bodies using a Ball joint, then attach an AMotor joint to the same two bodies. The Ball joint will keep the two bodies attached to each other and will allow movement in all directions. In the car demo below, you will see that the rear wheels are attached using Ball joints instead of Hinge2 joints like the two front wheels.
Without the AMotor joints on the rear wheels, they would collapse as Ball joints move in any direction. Try commenting out all of the AMotor stuff in the SetupCar() and UpdateCar() functions in the AMotor demo and you will see the rear wheels wobble and collapse.
One ability of the AMotor joint is to restrict motion on any axis, in the car demo it stops the wheels collapsing by restricting movement of the Ball joint in all directions except the z axis to allow the Ball joint (or wheel) to rotate.
The dJointSetAMotorAxis() functions will allow you to set whether rotation is allowed on each axis of the joint. A value of 0 (zero) will not allow movement, a value of 1 (or -1 to reverse) will allow movement.
Next, you need to set the 'dParamLoStop' and 'dParamHiStop' parameters with the dJointSetAMotorParam() function to define how much rotation is allowed. The value should be in radians, not degrees. A value of zero for both LoStop and HiStop will not allow any movement. As you can see in the car demo we need full rotation to allow the wheel to spin completely, so it is set with -4 radians for the LoStop and 4 radians for the HiStop which will allow full rotation. Try changing them to -2 and 2 and you will see that the wheels lock after approx 1/2 a rotation. Remember that the LoStop value must always be the lowest value and the HiStop must be the highest value.
The second ability is that you are able to supply a force to AMotor joints to make them rotate, like an electric motor. See the third For/Next loop in the UpdateCar() function in the car demo, you can use 'dParamVel' (force) and 'dParamFMax' (torque) to do this.
You need to set all of the AMotorAxis and AMotorParam settings for the AMotor joint to function correctly.
Here's the AMotor demo... (it will be included in the next JV-ODE update)
; ###################################################################################################
; # JV-ODE Car Demo #
; # Code by Jim Williams (VIP3R) # #
; # Feel free to use this code, any credit appreciated #
; ###################################################################################################
AppTitle "JV-ODE Car Demo - AMotor"
Include "JV-ODE.bb"
Graphics3D 800,600,0,2
Global CMass#=200 ; ### Car Mass
Global WMass#=14 ; ### Wheel Mass
Global WorldERP#=0.8 ; ### World Error Correction
Global WorldFriction#=70 ; ### World Friction
Global Torque#=24 ; ### Joint Torque
Global SuspensionHS#=0.01 ; ### Suspension Hardness/Softness (Higher=Softer - Lower=Harder)
Global Force#=0
Global Steer#=0
Global Car
Global CGeom
Global CMesh
Global CarStartY=20
Dim Wheel(4)
Dim WGeom(4)
Dim Joint(4)
Type ODEGeom
Field body
Field geom
Field mesh
End Type
; ###################################################################################################
; ### Setup ODE
Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)
dWorldSetAutoDisableFlag(World,1)
dWorldSetGravity(World,0,-0.98,0)
dWorldSetERP(World,WorldERP)
dContactSetMode(dContactSlip1)
dContactSetMu(WorldFriction)
; ### Create car body
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,0,CarStartY,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dMassTranslate(mass,0,-1,0)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,40,80,255
EntityAlpha ode\mesh,1
; ### Create wheels
For count=1 To 4
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Wheel(count)=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,0,0,0)
mass=dMassCreate()
dMassSetSphereTotal(mass,WMass,0.7)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateSphere(Space,0.7)
WGeom(count)=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCylinder(8)
ScaleMesh ode\mesh,0.7,0.25,0.7
RotateMesh ode\mesh,0,0,90
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,255,255,255
Next
dBodySetPosition(Wheel(1),-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(2),+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(3),-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(4),+2,CarStartY-0.5,-2)
; ### Create some objects
SeedRnd MilliSecs()
For spheres=1 To 20
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
ode\geom=dCreateSphere(Space,4)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateSphere()
ScaleMesh ode\mesh,4,4,4
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
Next
For cylinders=1 To 20
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,90,0,0)
dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
ode\geom=dCreateCCylinder(Space,1,8)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCylinder(8)
ScaleMesh ode\mesh,1,5,1
RotateMesh ode\mesh,90,0,0 ; <<< Mesh X-Axis must be rotated 90 degrees to fix cylinder alignment
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
Next
; ### Create light
Global Light=CreateLight()
RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130
; ### Create camera
Global CameraPivot=CreatePivot(CMesh)
PositionEntity CameraPivot,0,2,-7
Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
; ### Create plane
dCreatePlane(Space,0,1,0,0)
Plane=CreatePlane()
EntityAlpha Plane,0.8
PlaneTexture=CreateTexture(128,128,9)
ClsColor 0,200,80
Cls
Color 255,255,255
Rect 0,0,64,64,1
Rect 64,64,64,64,1
CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,20,20
EntityTexture Plane,PlaneTexture,0,0
Mirror=CreateMirror()
; ###################################################################################################
; ### BLITZ STATIC OBJECT (White)
blitzobject=CreateCube()
ScaleMesh blitzobject,1,4,20
RotateMesh blitzobject,-10,8,4
PositionMesh blitzobject,10,5,40
EntityColor blitzobject,255,255,255
EntityAlpha blitzobject,1
; ### ODE STATIC OBJECT (Blue)
ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,2,8,40)
dGeomSetRotation(ode\geom,-10,8,4)
dGeomSetPosition(ode\geom,20,5,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,1,4,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,0,100,200
EntityAlpha ode\mesh,1
; ### ODE STATIC OBJECT (Red)
ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,18,0.2,40)
dGeomSetRotation(ode\geom,-14,0,0)
dGeomSetPosition(ode\geom,-20,4.9,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,9,0.1,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,200,0,100
EntityAlpha ode\mesh,1
; ###################################################################################################
SetupCar()
While Not KeyHit(1)
UpdateKeys()
PTime=MilliSecs()
UpdateCar()
UpdateGeoms()
dSpaceCollide(Space,World,ContactGroup)
dWorldQuickStep(World,0.1)
dJointGroupEmpty(ContactGroup)
PhysicsTime#=MilliSecs()-PTime
UpdateCam()
UpdateWorld
RenderWorld
Text 0,0,"JV-ODE Version "+dGetVersion()
Text 0,15,"Physics Time:"+PhysicsTime
Text 0,50,"Force:"+Force
Text 0,65,"Torque:"+Torque
Text 640,0,"A - Accelerate"
Text 640,15,"Z - Brake/Reverse"
Text 640,30,"Arrows - Steering"
Text 640,45,"Space - Reset Car"
Flip
Wend
dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()
End
; ###################################################################################################
Function SetupCar()
For count=1 To 2
Joint(count)=dJointCreateHinge2(World,0)
dJointAttach(Joint(count),Car,Wheel(count))
dJointSetHinge2Anchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
dJointSetHinge2Axis1(Joint(count),0,1,0)
dJointSetHinge2Axis2(Joint(count),-1,0,0)
dJointSetHinge2Param(Joint(count),dParamSuspensionERP,0.8)
dJointSetHinge2Param(Joint(count),dParamSuspensionCFM,SuspensionHS)
Next
For count=3 To 4
Joint(count)=dJointCreateBall(World,0)
dJointAttach(Joint(count),Car,Wheel(count))
dJointSetBallAnchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
Joint(count)=dJointCreateAMotor(World,0)
dJointAttach(Joint(count),Car,Wheel(count))
dJointSetAMotorMode(Joint(count),dAMotorEuler)
dJointSetAMotorAxis(Joint(count),0,0,0,0,0)
dJointSetAMotorAxis(Joint(count),1,0,0,0,0)
dJointSetAMotorAxis(Joint(count),2,0,0,0,1)
dJointSetAMotorParam(Joint(count),dParamLoStop,-4)
dJointSetAMotorParam(Joint(count),dParamHiStop,4)
dJointSetAMotorParam(Joint(count),dParamLoStop2,0)
dJointSetAMotorParam(Joint(count),dParamHiStop2,0)
dJointSetAMotorParam(Joint(count),dParamLoStop3,0)
dJointSetAMotorParam(Joint(count),dParamHiStop3,0)
Next
Force=0
End Function
; ###################################################################################################
Function UpdateKeys()
If KeyDown(30)=1
Force=Force+0.08
If Force>70 Then Force=70
End If
If KeyDown(44)=1
Force=Force-0.1
If Force<-10 Then Force=-10
If Force>0 Then Force=Force*0.97
End If
If KeyDown(30)=0 And KeyDown(44)=0 Then Force=Force*0.99
If KeyDown(203)=1 Or KeyDown(205)=1
If KeyDown(203)=1
Steer=0.5
Else
Steer=-0.5
End If
Else
Steer=0
End If
If KeyHit(57)=1
Force=0
dBodySetRotation(Car,dGeomGetPitch#(CGeom),dGeomGetYaw#(CGeom),0)
End If
End Function
; ###################################################################################################
Function UpdateCar()
For count=1 To 4
dBodyEnable(Wheel(count))
Next
dBodyEnable(Car)
For count=1 To 2
dJointSetHinge2Param(Joint(count),dParamVel2,Force)
dJointSetHinge2Param(Joint(count),dParamFMax2,Torque)
Next
For count=3 To 4
dJointSetAMotorParam(Joint(count),dParamVel,-Force)
dJointSetAMotorParam(Joint(count),dParamFMax,Torque)
Next
For count=1 To 2
angle#=Steer-dJointGetHinge2Angle1(Joint(count))
dJointSetHinge2Param(Joint(count),dParamVel,angle)
dJointSetHinge2Param(Joint(count),dParamFMax,400)
Next
End Function
; ###################################################################################################
Function UpdateCam()
PositionEntity CameraPivot,0,3,-12
camx#=EntityX(CameraPivot,1)-EntityX(Camera)
camy#=EntityY(CameraPivot,1)-EntityY(Camera)
camz#=EntityZ(CameraPivot,1)-EntityZ(Camera)
TranslateEntity Camera,camx*0.5,camy*0.5,camz*0.5
PointEntity Camera,CMesh
End Function
; ###################################################################################################
Function UpdateGeoms()
For ode.ODEGeom=Each ODEGeom
RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
Next
End Function
; ###################################################################################################