Main Page   Class Hierarchy   Compound List   File List   Header Files   Compound Members   File Members  

vrpn_ForceDevice.h

This is the verbatim text of the vrpn_ForceDevice.h include file.
#ifndef FORCEDEVICE_H
#define  FORCEDEVICE_H

#include "vrpn_Connection.h"
#include "vrpn_BaseClass.h"
#include "vrpn_Tracker.h"
#include "vrpn_Button.h"

#define MAXPLANE 4   //maximum number of planes in the scene 

// for recovery:
#define DEFAULT_NUM_REC_CYCLES  (10)

// possible values for errorCode:
#define FD_VALUE_OUT_OF_RANGE 0 // surface parameter out of range
#define FD_DUTY_CYCLE_ERROR 1   // servo loop is taking too long
#define FD_FORCE_ERROR 2        // max force exceeded, or motors overheated
                                // or amplifiers not enabled
#define FD_MISC_ERROR 3         // everything else
#define FD_OK 4 // no error

// If defined, springs are implemented in the client as force fields.
// If not, springs are implemented with special messages
// and extra Ghost classes.  Either way support for the messages
// is compiled into the parent class so that servers can support
// both kinds of clients.

// (Springs as force fields require some knotty mathematical programming
// at the clients that I can't seem to get right, but avoid lots of
// extra message types and an awful lot of bug-prone Ghost.)

#define FD_SPRINGS_AS_FIELDS


class vrpn_ForceDevice : public vrpn_BaseClass {

  public:

    vrpn_ForceDevice (const char * name, vrpn_Connection *c);
    virtual ~vrpn_ForceDevice (void);

    void print_report (void);
    void print_plane (void);

    void setSurfaceKspring (vrpn_float32 k) { SurfaceKspring = k; }
    void setSurfaceKdamping (vrpn_float32 d) { SurfaceKdamping =d; }
    void setSurfaceFstatic (vrpn_float32 ks) { SurfaceFstatic = ks; }
    void setSurfaceFdynamic (vrpn_float32 kd) { SurfaceFdynamic =kd; }
    void setRecoveryTime (int rt) { numRecCycles = rt; }

    // additional surface properties
    void setSurfaceKadhesionNormal (vrpn_float32 k)
           { SurfaceKadhesionNormal = k; }
    void setSurfaceKadhesionLateral (vrpn_float32 k) 
           { SurfaceKadhesionLateral = k; }
    void setSurfaceBuzzFrequency (vrpn_float32 freq)
           { SurfaceBuzzFreq = freq; }
    void setSurfaceBuzzAmplitude (vrpn_float32 amp)
           { SurfaceBuzzAmp = amp; }
    void setSurfaceTextureWavelength (vrpn_float32 wl) 
           { SurfaceTextureWavelength = wl; }
    void setSurfaceTextureAmplitude (vrpn_float32 amp) 
           { SurfaceTextureAmplitude = amp; }

    void setFF_Origin (vrpn_float32 x, vrpn_float32 y, vrpn_float32 z)
           { ff_origin[0] = x; ff_origin[1] = y; ff_origin[2] = z; }
    void setFF_Origin (vrpn_float32 x [3])
           { ff_origin[0] = x[0]; ff_origin[1] = x[1]; ff_origin[2] = x[2]; }
    void setFF_Force (vrpn_float32 fx, vrpn_float32 fy, vrpn_float32 fz)
           { ff_force[0] = fx; ff_force[1] = fy; ff_force[2] = fz; }
    void setFF_Force (vrpn_float32 f [3])
           { ff_force[0] = f[0]; ff_force[1] = f[1]; ff_force[2] = f[2]; }
    void setFF_Jacobian
             (vrpn_float32 dfxdx, vrpn_float32 dfxdy, vrpn_float32 dfxdz,
              vrpn_float32 dfydx, vrpn_float32 dfydy, vrpn_float32 dfydz,
              vrpn_float32 dfzdx, vrpn_float32 dfzdy, vrpn_float32 dfzdz)
           { ff_jacobian[0][0] = dfxdx; ff_jacobian[0][1] = dfxdy;
             ff_jacobian[0][2] = dfxdz; ff_jacobian[1][0] = dfydx;
             ff_jacobian[1][1] = dfydy; ff_jacobian[1][2] = dfydz;
             ff_jacobian[2][0] = dfzdx; ff_jacobian[2][1] = dfzdy;
             ff_jacobian[2][2] = dfzdz; }
    void setFF_Radius (vrpn_float32 r) { ff_radius = r; }

    void set_plane (vrpn_float32 *p);
    void set_plane (vrpn_float32 *p, vrpn_float32 d);
    void set_plane (vrpn_float32 a, vrpn_float32 b, vrpn_float32 c,
                    vrpn_float32 d);

    void sendError (int error_code);

    int getRecoveryTime (void) {return numRecCycles;}
    int connectionAvailable (void) {return (d_connection != NULL);}

    // constants for constraint messages

    enum ConstraintGeometry
            { NO_CONSTRAINT,
              POINT_CONSTRAINT,
              LINE_CONSTRAINT,
              PLANE_CONSTRAINT };

  protected:

    virtual int register_types(void);

    vrpn_int32 force_message_id;        // ID of force message to connection
    vrpn_int32 plane_message_id;        //ID of plane equation message
        vrpn_int32 plane_effects_message_id; // additional plane properties
    vrpn_int32 forcefield_message_id;   // ID of force field message
    vrpn_int32 scp_message_id;          // ID of surface contact point message


    // constraint messages

    vrpn_int32 enableConstraint_message_id;
    vrpn_int32 setConstraintMode_message_id;
    vrpn_int32 setConstraintPoint_message_id;
    vrpn_int32 setConstraintLinePoint_message_id;
    vrpn_int32 setConstraintLineDirection_message_id;
    vrpn_int32 setConstraintPlanePoint_message_id;
    vrpn_int32 setConstraintPlaneNormal_message_id;
    vrpn_int32 setConstraintKSpring_message_id;
    //vrpn_int32 set_constraint_message_id;// ID of constraint force message

    // XXX - error messages should be put into the vrpn base class 
    // whenever someone makes one

    vrpn_int32 error_message_id;        // ID of force device error message

    // IDs for trimesh messages

    vrpn_int32 setVertex_message_id;   
    vrpn_int32 setNormal_message_id;   
    vrpn_int32 setTriangle_message_id;   
    vrpn_int32 removeTriangle_message_id;   
    vrpn_int32 updateTrimeshChanges_message_id;   
    vrpn_int32 transformTrimesh_message_id;    
    vrpn_int32 setTrimeshType_message_id;    
    vrpn_int32 clearTrimesh_message_id;    

    // ENCODING
    static char *encode_force(vrpn_int32 &length, const vrpn_float64 *force);
    static char *encode_scp(vrpn_int32 &length,
            const vrpn_float64 *pos, const vrpn_float64 *quat);
    static char *encode_plane(vrpn_int32 &length,const vrpn_float32 *plane, 
                            const vrpn_float32 kspring, const vrpn_float32 kdamp,
                            const vrpn_float32 fdyn, const vrpn_float32 fstat, 
                            const vrpn_int32 plane_index, const vrpn_int32 n_rec_cycles);
    static char *encode_surface_effects(vrpn_int32 &len, 
                        const vrpn_float32 k_adhesion_norm, 
                        const vrpn_float32 k_adhesion_lat,
                    const vrpn_float32 tex_amp, const vrpn_float32 tex_wl,
                    const vrpn_float32 buzz_amp, const vrpn_float32 buzz_freq);
    static char *encode_vertex(vrpn_int32 &len, const vrpn_int32 vertNum,
                const vrpn_float32 x,const vrpn_float32 y,const vrpn_float32 z); 
    static char *encode_normal(vrpn_int32 &len,const vrpn_int32 vertNum,
                const vrpn_float32 x,const vrpn_float32 y,const vrpn_float32 z); 
    static char *encode_triangle(vrpn_int32 &len,const vrpn_int32 triNum,
              const vrpn_int32 vert0,const vrpn_int32 vert1,const vrpn_int32 vert2,
              const vrpn_int32 norm0,const vrpn_int32 norm1,const vrpn_int32 norm2);           
    static char *encode_removeTriangle(vrpn_int32 &len,const vrpn_int32 triNum);
    static char *encode_updateTrimeshChanges(vrpn_int32 &len,
                const vrpn_float32 kspring, const vrpn_float32 kdamp,
                const vrpn_float32 fdyn, const vrpn_float32 fstat);
    static char *encode_setTrimeshType(vrpn_int32 &len,const vrpn_int32 type);
    static char *encode_trimeshTransform(vrpn_int32 &len,
                const vrpn_float32 homMatrix[16]);

    static char *encode_forcefield(vrpn_int32 &len, const vrpn_float32 origin[3],
        const vrpn_float32 force[3], const vrpn_float32 jacobian[3][3], const vrpn_float32 radius);
    static char *encode_error(vrpn_int32 &len, const vrpn_int32 error_code);


    // DECODING
    static vrpn_int32 decode_force (const char *buffer, const vrpn_int32 len, 
                                                        vrpn_float64 *force);
    static vrpn_int32 decode_scp(const char *buffer, const vrpn_int32 len,
                                        vrpn_float64 *pos, vrpn_float64 *quat);
    static vrpn_int32 decode_plane(const char *buffer, const vrpn_int32 len,
            vrpn_float32 *plane, 
            vrpn_float32 *kspring, vrpn_float32 *kdamp,vrpn_float32 *fdyn, vrpn_float32 *fstat, 
            vrpn_int32 *plane_index, vrpn_int32 *n_rec_cycles);
    static vrpn_int32 decode_surface_effects(const char *buffer,
            const vrpn_int32 len, vrpn_float32 *k_adhesion_norm,
            vrpn_float32 *k_adhesion_lat,
                vrpn_float32 *tex_amp, vrpn_float32 *tex_wl,
            vrpn_float32 *buzz_amp, vrpn_float32 *buzz_freq);
    static vrpn_int32 decode_vertex(const char *buffer, const vrpn_int32 len,
                vrpn_int32 *vertNum,
                vrpn_float32 *x,vrpn_float32 *y,vrpn_float32 *z); 
    static vrpn_int32 decode_normal(const char *buffer,const vrpn_int32 len,
                vrpn_int32 *vertNum,vrpn_float32 *x,vrpn_float32 *y,vrpn_float32 *z); 
    static vrpn_int32 decode_triangle(const char *buffer,const vrpn_int32 len,vrpn_int32 *triNum,
                vrpn_int32 *vert0,vrpn_int32 *vert1,vrpn_int32 *vert2,
                vrpn_int32 *norm0,vrpn_int32 *norm1,vrpn_int32 *norm2);        
    static vrpn_int32 decode_removeTriangle(const char *buffer,const vrpn_int32 len,
                                                vrpn_int32 *triNum);
    static vrpn_int32 decode_updateTrimeshChanges(const char *buffer,const vrpn_int32 len,
                vrpn_float32 *kspring, vrpn_float32 *kdamp, vrpn_float32 *fdyn, vrpn_float32 *fstat);
    static vrpn_int32 decode_setTrimeshType(const char *buffer,const vrpn_int32 len,
                                                vrpn_int32 *type);
    static vrpn_int32 decode_trimeshTransform(const char *buffer,const vrpn_int32 len,
                                                vrpn_float32 homMatrix[16]);

    static vrpn_int32 decode_forcefield(const char *buffer,const vrpn_int32 len,
        vrpn_float32 origin[3], vrpn_float32 force[3], vrpn_float32 jacobian[3][3], vrpn_float32 *radius);
    static vrpn_int32 decode_error(const char *buffer, const vrpn_int32 len, 
                vrpn_int32 *error_code);

    // constraint encoding & decoding

    static char * encode_enableConstraint
                   (vrpn_int32 & len,
                    vrpn_int32 enable);
    static vrpn_int32 decode_enableConstraint
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_int32 * enable);
                         
    static char * encode_setConstraintMode
                   (vrpn_int32 & len,
                    ConstraintGeometry mode);
    static vrpn_int32 decode_setConstraintMode
                   (const char * buffer,
                    const vrpn_int32 len,
                    ConstraintGeometry * mode);
                         
    static char * encode_setConstraintPoint
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decode_setConstraintPoint
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);
                         
    static char * encode_setConstraintLinePoint
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decode_setConstraintLinePoint
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);
                         
    static char * encode_setConstraintLineDirection
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decode_setConstraintLineDirection
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);
                         
    static char * encode_setConstraintPlanePoint
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decode_setConstraintPlanePoint
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);
                         
    static char * encode_setConstraintPlaneNormal
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decode_setConstraintPlaneNormal
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);
                         
    static char * encode_setConstraintKSpring
                   (vrpn_int32 & len,
                    vrpn_float32 k);
    static vrpn_int32 decode_setConstraintKSpring
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * k);

    // utility functions

    static char * encodePoint
                   (vrpn_int32 & len,
                    vrpn_float32 x, vrpn_float32 y, vrpn_float32 z);
    static vrpn_int32 decodePoint
                   (const char * buffer,
                    const vrpn_int32 len,
                    vrpn_float32 * x, vrpn_float32 * y, vrpn_float32 * z);


    struct timeval timestamp;

    vrpn_int32   which_plane;

    vrpn_float64 d_force [3];

    vrpn_float64 scp_pos [3];
    vrpn_float64 scp_quat [4];  // for torque
    vrpn_float32 plane [4];

    vrpn_float32 ff_origin [3];
    vrpn_float32 ff_force [3];
    vrpn_float32 ff_jacobian [3][3]; // J[i][j] = dF[i]/dx[j]
    vrpn_float32 ff_radius;

    vrpn_float32 SurfaceKspring;
    vrpn_float32 SurfaceKdamping;
    vrpn_float32 SurfaceFstatic;
    vrpn_float32 SurfaceFdynamic;
    vrpn_int32 numRecCycles;
    vrpn_int32 errorCode;

    vrpn_float32 SurfaceKadhesionLateral;
    vrpn_float32 SurfaceKadhesionNormal;
    vrpn_float32 SurfaceBuzzFreq;
    vrpn_float32 SurfaceBuzzAmp;
    vrpn_float32 SurfaceTextureWavelength;
    vrpn_float32 SurfaceTextureAmplitude;
};

// User routine to handle position reports for surface contact point (SCP)
// This is in vrpn_ForceDevice rather than vrpn_Tracker because only
// a force feedback device should know anything about SCPs as this is a
// part of the force feedback model. It may be preferable to use the SCP
// rather than the tracker position for graphics so the hand position
// doesn't appear to go below the surface making the surface look very
// compliant. 
typedef struct {
        struct          timeval msg_time;       // Time of the report
        vrpn_float64    pos[3];                 // position of SCP
        vrpn_float64    quat[4];                // orientation of SCP
} vrpn_FORCESCPCB;
typedef void (*vrpn_FORCESCPHANDLER) (void *userdata,
                                        const vrpn_FORCESCPCB info);

typedef struct {
        struct          timeval msg_time;       // Time of the report
        vrpn_float64    force[3];               // force value
} vrpn_FORCECB;
typedef void (*vrpn_FORCECHANGEHANDLER)(void *userdata,
                                         const vrpn_FORCECB info);

typedef struct {
        struct          timeval msg_time;       // time of the report
        vrpn_int32              error_code;             // type of error
} vrpn_FORCEERRORCB;
typedef void (*vrpn_FORCEERRORHANDLER) (void *userdata,
                                        const vrpn_FORCEERRORCB info);

class vrpn_ForceDevice_Remote: public vrpn_ForceDevice {
public:

    // The name of the force device to connect to.
    // The connection argument is used only if you already have a connection
    // the device must listen on (it is not normally used).
    vrpn_ForceDevice_Remote(const char *name, vrpn_Connection *cn = NULL);
    virtual ~vrpn_ForceDevice_Remote (void);

    void sendSurface(void);
    void startSurface(void);
    void stopSurface(void);

    // vertNum normNum and triNum start at 0
    void setVertex(vrpn_int32 vertNum,vrpn_float32 x,vrpn_float32 y,vrpn_float32 z);
    // NOTE: ghost dosen't take normals, 
    //       and normals still aren't implemented for Hcollide
    void setNormal(vrpn_int32 normNum,vrpn_float32 x,vrpn_float32 y,vrpn_float32 z);
    void setTriangle(vrpn_int32 triNum,vrpn_int32 vert0,vrpn_int32 vert1,vrpn_int32 vert2,
                  vrpn_int32 norm0=-1,vrpn_int32 norm1=-1,vrpn_int32 norm2=-1);
    void removeTriangle(vrpn_int32 triNum); 
    // should be called to incorporate the above changes into the 
    // displayed trimesh 
    void updateTrimeshChanges();
    // set the trimesh's homogen transform matrix (in row major order)
    void setTrimeshTransform(vrpn_float32 homMatrix[16]);
        void clearTrimesh(void);
  
    // the next time we send a trimesh we will use the following type
    void useHcollide();
    void useGhost();

    // Generalized constraint code.
    // Constrains as a spring connected to a point, sliding along a line
    // (constraint forces in a plane perpendicular to the line), or
    // sliding along a plane (constraint forces only along the plane's
    // normal).  LineDirection and PlaneNormal should be normalized
    // (vector length == 1).

    // Constraints are implemented as force fields, so both cannot
    // run at once.

    // XXX it would be safer if changes (especially enable/disable)
    // had better relaxation support

    void enableConstraint (vrpn_int32 enable);  // zero disables
    void setConstraintMode (ConstraintGeometry mode);
    void setConstraintPoint (vrpn_float32 point [3]);
    void setConstraintLinePoint (vrpn_float32 point [3]);
    void setConstraintLineDirection (vrpn_float32 direction [3]);
    void setConstraintPlanePoint (vrpn_float32 point [3]);
    void setConstraintPlaneNormal (vrpn_float32 normal [3]);
    void setConstraintKSpring (vrpn_float32 k);

    //void sendConstraint (vrpn_int32 enable, vrpn_float32 x,
                         //vrpn_float32 y, vrpn_float32 z, vrpn_float32 kSpr);

    // At the <origin> of the field, user feels the specified <force>.
    // As the user moves away from the origin, the force felt changes
    // according to the jacobian.  If the user moves further than <radius>
    // from <origin>, the field cuts out.

    // XXX it would be safer for the field to attenuate rapidly
    // from the value at the radius if the user moves beyond the radius

    void sendForceField
           (vrpn_float32 origin [3], vrpn_float32 force [3],
            vrpn_float32 jacobian [3][3], vrpn_float32 radius);
    void sendForceField (void);
    void stopForceField (void);

    // This routine calls the mainloop of the connection it is on
    virtual void mainloop ();

    // (un)Register a callback handler to handle a force change
    // and plane equation change and trimesh change
    virtual int register_force_change_handler(void *userdata,
            vrpn_FORCECHANGEHANDLER handler);
    virtual int unregister_force_change_handler(void *userdata,
            vrpn_FORCECHANGEHANDLER handler);

    virtual int register_scp_change_handler(void *userdata,
            vrpn_FORCESCPHANDLER handler);
    virtual int unregister_scp_change_handler(void *userdata,
            vrpn_FORCESCPHANDLER handler);

    virtual int register_error_handler(void *userdata,
            vrpn_FORCEERRORHANDLER handler);
    virtual int unregister_error_handler(void *userdata,
            vrpn_FORCEERRORHANDLER handler);
protected:

    typedef     struct vrpn_RFCS {
            void                                *userdata;
            vrpn_FORCECHANGEHANDLER     handler;
            struct vrpn_RFCS            *next;
    } vrpn_FORCECHANGELIST;
    vrpn_FORCECHANGELIST        *change_list;
    static int handle_force_change_message(void *userdata,vrpn_HANDLERPARAM p);

    typedef struct vrpn_RFSCPCS {
            void                            *userdata;
            vrpn_FORCESCPHANDLER handler;
            struct vrpn_RFSCPCS         *next;
    } vrpn_FORCESCPCHANGELIST;
    vrpn_FORCESCPCHANGELIST     *scp_change_list;
    static int handle_scp_change_message(void *userdata,
                                                    vrpn_HANDLERPARAM p);
    typedef struct vrpn_RFERRCS {
            void                                *userdata;
            vrpn_FORCEERRORHANDLER handler;
            struct vrpn_RFERRCS         *next;
    } vrpn_FORCEERRORCHANGELIST;
    vrpn_FORCEERRORCHANGELIST *error_change_list;
    static int handle_error_change_message(void *userdata,
                                                    vrpn_HANDLERPARAM p);

    // constraint types

    vrpn_int32 d_conEnabled;
    ConstraintGeometry d_conMode;
    vrpn_float32 d_conPoint [3];
    vrpn_float32 d_conLinePoint [3];
    vrpn_float64 d_conLineDirection [3];  // (assumed) normalized
    vrpn_float32 d_conPlanePoint [3];
    vrpn_float64 d_conPlaneNormal [3];  // (assumed) normalized
    vrpn_float32 d_conKSpring;

    // utility functions

    void send (const char * msgbuf, vrpn_int32 len, vrpn_int32 type);
      // Takes a pointer to a buffer, the length of the buffer, and the
      // vrpn message type id to send.  Sends the buffer reliably
      // over connection AND DELETES THE BUFFER.

#ifdef FD_SPRINGS_AS_FIELDS

    void constraintToForceField (void);
      // takes the current cs_* settings and translates them into
      // a force field.

#endif  // FD_SPRINGS_AS_FIELDS

};

#endif




Generated at Fri Sep 13 15:04:12 2002 for vrpn by doxygen 1.0.0 written by Dimitri van Heesch, © 1997-1999