Exemple #1
0
void dJointGetGearboxAxis2( dJointID j, dVector3 result )
{
    dxJointGearbox* joint = static_cast<dxJointGearbox*>(j);
    dUASSERT( joint, "bad joint argument" );

    dBodyVectorToWorld(joint->node[0].body,
                       joint->axis2[0], joint->axis2[1], joint->axis2[2],
                       result);
}
Exemple #2
0
void
dxJointGearbox::getInfo2( dxJoint::Info2* info )
{
    dVector3 globalAxis1, globalAxis2;

    dBodyVectorToWorld(node[0].body, axis1[0], axis1[1], axis1[2], globalAxis1);
    dBodyVectorToWorld(node[1].body, axis2[0], axis2[1], axis2[2], globalAxis2);

    double ang1 = getHingeAngle(refBody1,node[0].body,globalAxis1,qrel1);
    double ang2 = getHingeAngle(refBody2,node[1].body,globalAxis2,qrel2);
    // printf("a1(%f) a10(%f) a2(%f) a20(%f)\n",
    //   ang1, cumulative_angle1, ang2, cumulative_angle2);

    cumulative_angle1 = dShortestAngularDistanceUpdate(cumulative_angle1,ang1);
    cumulative_angle2 = dShortestAngularDistanceUpdate(cumulative_angle2,ang2);

    double err = dShortestAngularDistance(
     cumulative_angle1, -ratio * cumulative_angle2);

    // FIXME: error calculation is not amenable to reset of poses,
    // cumulative angles might snap to wrong angular value.
    // printf("a1(%f) a1f(%f) a2(%f) a2f(%f) e(%f)\n",
    //   ang1, cumulative_angle1, ang2, cumulative_angle2, err);

    info->J1a[0] = globalAxis1[0];
    info->J1a[1] = globalAxis1[1];
    info->J1a[2] = globalAxis1[2];
    
    info->J2a[0] = ratio * globalAxis2[0];
    info->J2a[1] = ratio * globalAxis2[1];
    info->J2a[2] = ratio * globalAxis2[2];
    
    dReal k = info->fps * info->erp;
    info->c[0] = -k * err;

    // dVector3 d;
    // dAddScaledVectors3(d, node[0].body->avel, node[1].body->avel,
    // 		       1.0, ratio);

    // printf("d: %f\n", dCalcVectorDot3(globalAxis1, d));
}
Exemple #3
0
void dJointGetTransmissionAxis2( dJointID j, dVector3 result )
{
    dxJointTransmission* joint = static_cast<dxJointTransmission*>(j);
    dUASSERT( joint, "bad joint argument" );
    dUASSERT( result, "bad result argument" );

    if (joint->node[1].body) {
        dBodyVectorToWorld(joint->node[1].body,
                           joint->axes[1][0],
                           joint->axes[1][1],
                           joint->axes[1][2],
                           result);
    }
}
Exemple #4
0
void dJointGetTransmissionAxis( dJointID j, dVector3 result )
{
    dxJointTransmission* joint = static_cast<dxJointTransmission*>(j);
    dUASSERT( joint, "bad joint argument" );
    dUASSERT( result, "bad result argument" );
    dUASSERT(joint->mode == dTransmissionParallelAxes,
             "axes must be queried individualy in current mode" );

    if (joint->node[0].body) {
        dBodyVectorToWorld(joint->node[0].body,
                           joint->axes[0][0],
                           joint->axes[0][1],
                           joint->axes[0][2],
                           result);
    }
}
Exemple #5
0
void Buggy::doDynamics(dBodyID body)
{
    //dReal *v = (dReal *)dBodyGetLinearVel(body);

    //dJointSetHinge2Param (carjoint[0],dParamVel,getThrottle());
    //dJointSetHinge2Param (carjoint[0],dParamFMax,1000);

    dJointSetHinge2Param (carjoint[0],dParamVel2,yRotAngle);
    dJointSetHinge2Param (carjoint[0],dParamFMax2,1000);
    
    dJointSetHinge2Param (carjoint[1],dParamVel2,yRotAngle);
    dJointSetHinge2Param (carjoint[1],dParamFMax2,1000);
    
    // steering
    dReal v = dJointGetHinge2Angle1 (carjoint[0]);
    if (v > 0.1) v = 0.1;
    if (v < -0.1) v = -0.1;
    v *= 10.0;
    //dJointSetHinge2Param (carjoint[0],dParamVel,0);
    //dJointSetHinge2Param (carjoint[0],dParamFMax,1000);
    //dJointSetHinge2Param (carjoint[0],dParamLoStop,-0.75);
    //dJointSetHinge2Param (carjoint[0],dParamHiStop,0.75);
    //dJointSetHinge2Param (carjoint[0],dParamFudgeFactor,0.1);
    
    //dBodyAddRelForce (body,0, 0,getThrottle());

    
    // This should be after the world step
    /// stuff
    dVector3 result;
    
    dBodyVectorToWorld(body, 0,0,1,result);
    setForward(result[0],result[1],result[2]);
    
    const dReal *dBodyPosition = dBodyGetPosition(body);
    const dReal *dBodyRotation = dBodyGetRotation(body);
    
    setPos(dBodyPosition[0],dBodyPosition[1],dBodyPosition[2]);
    setLocation((float *)dBodyPosition, (float *)dBodyRotation);
    
}
Exemple #6
0
void
dxJointDBall::getInfo2( dxJoint::Info2 *info )
{
    info->erp = erp;
    info->cfm[0] = cfm;

    dVector3 globalA1, globalA2;
    dBodyGetRelPointPos(node[0].body, anchor1[0], anchor1[1], anchor1[2], globalA1);
    if (node[1].body)
        dBodyGetRelPointPos(node[1].body, anchor2[0], anchor2[1], anchor2[2], globalA2);
    else
        dCopyVector3(globalA2, anchor2);

    dVector3 q;
    dSubtractVectors3(q, globalA1, globalA2);

#ifdef dSINGLE
    const dReal MIN_LENGTH = REAL(1e-7);
#else
    const dReal MIN_LENGTH = REAL(1e-12);
#endif

    if (dCalcVectorLength3(q) < MIN_LENGTH) {
        // too small, let's choose an arbitrary direction
        // heuristic: difference in velocities at anchors
        dVector3 v1, v2;
        dBodyGetPointVel(node[0].body, globalA1[0], globalA1[1], globalA1[2], v1);
        if (node[1].body)
            dBodyGetPointVel(node[1].body, globalA2[0], globalA2[1], globalA2[2], v2);
        else
            dSetZero(v2, 3);
        dSubtractVectors3(q, v1, v2);

        if (dCalcVectorLength3(q) < MIN_LENGTH) {
            // this direction is as good as any
            q[0] = 1;
            q[1] = 0;
            q[2] = 0;
        }
    }
    dNormalize3(q);

    info->J1l[0] = q[0];
    info->J1l[1] = q[1];
    info->J1l[2] = q[2];

    dVector3 relA1;
    dBodyVectorToWorld(node[0].body,
                       anchor1[0], anchor1[1], anchor1[2],
                       relA1);

    dMatrix3 a1m;
    dSetZero(a1m, 12);
    dSetCrossMatrixMinus(a1m, relA1, 4);

    dMultiply1_331(info->J1a, a1m, q);

    if (node[1].body) {
        info->J2l[0] = -q[0];
        info->J2l[1] = -q[1];
        info->J2l[2] = -q[2];

        dVector3 relA2;
        dBodyVectorToWorld(node[1].body,
                           anchor2[0], anchor2[1], anchor2[2],
                           relA2);
        dMatrix3 a2m;
        dSetZero(a2m, 12);
        dSetCrossMatrixPlus(a2m, relA2, 4);
        dMultiply1_331(info->J2a, a2m, q);
    }
    
    const dReal k = info->fps * info->erp;
    info->c[0] = k * (targetDistance - dCalcPointsDistance3(globalA1, globalA2));

}
Exemple #7
0
void
dxJointTransmission::getInfo2( dReal worldFPS, 
                               dReal /*worldERP*/,
                               const Info2Descr* info )
 {
    dVector3 a[2], n[2], l[2], r[2], c[2], s, t, O, d, z, u, v;
    dReal theta, delta, nn, na_0, na_1, cosphi, sinphi, m;
    const dReal *p[2], *omega[2];
    int i;

    // Transform all needed quantities to the global frame.

    for (i = 0 ; i < 2 ; i += 1) {
        dBodyGetRelPointPos(node[i].body,
                            anchors[i][0], anchors[i][1], anchors[i][2],
                            a[i]);

        dBodyVectorToWorld(node[i].body, axes[i][0], axes[i][1], axes[i][2],
                           n[i]);

        p[i] = dBodyGetPosition(node[i].body);
        omega[i] = dBodyGetAngularVel(node[i].body);
    }

    if (update) {
        // Make sure both gear reference frames end up with the same
        // handedness.
    
        if (dCalcVectorDot3(n[0], n[1]) < 0) {
            dNegateVector3(axes[0]);
            dNegateVector3(n[0]);
        }
    }

    // Calculate the mesh geometry based on the current mode.
    
    switch (mode) {
    case dTransmissionParallelAxes:
        // Simply calculate the contact point as the point on the
        // baseline that will yield the correct ratio.

        dIASSERT (ratio > 0);
        
        dSubtractVectors3(d, a[1], a[0]);
        dAddScaledVectors3(c[0], a[0], d, 1, ratio / (1 + ratio));
        dCopyVector3(c[1], c[0]);
        
        dNormalize3(d);
        
        for (i = 0 ; i < 2 ; i += 1) {
            dCalcVectorCross3(l[i], d, n[i]);
        }

        break;
    case dTransmissionIntersectingAxes:
        // Calculate the line of intersection between the planes of the
        // gears.

        dCalcVectorCross3(l[0], n[0], n[1]);
        dCopyVector3(l[1], l[0]);

        nn = dCalcVectorDot3(n[0], n[1]);
        dIASSERT(fabs(nn) != 1);
        
        na_0 = dCalcVectorDot3(n[0], a[0]);
        na_1 = dCalcVectorDot3(n[1], a[1]);

        dAddScaledVectors3(O, n[0], n[1],
                           (na_0 - na_1 * nn) / (1 - nn * nn),
                           (na_1 - na_0 * nn) / (1 - nn * nn));

        // Find the contact point as:
        //
        // c = ((r_a - O) . l) l + O
        //
        // where r_a the anchor point of either gear and l, O the tangent
        // line direction and origin.

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3(d, a[i], O);
            m = dCalcVectorDot3(d, l[i]);        
            dAddScaledVectors3(c[i], O, l[i], 1, m);
        }

        break;
    case dTransmissionChainDrive:
        dSubtractVectors3(d, a[0], a[1]);
        m = dCalcVectorLength3(d);

        dIASSERT(m > 0);
        
        // Caclulate the angle of the contact point relative to the
        // baseline.

        cosphi = clamp((radii[1] - radii[0]) / m, REAL(-1.0), REAL(1.0)); // Force into range to fix possible computation errors
        sinphi = dSqrt (REAL(1.0) - cosphi * cosphi);

        dNormalize3(d);

        for (i = 0 ; i < 2 ; i += 1) {
            // Calculate the contact radius in the local reference
            // frame of the chain.  This has axis x pointing along the
            // baseline, axis y pointing along the sprocket axis and
            // the remaining axis normal to both.

            u[0] = radii[i] * cosphi;
            u[1] = 0;
            u[2] = radii[i] * sinphi;

            // Transform the contact radius into the global frame.

            dCalcVectorCross3(z, d, n[i]);
            
            v[0] = dCalcVectorDot3(d, u);
            v[1] = dCalcVectorDot3(n[i], u);
            v[2] = dCalcVectorDot3(z, u);

            // Finally calculate contact points and l.
            
            dAddVectors3(c[i], a[i], v);
            dCalcVectorCross3(l[i], v, n[i]);
            dNormalize3(l[i]);

            // printf ("%d: %f, %f, %f\n",
            //      i, l[i][0], l[i][1], l[i][2]);
        }

        break;
    }

    if (update) {
        // We need to calculate an initial reference frame for each
        // wheel which we can measure the current phase against.  This
        // frame will have the initial contact radius as the x axis,
        // the wheel axis as the z axis and their cross product as the
        // y axis.

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3 (r[i], c[i], a[i]);
            radii[i] = dCalcVectorLength3(r[i]);
            dIASSERT(radii[i] > 0);
            
            dBodyVectorFromWorld(node[i].body, r[i][0], r[i][1], r[i][2],
                                 reference[i]);
            dNormalize3(reference[i]);
            dCopyVector3(reference[i] + 8, axes[i]);
            dCalcVectorCross3(reference[i] + 4, reference[i] + 8, reference[i]);

            // printf ("%f\n", dDOT(r[i], n[i]));
            // printf ("(%f, %f, %f,\n %f, %f, %f,\n %f, %f, %f)\n",
            //      reference[i][0],reference[i][1],reference[i][2],
            //      reference[i][4],reference[i][5],reference[i][6],
            //      reference[i][8],reference[i][9],reference[i][10]);

            radii[i] = radii[i];
            phase[i] = 0;
        }

        ratio = radii[0] / radii[1];
        update = 0;
    }
    
    for (i = 0 ; i < 2 ; i += 1) {
        dReal phase_hat;

        dSubtractVectors3 (r[i], c[i], a[i]);
        
        // Transform the (global) contact radius into the gear's
        // reference frame.

        dBodyVectorFromWorld (node[i].body, r[i][0], r[i][1], r[i][2], s);
        dMultiply0_331(t, reference[i], s);

        // Now simply calculate its angle on the plane relative to the
        // x-axis which is the initial contact radius.  This will be
        // an angle between -pi and pi that is coterminal with the
        // actual phase of the wheel.  To find the real phase we
        // estimate it by adding omega * dt to the old phase and then
        // find the closest angle to that, that is coterminal to
        // theta.

        theta = atan2(t[1], t[0]);
        phase_hat = phase[i] + dCalcVectorDot3(omega[i], n[i]) / worldFPS;

        if (phase_hat > M_PI_2) {
            if (theta < 0) {
                theta += (dReal)(2 * M_PI);
            }

            theta += (dReal)(floor(phase_hat / (2 * M_PI)) * (2 * M_PI));
        } else if (phase_hat < -M_PI_2) {
            if (theta > 0) {
                theta -= (dReal)(2 * M_PI);
            }

            theta += (dReal)(ceil(phase_hat / (2 * M_PI)) * (2 * M_PI));
        }
                
        if (phase_hat - theta > M_PI) {
            phase[i] = theta + (dReal)(2 * M_PI);
        } else if (phase_hat - theta < -M_PI) {
            phase[i] = theta - (dReal)(2 * M_PI);
        } else {
            phase[i] = theta;
        }

        dIASSERT(fabs(phase_hat - phase[i]) < M_PI);
    }

    // Calculate the phase error.  Depending on the mode the condition
    // is that the distances traveled by each contact point must be
    // either equal (chain and sprockets) or opposite (gears).

    if (mode == dTransmissionChainDrive) {
        delta = (dCalcVectorLength3(r[0]) * phase[0] -
                 dCalcVectorLength3(r[1]) * phase[1]);
    } else {
        delta = (dCalcVectorLength3(r[0]) * phase[0] +
                 dCalcVectorLength3(r[1]) * phase[1]);
    }

    // When in chain mode a torque reversal, signified by the change
    // in sign of the wheel phase difference, has the added effect of
    // switching the active chain branch.  We must therefore reflect
    // the contact points and tangents across the baseline.
    
    if (mode == dTransmissionChainDrive && delta < 0) {
        dVector3 d;

        dSubtractVectors3(d, a[0], a[1]);
        
        for (i = 0 ; i < 2 ; i += 1) {
            dVector3 nn;
            dReal a;
            
            dCalcVectorCross3(nn, n[i], d);
            a = dCalcVectorDot3(nn, nn);
            dIASSERT(a > 0);
            
            dAddScaledVectors3(c[i], c[i], nn,
                               1, -2 * dCalcVectorDot3(c[i], nn) / a);
            dAddScaledVectors3(l[i], l[i], nn,
                               -1, 2 * dCalcVectorDot3(l[i], nn) / a);
        }
    }

    // Do not add the constraint if there's backlash and we're in the
    // backlash gap.

    if (backlash == 0 || fabs(delta) > backlash) {
        // The constraint is satisfied iff the absolute velocity of the
        // contact point projected onto the tangent of the wheels is equal
        // for both gears.  This velocity can be calculated as:
        // 
        // u = v + omega x r_c
        // 
        // The constraint therefore becomes:
        // (v_1 + omega_1 x r_c1) . l = (v_2 + omega_2 x r_c2) . l <=>
        // (v_1 . l + (r_c1 x l) . omega_1 = v_2 . l + (r_c2 x l) . omega_2

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3 (r[i], c[i], p[i]);
        }

        dCalcVectorCross3(info->J1a, r[0], l[0]);
        dCalcVectorCross3(info->J2a, l[1], r[1]);

        dCopyVector3(info->J1l, l[0]);
        dCopyNegatedVector3(info->J2l, l[1]);

        if (delta > 0) {
            if (backlash > 0) {
                info->lo[0] = -dInfinity;
                info->hi[0] = 0;
            }

            info->c[0] = -worldFPS * erp * (delta - backlash);
        } else {
            if (backlash > 0) {
                info->lo[0] = 0;
                info->hi[0] = dInfinity;
            }

            info->c[0] = -worldFPS * erp * (delta + backlash);
        }
    }

    info->cfm[0] = cfm;

    // printf ("%f, %f, %f, %f, %f\n", delta, phase[0], phase[1], -phase[1] / phase[0], ratio);

    // Cache the contact point (in world coordinates) to avoid
    // recalculation if requested by the user.

    dCopyVector3(contacts[0], c[0]);
    dCopyVector3(contacts[1], c[1]);
}
Exemple #8
0
//collide camera with track, generate acceleration on camera if collisding
void camera_physics_step()
{
	//some values that are easy to deal with:
	dReal time = internal.stepsize;
	car_struct *car = camera.car;
	camera_settings *settings = camera.settings;

	//if camera got a targeted car and proper settings, simulate movment
	//
	//divided into 4 parts:
	//1) calculate velocity
	//2) check for collisions
	//3) add damping to velocity
	//4) move camera
	//
	if (car && settings)
	{
		//random values will come handy:


		//check for some exceptions
		if (settings->reverse) //enabled
		{
			if (car->throttle > 0.0) //wanting to go forward
				camera.reverse = false;
			else if (car->throttle < 0.0 && car->velocity < 0.0) //wanting and going backwards
				camera.reverse = true;
		}

		if (settings->in_air) //in air enabled
		{
			if (!(car->sensor1->event) && !(car->sensor2->event)) //in air
			{
				if (camera.in_air) //in ground mode
				{
					//smooth transition between offset and center (and needed)
					if (settings->offset_scale_speed != 0 && camera.offset_scale > 0)
						camera.offset_scale -= (settings->offset_scale_speed*time);
					else //jump directly
						camera.offset_scale = 0;
				}
				if (!camera.in_air) //camera not in "air mode"
				{
					if (camera.air_timer > settings->air_time)
					{
						camera.in_air = true; //go to air mode
						camera.air_timer = 0; //reset timer
					}
					else
						camera.air_timer += time;
				}
			}
			else //not in air
			{
				if (camera.in_air) //camera in "air mode"
				{
					if (camera.air_timer > settings->ground_time)
					{
						camera.in_air = false; //leave air mode
						camera.air_timer = 0; //reset timer
					}
					else
						camera.air_timer += time;
				}
				else //camera in "ground mode"
				{
					//smooth transition between center and offset (and needed)
					if (settings->offset_scale_speed != 0 && camera.offset_scale < 1)
						camera.offset_scale += (settings->offset_scale_speed*time);
					else //jump directly
						camera.offset_scale = 1;
				}
			}
		}


		//store old velocity
		dReal old_vel[3] = {camera.vel[0], camera.vel[1], camera.vel[2]};

		//wanted position of "target" - position on car that should be focused
		dVector3 t_pos;
		//wanted position of camera relative to anchor (translated to world coords)
		dVector3 pos_wanted;

		if (camera.reverse && !camera.in_air) //move target and position to opposite side (if not just spinning in air)
		{
			dBodyGetRelPointPos (car->bodyid, settings->target[0], -settings->target[1], settings->target[2]*car->dir, t_pos);
			dBodyVectorToWorld(car->bodyid, settings->distance[0], -settings->distance[1], settings->distance[2]*car->dir, pos_wanted);
		}
		else //normal
		{
			dBodyGetRelPointPos (car->bodyid, settings->target[0]*camera.offset_scale,
					settings->target[1]*camera.offset_scale, settings->target[2]*car->dir*camera.offset_scale, t_pos);
			dBodyVectorToWorld(car->bodyid, settings->distance[0], settings->distance[1], settings->distance[2]*car->dir, pos_wanted);
		}

		//position and velocity of anchor
		dVector3 a_pos;
		dBodyGetRelPointPos (car->bodyid, settings->anchor[0], settings->anchor[1], settings->anchor[2]*car->dir, a_pos);

		//relative pos and vel of camera (from anchor)
		dReal pos[3] = {camera.pos[0]-a_pos[0], camera.pos[1]-a_pos[1], camera.pos[2]-a_pos[2]};

		//vector lengths
		dReal pos_l = v_length(pos[0], pos[1], pos[2]);
		//how far from car we want to stay
		//(TODO: could be computed just once - only when changing camera)
		dReal pos_wanted_l = v_length(pos_wanted[0], pos_wanted[1], pos_wanted[2]);

		//unit vectors
		dReal pos_u[3] = {pos[0]/pos_l, pos[1]/pos_l, pos[2]/pos_l};
		dReal pos_wanted_u[3] = {pos_wanted[0]/pos_wanted_l, pos_wanted[1]/pos_wanted_l, pos_wanted[2]/pos_wanted_l};


		//
		// 1) spring physics for calculating acceleration
		//

		//"linear spring" between anchor and camera (based on distance)
		dReal dist = pos_l-pos_wanted_l;

		if (settings->linear_stiffness == 0) //disabled smooth movement, jump directly
		{
			//chanses are we have an anchor distance of 0, then vel=0
			if (pos_wanted_l == 0)
			{
				//position at wanted
				camera.pos[0]=a_pos[0];
				camera.pos[1]=a_pos[1];
				camera.pos[2]=a_pos[2];

				//velocity 0
				camera.vel[0]=0;
				camera.vel[1]=0;
				camera.vel[2]=0;
			}
			else
			{
				//set position
				camera.pos[0]-=pos_u[0]*dist;
				camera.pos[1]-=pos_u[1]*dist;
				camera.pos[2]-=pos_u[2]*dist;

				//velocity towards/from anchor = 0
				//vel towards anchor
				dReal dot = (pos_u[0]*camera.vel[0] + pos_u[1]*camera.vel[1] + pos_u[2]*camera.vel[2]);

				//remove vel towards anchor
				camera.vel[0]-=pos_u[0]*dot;
				camera.vel[1]-=pos_u[1]*dot;
				camera.vel[2]-=pos_u[2]*dot;
			}
		}
		else //smooth movement
		{
			//how much acceleration (based on distance from wanted distance)
			dReal acceleration = time*(camera.settings->linear_stiffness)*dist;

			camera.vel[0]-=pos_u[0]*acceleration;
			camera.vel[1]-=pos_u[1]*acceleration;
			camera.vel[2]-=pos_u[2]*acceleration;
		}

		//perpendicular "angular spring" to move camera behind car
		if (pos_wanted_l > 0 && !camera.in_air) //actually got distance, and camera not in "air mode"
		{
			//dot between wanted and current rotation
			dReal dot = (pos_wanted_u[0]*pos_u[0] + pos_wanted_u[1]*pos_u[1] + pos_wanted_u[2]*pos_u[2]);

			if (dot < 1.0) //if we aren't exactly at wanted position (and prevent possibility of acos a number bigger than 1.0)
			{
				//angle
				dReal angle = acos(dot);

				//how much acceleration
				dReal accel = time*angle*(settings->angular_stiffness);

				//direction of acceleration (remove part of wanted that's along current pos)
				dReal dir[3];
				dir[0]=pos_wanted_u[0]-dot*pos_u[0];
				dir[1]=pos_wanted_u[1]-dot*pos_u[1];
				dir[2]=pos_wanted_u[2]-dot*pos_u[2];

				//not unit, get length and modify accel to compensate for not unit
				accel /= v_length(dir[0], dir[1], dir[2]);

				camera.vel[0]+=(accel*dir[0]);
				camera.vel[1]+=(accel*dir[1]);
				camera.vel[2]+=(accel*dir[2]);
			}
		}


		//
		// 2) check for collision, and if so, remove possible movement into collision direction
		//

		if (settings->radius > 0)
		{
			dGeomID geom = dCreateSphere (0, settings->radius);
			dGeomSetPosition(geom, camera.pos[0], camera.pos[1], camera.pos[2]);

			dContactGeom contact[internal.contact_points];
			int count = dCollide ( (dGeomID)(track.object->space), geom, internal.contact_points, &contact[0], sizeof(dContactGeom));

			int i;
			dReal depth;
			dReal V;
			for (i=0; i<count; ++i)
			{
				depth = contact[i].depth;
				camera.pos[0]-=contact[i].normal[0]*depth;
				camera.pos[1]-=contact[i].normal[1]*depth;
				camera.pos[2]-=contact[i].normal[2]*depth;

				//remove movement into colliding object
				//velocity along collision axis
				V = camera.vel[0]*contact[i].normal[0] + camera.vel[1]*contact[i].normal[1] + camera.vel[2]*contact[i].normal[2];
				if (V > 0) //right direction (not away from collision)?
				{
					//remove direction
					camera.vel[0]-=V*contact[i].normal[0];
					camera.vel[1]-=V*contact[i].normal[1];
					camera.vel[2]-=V*contact[i].normal[2];
				}
			}

			dGeomDestroy (geom);
		}

		//
		// 3) damping of current velocity
		//
	
		if (settings->relative_damping)
		{
			//damping (of relative movement)
			dVector3 a_vel; //anchor velocity
			dBodyGetRelPointVel (car->bodyid, settings->anchor[0], settings->anchor[1], settings->anchor[2]*car->dir, a_vel);
			dReal vel[3] = {camera.vel[0]-a_vel[0], camera.vel[1]-a_vel[1], camera.vel[2]-a_vel[2]}; //velocity relative to anchor

			dReal damping = (time*settings->damping);
			if (damping > 1)
				damping=1;

			camera.vel[0]-=damping*vel[0];
			camera.vel[1]-=damping*vel[1];
			camera.vel[2]-=damping*vel[2];
		}
		else
		{
			//absolute damping
			dReal damping = 1-(time*settings->damping);

			if (damping < 0)
				damping=0;

			camera.vel[0]*=damping;
			camera.vel[1]*=damping;
			camera.vel[2]*=damping;
		}

		//
		// 4) movement
		//
	
		//during the step, camera will have linear acceleration from old velocity to new
		//avarge velocity over the step is between new and old velocity
		camera.pos[0]+=((camera.vel[0]+old_vel[0])/2)*time;
		camera.pos[1]+=((camera.vel[1]+old_vel[1])/2)*time;
		camera.pos[2]+=((camera.vel[2]+old_vel[2])/2)*time;


		//movement of camera done.




		//
		//the following is smooth rotation and focusing
		//

		//smooth rotation (if enabled)
		//(move partially from current "up" to car "up", and make unit)

		dReal target_up[3];

		if (camera.in_air) //if in air, use absolute up instead
		{
			target_up[0] = 0;
			target_up[1] = 0;
			target_up[2] = 1;
		}
		else //use car up
		{
			const dReal *rotation = dBodyGetRotation (car->bodyid);
			target_up[0] = rotation[2]*car->dir;
			target_up[1] = rotation[6]*car->dir;
			target_up[2] = rotation[10]*car->dir;
		}

		if (settings->rotation_tightness == 0) //disabled, rotate directly
		{
			camera.up[0]=target_up[0];
			camera.up[1]=target_up[1];
			camera.up[2]=target_up[2];
		}
		else
		{
			dReal diff[3]; //difference between
			diff[0]=target_up[0]-camera.up[0];
			diff[1]=target_up[1]-camera.up[1];
			diff[2]=target_up[2]-camera.up[2];
			
			dReal movement=time*(settings->rotation_tightness);

			if (movement > 1)
				movement=1;

			camera.up[0]+=diff[0]*movement;
			camera.up[1]+=diff[1]*movement;
			camera.up[2]+=diff[2]*movement;

			//gluLookAt wants up to be unit
			dReal length=v_length(camera.up[0], camera.up[1], camera.up[2]);
			camera.up[0]/=length;
			camera.up[1]/=length;
			camera.up[2]/=length;
		}

		//smooth movement of target focus (if enabled)
		if (settings->target_tightness == 0)
		{
			camera.t_pos[0] = t_pos[0];
			camera.t_pos[1] = t_pos[1];
			camera.t_pos[2] = t_pos[2];
		}
		else
		{
			dReal diff[3], movement;

			diff[0]=t_pos[0]-camera.t_pos[0];
			diff[1]=t_pos[1]-camera.t_pos[1];
			diff[2]=t_pos[2]-camera.t_pos[2];

			movement = time*(settings->target_tightness);

			if (movement>1)
				movement=1;

			camera.t_pos[0]+=diff[0]*movement;
			camera.t_pos[1]+=diff[1]*movement;
			camera.t_pos[2]+=diff[2]*movement;
		}

	}
}
// called by Webots at the beginning of the simulation
void webots_physics_init(dWorldID w, dSpaceID s, dJointGroupID j) {

  int i;

  // store global objects for later use
  world = w;
  space = s;
  contact_joint_group = j;

  // get floor geometry
  floor_geom = getGeom(floor_name);
  if (!floor_geom)
    return;

  // get foot geometry and body id's
  for (i = 0; i < N_FEET; i++) {
    foot_geom[i] = getGeom(foot_name[i]);
    if (!foot_geom[i])
      return;
    foot_body[i] = dGeomGetBody(foot_geom[i]);
    if (!foot_body[i])
      return;
  }

  // create universal joints for linear actuators
  for (i = 0; i < 10; i++) {
    dBodyID upper_piston = getBody(upper_piston_name[i]);
    dBodyID lower_piston = getBody(lower_piston_name[i]);
    dBodyID upper_link = getBody(upper_link_name[i]);
    dBodyID lower_link = getBody(lower_link_name[i]);
    if (!upper_piston || !lower_piston || !upper_link || !lower_link)
      return;

    // create a ball and socket joint (3 DOFs) to attach the lower piston body to the lower link 
    // we don't need a universal joint here, because the piston's passive rotation is prevented
    // by the universal joint at its upper end.
    dJointID lower_balljoint = dJointCreateBall(world, 0);
    dJointAttach(lower_balljoint, lower_piston, lower_link);

    // transform attachement point from local to global coordinate system
    // warning: this is a hard-coded translation 
    dVector3 lower_ball;
    dBodyGetRelPointPos(lower_piston, 0, 0, -0.075, lower_ball);

    // set attachement point (anchor)
    dJointSetBallAnchor(lower_balljoint, lower_ball[0], lower_ball[1], lower_ball[2]);
    
    // create a universal joint (2 DOFs) to attach upper piston body to upper link
    // we need to use a universal joint to prevent the piston from passively rotating around its long axis
    dJointID upper_ujoint = dJointCreateUniversal(world, 0);
    dJointAttach(upper_ujoint, upper_piston, upper_link);

    // transform attachement point from local to global coordinate system
    // warning: this is a hard-coded translation 
    dVector3 upper_ball;
    dBodyGetRelPointPos(upper_piston, 0, 0, 0, upper_ball);

    // set attachement point (anchor)
    dJointSetUniversalAnchor(upper_ujoint, upper_ball[0], upper_ball[1], upper_ball[2]);

    // set the universal joint axes
    dVector3 upper_xaxis;
    dVector3 upper_yaxis;
    dBodyVectorToWorld(upper_piston, 1, 0, 0, upper_xaxis);
    dBodyVectorToWorld(upper_piston, 0, 1, 0, upper_yaxis);
    dJointSetUniversalAxis1(upper_ujoint, upper_xaxis[0], upper_xaxis[1], upper_xaxis[2]);
    dJointSetUniversalAxis2(upper_ujoint, upper_yaxis[0], upper_yaxis[1], upper_yaxis[2]);

  }
}
void SimpleTrackedVehicleEnvironment::nearCallbackGrouserTerrain(dGeomID o1, dGeomID o2) {
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    if(b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return;

    // body of the whole vehicle
    dBodyID vehicleBody = ((SimpleTrackedVehicle*)this->v)->vehicleBody;

    unsigned long geom1Categories = dGeomGetCategoryBits(o1);

    // speeds of the belts
    const dReal leftBeltSpeed = ((SimpleTrackedVehicle*)this->v)->leftTrack->getVelocity();
    const dReal rightBeltSpeed = ((SimpleTrackedVehicle*)this->v)->rightTrack->getVelocity();

    dReal beltSpeed = 0; // speed of the belt which is in collision and examined right now
    if (geom1Categories & Category::LEFT) {
        beltSpeed = leftBeltSpeed;
    } else {
        beltSpeed = rightBeltSpeed;
    }

    // the desired linear and angular speeds (set by desired track velocities)
    const dReal linearSpeed = (leftBeltSpeed + rightBeltSpeed) / 2;
    const dReal angularSpeed = (leftBeltSpeed - rightBeltSpeed) * steeringEfficiency / tracksDistance;

    // radius of the turn the robot is doing
    const dReal desiredRotationRadiusSigned = (fabs(angularSpeed) < 0.1) ?
                                                dInfinity : // is driving straight
                                                ((fabs(linearSpeed) < 0.1) ?
                                                    0 : // is rotating about a single point
                                                    linearSpeed / angularSpeed // general movement
                                                );


    dVector3 yAxisGlobal; // vector pointing from vehicle body center in the direction of +y axis
    dVector3 centerOfRotation; // at infinity if driving straight, so we need to distinguish the case
    { // compute the center of rotation
        dBodyVectorToWorld(vehicleBody, 0, 1, 0, yAxisGlobal);

        dCopyVector3(centerOfRotation, yAxisGlobal);
        // make the unit vector as long as we need (and change orientation if needed; the radius is a signed number)
        dScaleVector3(centerOfRotation, desiredRotationRadiusSigned);

        const dReal *vehicleBodyPos = dBodyGetPosition(vehicleBody);
        dAddVectors3(centerOfRotation, centerOfRotation, vehicleBodyPos);
    }

    int maxContacts = 20;
    dContact contact[maxContacts];
    int numContacts = dCollide(o1, o2, maxContacts, &contact[0].geom, sizeof(dContact));

    for(size_t i = 0; i < numContacts; i++) {
        dVector3 contactInVehiclePos; // position of the contact point relative to vehicle body
        dBodyGetPosRelPoint(vehicleBody, contact[i].geom.pos[0], contact[i].geom.pos[1], contact[i].geom.pos[2], contactInVehiclePos);

        dVector3 beltDirection; // vector tangent to the belt pointing in the belt's movement direction
        dCalcVectorCross3(beltDirection, contact[i].geom.normal, yAxisGlobal);
        if (beltSpeed > 0) {
            dNegateVector3(beltDirection);
        }

        if (desiredRotationRadiusSigned != dInfinity) { // non-straight drive

            dVector3 COR2Contact; // vector pointing from the center of rotation to the contact point
            dSubtractVectors3(COR2Contact, contact[i].geom.pos, centerOfRotation);
            // the friction force should be perpendicular to COR2Contact
            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, COR2Contact);

            const dReal linearSpeedSignum = (fabs(linearSpeed) > 0.1) ? sgn(linearSpeed) : 1;

            // contactInVehiclePos[0] > 0 means the contact is in the front part of the track
            if (sgn(angularSpeed) * sgn(dCalcVectorDot3(yAxisGlobal, contact[i].fdir1)) !=
                    sgn(contactInVehiclePos[0]) * linearSpeedSignum) {
                dNegateVector3(contact[i].fdir1);
            }

        } else { // straight drive

            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, yAxisGlobal);

            if (dCalcVectorDot3(contact[i].fdir1, beltDirection) < 0) {
                dNegateVector3(contact[i].fdir1);
            }

        }

        // use friction direction and motion1 to simulate the track movement
        contact[i].surface.mode = dContactFDir1 | dContactMotion1 | dContactMu2;
        contact[i].surface.mu = 0.5;
        contact[i].surface.mu2 = 10;
        // the dot product <beltDirection,fdir1> is the cosine of the angle they form (because both are unit vectors)
        contact[i].surface.motion1 = -dCalcVectorDot3(beltDirection, contact[i].fdir1) * fabs(beltSpeed) * 0.07;

        // friction force visualization
        dMatrix3 forceRotation;
        dVector3 vec;
        dBodyVectorToWorld(vehicleBody, 1, 0, 0, vec);
        dRFrom2Axes(forceRotation, contact[i].fdir1[0], contact[i].fdir1[1], contact[i].fdir1[2], vec[0], vec[1], vec[2]);
        posr data;
        dCopyVector3(data.pos, contact[i].geom.pos);
        dCopyMatrix4x3(data.R, forceRotation);
        forces.push_back(data);

        dJointID c = dJointCreateContact(this->world, this->contactGroup, &contact[i]);
        dJointAttach(c, b1, b2);
        if(!isValidCollision(o1, o2, contact[i]))
            this->badCollision = true;
        if(config.contact_grouser_terrain.debug)
            this->contacts.push_back(contact[i].geom);
    }
}
void PhysicsBody::vectorToWorld(const Vec3f &v, Vec3f &result)
{
    dVector3 t;
    dBodyVectorToWorld(_BodyID, v.x(), v.y(), v.z(), t);
    result.setValue(Vec3f(t[0], t[1], t[2]));
}
Exemple #12
0
void dxPlanarJoint::getInfo2(dReal worldFPS, dReal worldERP, const Info2Descr* info)
{
    /* ====================================================================
     * This joint restricts 2 rotational and 1 translational DOF.
     *
     * The 2 rotational constraints are essentially the same as in dxJointPiston, so the implementation here is mostly
     * just a copy of them.
     *
     * The translational 1DOF constraint has not yet been implemented for any joint in ODE, so we'll talk more about it.
     * It is similar to the constraints in a slider joint, but in this case we only want body2 to move the plane, and
     * body1 anchor has no use in this case, too.
     *
     * We basically want to express the plane in body2 local coordinates (because it should move along with body2), and
     * check, if body1 origin lies in the plane.
     *
     * Let's say n' is the plane normal in body2 coordinates and a' is the anchor point in body2 coordinates
     * (with n, a, being the corresponding global variables).
     * Further, let's call the global position of body1 p1, and similarly p2 for body2.
     * Last, let's call body2 rotation matrix R2 (so that n = R2*n' and a = R2*a' + p2).
     *
     * The plane can then be expressed in global coordinates as:
     * (n^ . x) - (n^ . a) = 0,
     * where x is in global coordinates and ^ denotes vector/matrix transpose.
     *
     * Rewriting the equation using body2 local coordinates and setting x=p1, we get the constraint:
     * (R2*n')^ * p1 - (R2*n')^ * (R2*a' + p2) = 0
     * ...
     * (n'^ * R2^ * p1) - (n'^ * R2^ * p2) - (n'^ * a') = 0
     * (n^ * p1) - (n^ * p2) - (n'^ * a') = 0
     *
     * The part left to "=" will be the "c" on the RHS of the Jacobian equation (because it expresses
     * the distance of p1 from the plane).
     *
     * Next, we need to take time derivative of the constraint to get the J1 and J2 parts.
     * v1, v2, w1 and w2 denote the linear and angular velocities od body1 and body2.
     * [a]x denotes the skew-symmetric cross-product matrix of vector a.
     *
     * d/dt [(n'^ * R2^ * p1) - (n'^ * R2^ * p2) - (n'^ * a') = 0]        (n', a' are constant in time)
     * n'^ * ((d/dt[R2^] * p1) + (R2^ * v1)) - n'^ * ((d/dt[R2^] * p2) + (R2^ * v2)) = 0
     * n'^ * ((([w2]x R2)^ * p1) + (R2^ * v1)) - n'^ * ((([w2]x R2)^ * p2) + (R2^ * v2)) = 0
     * ...
     * n^*v1 - n^*v2 + [n]x (p1 - p2) . w2 = 0
     * -n^*v1 + n^*v2 + [n]x (p2 - p1) . w2 = 0
     *
     * Thus we see that
     * J1l = -n
     * J2l = n
     * J1a = 0
     * J2a = [n]x (p2 - p1)
     * c = eps * ( (n^ * p1) - (n^ * a) )
     *
     */

    const int row0Index = 0;
    const int row1Index = info->rowskip;
    const int row2Index = 2 * row1Index;
    const dReal eps = worldFPS * worldERP;

    dVector3 globalAxis1;
    dBodyVectorToWorld(node[0].body, axis1[0], axis1[1], axis1[2], globalAxis1);

    dVector3 globalAxis2;
    dVector3 globalAnchor;

    if (node[1].body) {
        dBodyVectorToWorld(node[1].body, axis2[0], axis2[1], axis2[2], globalAxis2);
        dBodyGetRelPointPos(node[1].body, anchor2[0], anchor2[1], anchor2[2], globalAnchor);
    } else {
        dCopyVector3(globalAxis2, axis2);
        dCopyVector3(globalAnchor, anchor2);
    }

    ///////////////////////////////////////////////////////
    // Angular velocity constraints (2 rows)
    //
    // Refer to the piston joint source code for details.
    ///////////////////////////////////////////////////////

    // Find the 2 direction vectors of the plane.
    dVector3 p, q;
    dPlaneSpace ( globalAxis2, p, q );

    // LHS 0
    dCopyNegatedVector3 (info->J1a + row0Index, p );
    dCopyNegatedVector3 (info->J1a + row1Index, q );

    // LHS 1
    dCopyVector3 (info->J2a + row0Index, p );
    dCopyVector3 (info->J2a + row1Index, q );

    // RHS 0 & 1 (absolute errors of the axis direction computed by dot product of the desired and actual axis)
    dVector3 b;
    dCalcVectorCross3( b, globalAxis2, globalAxis1 );
    info->c[0] = eps * dCalcVectorDot3 ( p, b );
    info->c[1] = eps * dCalcVectorDot3 ( q, b );

    //////////////////////////////////////////////////////////////////////////////////////////
    // Linear velocity constraint (1 row, removes 1 translational DOF along the plane normal)
    //
    // Only body1 should be restricted by the plane, which is moved along with body2.
    //////////////////////////////////////////////////////////////////////////////////////////

    dVector3 body1Center;
    dCopyVector3(body1Center, node[0].body->posr.pos);

    dVector3 body2Center = {0, 0, 0};
    if (node[1].body) {
        dCopyVector3(body2Center, node[1].body->posr.pos);
    }

    // LHS 2
    dCopyNegatedVector3(info->J1l + row2Index, globalAxis2);
    dCopyVector3(       info->J2l + row2Index, globalAxis2);

    dVector3 body2_body1;
    dSubtractVectors3(body2_body1, body2Center, body1Center);
    dCalcVectorCross3(info->J2a + row2Index, globalAxis2, body2_body1);

    // RHS 2 (distance of body1 center from the plane)
    info->c[2] = eps * (dCalcVectorDot3(globalAxis2, body1Center) - dCalcVectorDot3(globalAxis2, globalAnchor));
}