Ejemplo n.º 1
0
dReal dJointGetPUPositionRate( dJointID j )
{
    dxJointPU* joint = ( dxJointPU* ) j;
    dUASSERT( joint, "bad joint argument" );
    checktype( joint, PU );

    if ( joint->node[0].body )
    {
        // We want to find the rate of change of the prismatic part of the joint
        // We can find it by looking at the speed difference between body1 and the
        // anchor point.

        // r will be used to find the distance between body1 and the anchor point
        dVector3 r;
        dVector3 anchor2 = {0,0,0};
        if ( joint->node[1].body )
        {
            // Find joint->anchor2 in global coordinates
            dMultiply0_331( anchor2, joint->node[1].body->posr.R, joint->anchor2 );

            r[0] = ( joint->node[0].body->posr.pos[0] -
                ( anchor2[0] + joint->node[1].body->posr.pos[0] ) );
            r[1] = ( joint->node[0].body->posr.pos[1] -
                ( anchor2[1] + joint->node[1].body->posr.pos[1] ) );
            r[2] = ( joint->node[0].body->posr.pos[2] -
                ( anchor2[2] + joint->node[1].body->posr.pos[2] ) );
        }
        else
        {
            //N.B. When there is no body 2 the joint->anchor2 is already in
            //     global coordinates
            // r = joint->node[0].body->posr.pos -  joint->anchor2;
            dSubtractVectors3( r, joint->node[0].body->posr.pos, joint->anchor2 );
        }

        // The body1 can have velocity coming from the rotation of
        // the rotoide axis. We need to remove this.

        // N.B. We do vel = r X w instead of vel = w x r to have vel negative
        //      since we want to remove it from the linear velocity of the body
        dVector3 lvel1;
        dCalcVectorCross3( lvel1, r, joint->node[0].body->avel );

        // lvel1 += joint->node[0].body->lvel;
        dAddVectors3( lvel1, lvel1, joint->node[0].body->lvel );

        // Since we want rate of change along the prismatic axis
        // get axisP1 in global coordinates and get the component
        // along this axis only
        dVector3 axP1;
        dMultiply0_331( axP1, joint->node[0].body->posr.R, joint->axisP1 );

        if ( joint->node[1].body )
        {
            // Find the contribution of the angular rotation to the linear speed
            // N.B. We do vel = r X w instead of vel = w x r to have vel negative
            //      since we want to remove it from the linear velocity of the body
            dVector3 lvel2;
            dCalcVectorCross3( lvel2, anchor2, joint->node[1].body->avel );

            // lvel1 -=  lvel2 + joint->node[1].body->lvel;
            dVector3 tmp;
            dAddVectors3( tmp, lvel2, joint->node[1].body->lvel );
            dSubtractVectors3( lvel1, lvel1, tmp );

            return dCalcVectorDot3( axP1, lvel1 );
        }
        else
        {
            dReal rate = dCalcVectorDot3( axP1, lvel1 );
            return ( (joint->flags & dJOINT_REVERSE) ? -rate : rate);
        }
    }

    return 0.0;
}
Ejemplo n.º 2
0
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);
    }
}
Ejemplo n.º 3
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]);
}
Ejemplo n.º 4
0
void start()
{
    world = dWorldCreate();
    dWorldSetGravity (world,0,0,-9.8);

    contact_group = dJointGroupCreate(0);

    space = dSimpleSpaceCreate (0);


    // first, the ground plane
    // it has to coincide with the plane we have in drawstuff
    ground = dCreatePlane(space, 0, 0, 1, 0);


    // now a ball
    dMass m;
    dMassSetSphere(&m, 0.1, ball_radius);

    ball1_geom = dCreateSphere(space, ball_radius);
    ball1_body = dBodyCreate(world);
    dGeomSetBody(ball1_geom, ball1_body);
    dBodySetMass(ball1_body, &m);

    ball2_geom = dCreateSphere(space, ball_radius);
    ball2_body = dBodyCreate(world);
    dGeomSetBody(ball2_geom, ball2_body);
    dBodySetMass(ball2_body, &m);




    // tracks made out of boxes
    dGeomID trk;
    dMatrix3 r1, r2, r3;
    dVector3 ro = {0, -(0.5*track_gauge + 0.5*track_width), track_elevation};
    dMatrix3 s1, s2, s3;
    dVector3 so = {0, 0.5*track_gauge + 0.5*track_width, track_elevation};

    dRFromAxisAndAngle(r1, 1, 0, 0,  track_angle);
    dRFromAxisAndAngle(r2, 0, 1, 0, -track_incl);
    dMultiply0_333(r3, r2, r1);

    dRFromAxisAndAngle(s1, 1, 0, 0, -track_angle);
    dRFromAxisAndAngle(s2, 0, 1, 0, -track_incl);
    dMultiply0_333(s3, s2, s1);

    trk = dCreateBox(space, track_len, track_width, track_height);
    dGeomSetPosition(trk, ro[0], ro[1] + balls_sep, ro[2]);
    dGeomSetRotation(trk, r3);

    trk = dCreateBox(space, track_len, track_width, track_height);
    dGeomSetPosition(trk, so[0], so[1] + balls_sep, so[2]);
    dGeomSetRotation(trk, s3);



    

    // tracks made out of trimesh
    for (unsigned i=0; i<n_box_verts; ++i) {
        dVector3 p;
        dMultiply0_331(p, s3, box_verts[i]);
        dAddVectors3(p, p, so);
        dCopyVector3(track_verts[i], p);
    }
    // trimesh tracks 2, transform all vertices by s3
    for (unsigned i=0; i<n_box_verts; ++i) {
        dVector3 p;
        dMultiply0_331(p, r3, box_verts[i]);
        dAddVectors3(p, p, ro);
        dCopyVector3(track_verts[n_box_verts + i], p);
    }

    // copy face indices
    for (unsigned i=0; i<n_box_faces; ++i)
        for (unsigned j=0; j<3; ++j) // each face index
            track_faces[3*i+j] = box_faces[3*i+j];
    for (unsigned i=0; i<n_box_faces; ++i)
        for (unsigned j=0; j<3; ++j) // each face index
            track_faces[3*(i + n_box_faces)+j] = box_faces[3*i+j] + n_box_verts;

    mesh_data = dGeomTriMeshDataCreate();
    dGeomTriMeshDataBuildSimple(mesh_data,
                                track_verts[0], n_track_verts,
                                track_faces, 3*n_track_faces);
    mesh_geom = dCreateTriMesh(space, mesh_data, 0, 0, 0);





    resetSim();
    

    // initial camera position
    static float xyz[3] = {-5.9414,-0.4804,2.9800};
    static float hpr[3] = {32.5000,-10.0000,0.0000};
    dsSetViewpoint (xyz,hpr);

    dsSetSphereQuality(3);
}