VRPN main page

Obtaining VRPN

VRPN Support

Installing and Testing

Compiling and Modifying

Client code

Server code

Troubleshooting

Connections

Logging and Playback

Shared Objects

Clock Synchronization

Coming attractions & suggestions

UNC-specific information

Table of Contents

#define  FORCEDEVICE_H

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

#define	FORCE_DEVICE_READY  0
#define FORCE_DEVICE_BROKEN 1

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

// for recovery:
#define DEFAULT_NUM_REC_CYCLES	(10)

// number of floating point values encoded in a message
#define NUM_MESSAGE_PARAMETERS (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

class vrpn_ForceDevice {
public:
	vrpn_ForceDevice(char * name, vrpn_Connection *c);
	virtual void mainloop(void) = 0;
	void print_report(void);
	void print_plane(void);

	void setSurfaceKspring(float k) { 
					SurfaceKspring = k; }
	void setSurfaceKdamping(float d) {SurfaceKdamping =d;}
	void setSurfaceFstatic(float ks) {SurfaceFstatic = ks;}
	void setSurfaceFdynamic(float kd) {SurfaceFdynamic =kd;}
	void setRecoveryTime(int rt) {numRecCycles = rt;}
	void setFF_Origin(float x, float y, float z) {
		ff_origin[0] = x;ff_origin[1] = y; ff_origin[2] = z;}
	void setFF_Force(float fx, float fy, float fz) {
		ff_force[0] = fx; ff_force[1] = fy; ff_force[2] = fz;}
	void setFF_Jacobian(float dfxdx, float dfxdy, float dfxdz,
				float dfydx, float dfydy, float dfydz,
				float dfzdx, float dfzdy, float 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(float r) { ff_radius = r;};
	int getRecoveryTime(void) {return numRecCycles;}
	int connectionAvailable(void) {return (connection != NULL);}

protected:
	vrpn_Connection *connection;		// Used to send messages
	int status;  //status of force device
//	virtual void get_report(void) = 0;
	virtual int encode_to(char *buf);
	virtual int encode_scp_to(char *buf);

	struct timeval timestamp;
	long my_id;		// ID of this force device to connection
	long force_message_id;	// ID of force message to connection
	long plane_message_id;  //ID of plane equation message
	long forcefield_message_id; 	// ID of force field message
	long scp_message_id;	// ID of surface contact point message

	// XXX - error messages should be put into the vrpn base class 
	// whenever someone makes one
	long error_message_id;	// ID of force device error message

        // IDs for trimesh messages
        long setVertex_message_id;   
        long setNormal_message_id;   
        long setTriangle_message_id;   
        long removeTriangle_message_id;   
        long updateTrimeshChanges_message_id;   
        long transformTrimesh_message_id;    
        long setTrimeshType_message_id;    
        long clearTrimesh_message_id;    

	long set_constraint_message_id;

	int   which_plane;
	double force[3];
	double scp_pos[3];
	double scp_quat[4];  // I think this would only be used on 6DOF device
	float plane[4];

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

	float SurfaceKspring;
	float SurfaceKdamping;
	float SurfaceFstatic;
	float SurfaceFdynamic;
	int numRecCycles;
	int errorCode;

};

// 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
	double		pos[3];			// position of SCP
	double		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
	double		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
	int		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
	vrpn_ForceDevice_Remote(char *name);
 	void set_plane(float *p);
	void set_plane(float *p, float d);
	void set_plane(float a, float b, float c,float d);

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

        // vertNum normNum and triNum start at 0
        void setVertex(int vertNum,float x,float y,float z);
        // NOTE: ghost dosen't take normals, 
        //       and normals still aren't implemented for Hcollide
        void setNormal(int normNum,float x,float y,float z);
        void setTriangle(int triNum,int vert0,int vert1,int vert2,
			  int norm0=-1,int norm1=-1,int norm2=-1);
        void removeTriangle(int 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(float homMatrix[16]);
  	void clearTrimesh(void);
  
        // the next time we send a trimesh we will use the following type
        void useHcollide();
        void useGhost();

	void sendConstraint(int enable, float x, float y, float z, float kSpr);

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

	char *encode_plane(int &len);
        char *encode_vertex(int &len,int vertNum,float x,float y,float z); 
        char *encode_normal(int &len,int vertNum,float x,float y,float z); 
        char *encode_triangle(int &len,int triNum,
			      int vert0,int vert1,int vert2,
			      int norm0,int norm1,int norm2);	       
        char *encode_removeTriangle(int &len,int triNum);
        char *encode_updateTrimeshChanges(int &len);
        char *encode_setTrimeshType(int &len,int type);
        char *encode_trimeshTransform(int &len,float homMatrix[16]);

	char *encode_constraint(int &len, int enable, float x, float y, float z,
				float kSpr);
	char *encode_forcefield(int &len, float origin[3],
		float force[3], float jacobian[3][3], float radius);
	// This routine calls the mainloop of the connection it's own
	virtual void mainloop(void);

	// (un)Register a callback handler to handle a force change
	// and plane equation change and trimesh change
	virtual int register_change_handler(void *userdata,
		vrpn_FORCECHANGEHANDLER handler);
	virtual int unregister_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_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);
};

#endif