00001 /* 00002 00003 The contents of this file are subject to the Mozilla Public License 00004 Version 1.1 (the "License"); you may not use this file except in 00005 compliance with the License. You may obtain a copy of the License at 00006 http://www.mozilla.org/MPL/ 00007 00008 Software distributed under the License is distributed on an "AS IS" 00009 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 00010 License for the specific language governing rights and limitations 00011 under the License. 00012 00013 The Original Code is the PID trajectory playback library. 00014 00015 The Initial Developers of the Original Code are Andrew Crossan (ac@dcs.gla.ac.uk) 00016 and John Williamson (jhw@dcs.gla.ac.uk) from University of Glasgow. 00017 00018 Portions created by Andrew Crossan and John Williamson are Copyright (C) 2006. 00019 All Rights Reserved. 00020 00021 Contributor(s): ______________________________________. 00022 00023 */ 00024 00025 /* PID Trajectory Playback v1.1 - A library for playing a trajectory on a force feedback device 00026 * To playback a trajectory on the haptic device using the controller 00027 * 1. Initialise the controller using one of the CreateController functions 00028 * 2. Add a series of points for the trajectory using AddWaypoint 00029 * 3. Set the controller playing with StartPlayback 00030 * 4. At every servo loop update, call GetForce to get the controller force 00031 * GetForce will return false when the playback is finished 00032 * 00033 * if the trajectory has been recorded at full sampling rate, SetPlaybackAtSampleRate(true) 00034 * can be used to playback at the approximate recorded trajectory speed 00035 */ 00036 00037 #pragma once 00038 00039 00040 #include "pid.h" 00041 #include "micolelib.h" 00042 00043 #include "FF3DForceModel.h" 00044 using namespace Reachin; 00045 00046 00047 #define PLAY_AT_SAMPLE_RATE false 00048 #define ABSOLUTE_POSITIONING false 00049 00050 #define BEAD_SPEED 100 00051 #define ERROR_THRESHOLD 10 00052 00053 struct PtsList { 00054 // double time; 00055 00056 double xPos, yPos, zPos; 00057 // double xVel, yVel, zVel; /* Added velocities jhw */ 00058 PtsList *prev, *next; 00059 }; 00060 00061 #define PID_PI 3.141592 00062 #define PID_PI_BY_2 PID_PI / 2.0 00063 #define _PLAY_MICOLE_RATE 700 00064 00065 enum Mode 00066 { 00067 PID_IDLE = 0, 00068 PID_STICK_TO_POINT = 1, 00069 PID_MOVE_TO_STICK_POINT = 2, 00070 PID_PLAY = 3, 00071 PID_MOVE_TO_PLAY_POINT = 4, 00072 PID_PAUSE = 5, 00073 PID_CONSTRAIN = 6, 00074 PID_MOVE_TO_CONSTRAIN_POINT = 7, 00075 }; 00076 00077 class Playback 00078 { 00079 public: 00080 Playback(); 00081 ~Playback(); 00082 // Overrides 00083 public: 00084 00085 Vec3f _stick_point; 00086 // Initialize a new PID controller with specfic values 00087 void CreateControllers(double p, double i, double d, double f, double out_filter, 00088 double gain, double sat_low, double sat_high, double dead_zone); 00089 /* 00090 * p: proportional control gain 00091 * i: integral control gain 00092 * d: derivative control gain 00093 * f: input filter (for deriv. estimation) 00094 * out_filter: output filtering 00095 * gain: overall gain 00096 * sat_low: minimum saturation point 00097 * sat_high: maximum_saturation point 00098 */ 00099 00100 // Initialise with preset Phantom omni parameters 00101 // p = 0.3, i = 0.0005, d = 20.0, f = 0.09, out_filter = 0.09, gain = 0.2, sat_low = -3.0, 00102 // sat_high = 3.0, dead_zone = 0.0 00103 void CreateControllersForOmni(); 00104 00105 // Initialise PD controller with preset Phantom omni parameters 00106 // Using PD instead of PID will avoid force wind up when playback is resisted 00107 // p = 0.3, i = 0.0, d = 20.0, f = 0.09, out_filter = 0.09, gain = 0.2, sat_low = -3.0, 00108 // sat_high = 3.0, dead_zone = 0.0 00109 void CreatePDControllersForOmni(); 00110 00111 // Initialise with preset Phantom Premium 1.5parameters 00112 // p = 0.3, i = 0.00005, d = 30.0, f = 0.09, out_filter = 0.09, gain = 0.2, sat_low = -1.5, 00113 // sat_high = 1.5, dead_zone = 0.0 00114 void CreateControllersForPremium15(); 00115 00116 // Reset the's the state of the controller 00117 void ResetControllerState(); 00118 00119 // moves the current position in the playback to the start of the gesture 00120 void MoveToStartOfGesture(); 00121 00122 // gets the current mode of playback 00123 Mode GetMode(); 00124 00125 // sets the playback state to idle. ie stops playback 00126 void SetIdle(); 00127 00128 // toggles between pause and play. Pause will stop the 00129 // gesture without returning to the start of the gesture 00130 void TogglePauseGesture(); 00131 00132 // Tries to control the users cursor to one specifc point 00133 // curPPos is the current device position, pt is the position to stick to 00134 void StickToPoint(double curPos[3], double pt[3]); 00135 00136 // Sticks the cursor to the currentPosition specified 00137 // by curPos 00138 void StickToThisPoint(double curPos[3]); 00139 00140 // sets the controller to playback one sample per update 00141 // if false, playback rate is controller through SetPlaybackSpeed 00142 // Note... this means that if the user resists moving, the gesture will 00143 // still continue 00144 void SetPlayAtSampleRate(bool pasr); 00145 00146 // returns true if the controller is set to playback at 00147 // the sample rate 00148 bool GetPlayAtSampleRate(); 00149 00150 // call at every servo loop update 00151 // afeter the call, force will contain the force calculated by the controller 00152 bool GetForce(double pt[3], double force[3]); 00153 00154 // Returns true only if not IDLE. In pPos, the current x, y, z playback position or 00155 // stick point position will be returned 00156 bool GetPlaybackPos(double pPos[3]); 00157 00158 // called to set the trajectory to play. You MUST still call GetForce every 00159 // servo loop update to get the force of th playback 00160 // either specify a trajectory explictly by passing in a list of points 00161 // or if no list is provided, the pre-built (with AddWaypoint) trajectory 00162 // is used 00163 void StartPlayback(PtsList *pt, double curPos[3]); // playback waypoints pt 00164 void StartPlayback(double curPos[3]); // playback currently stored waypoints 00165 00166 00167 // called to set the trajectory to constrain the user to. You MUST still call 00168 // GetForce every servo loop update to get the force of th playback 00169 // the pre-built (with AddWaypoint) trajectory is used for the constrain path 00170 // curPos is the currentPosition of the device 00171 // if using absolute positioning, the controller will initially go into 00172 // PID_MOVE_TO_CONSTRAIN_POINT mode 00173 void StartConstrain(double curPos[3]); 00174 00175 // set the speed of playback in mm/update if not in playback_at_sample_rate mode 00176 // default is 100 00177 void SetPlaybackSpeed(double v); 00178 00179 // clears the current trajectory 00180 void ClearPath(); 00181 00182 // add a waypoint to the end of the current trajectory. This is used in conjunction 00183 // with StartPlayback(double curPos[3])... 00184 // using StartPlayback(PtsList *pt, double curPos[3]) will overwrite any trajectory 00185 // built with AddWaypoint with the list of points specified 00186 void AddWaypoint(double pt[3]); 00187 00188 // load a gesture from a file fName is the path a name of the file 00189 // returns true if the file is found and false otherwise 00190 // File Format 00191 // time1, pt1_x, pt1_y, pt1_z 00192 // time2, pt2_x, pt2_y, pt2_z 00193 // time3, pt2_x, pt2_y, pt2_z 00194 // ....... 00195 bool LoadGestureFile(char *fName); 00196 00197 // Saves the current gesture to a file fName is the path a name of the file 00198 // returns true if the file can be created and false otherwise 00199 // File Format 00200 // time1, pt1_x, pt1_y, pt1_z 00201 // time2, pt2_x, pt2_y, pt2_z 00202 // time3, pt2_x, pt2_y, pt2_z 00203 // ....... 00204 bool SaveGestureFile(char *fName); 00205 00206 // absPos == True to use absolute Positioning for gesture 00207 // absPos == False to start gesture at the current postion 00208 void UseAbsolutePositioning(bool absPos); 00209 00210 // The error threshold is the distance that the device has to get 00211 // to the sample position before the trajectory is moved on to the 00212 // next point. This is measured in mm (default 10mm) 00213 void SetErrorThreshold(double e); 00214 double GetErrorThreshold(); 00215 00216 // cap the maximum force from the integrator to avoid wind up 00217 // for the CreateControllersForOmni and the CreateControllersForPremium15, 00218 // this is automatically set to the controller max force cap 00219 void SetIntegratorForceCap(double maxforce); 00220 00221 void stickToPointAndGetForce(Vec3f pos, Vec3f dest, Vec3f& force); 00222 00223 00224 private: 00225 00226 control_state *control_x, *control_y, *control_z; // Pos controllers 00227 PtsList *head, *cur, *end; 00228 PtsList *headToPt, *curToPt, *endToPt; 00229 double startPos[3], stickPoint[3], stickBeadPos[3], beadPos[3], beadSpeed; 00230 double startTime, prevTime; 00231 bool playAtSampleRate; 00232 bool absolutePositioning; 00233 double err_thresh; 00234 00235 Mode mode; 00236 00237 // helper functions for stick to Point 00238 void CreateGestureToPoint(double curPos[3], double thePoint[3]); 00239 void FreeGestureToPoint(); 00240 void MoveToPoint(double curPos[3], double pt[3], Mode m); 00241 00242 // helper functions for constrain 00243 bool DoConstrain(double pPos[3], double force[3]); 00244 00245 //Set the windup limit 00246 void SetIntegratorCap(double icap); 00247 00248 00249 // distance from cur along the pathway that the bead has moved in constrain 00250 // mode. This is used to ensure that the user can only move forwards along 00251 // the path therefore removing the tricky direction decision for sharp corners 00252 double curConstrainDist; 00253 00254 //debug 00255 double a; 00256 double distFromPrev; 00257 };