00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <CommsManager.H>
00014 #include <RobotDrive.H>
00015 #include <Egomotion.H>
00016 #include <VectorMoverTransport.H>
00017 #include <cmath>
00018 #include <stdlib.h>
00019 #include <RobotUtil.H>
00020
00021 using namespace WURDE;
00022 using namespace std;
00023
00024 static const float MAX_TRANS_VEL_DEFAULT = 0.4;
00025 static const float MAX_ANG_VEL_DEFAULT = 0.9;
00026
00027 static const float MAX_TRANS_ACCEL_DEFAULT = 0.8;
00028 static const float MAX_TRANS_DECEL_DEFAULT = 0.9;
00029 static const float MAX_ANG_ACCEL_DEFAULT = 10.0;
00030 static const float MAX_ANG_DECEL_DEFAULT = 10.0;
00031
00032 static const float CLOSE_ENOUGH_DISTANCE = 0.06;
00033 static const float CLOSE_ENOUGH_ANGLE = M_PI/180;
00034
00035 static const float DISPLACEMENT_ENVELOPE = 0.5;
00036
00037 static const float DELTA_THETA_ENVELOPE = 1.2;
00038
00039 double max_trans_vel=MAX_TRANS_VEL_DEFAULT;
00040 double max_ang_vel=MAX_ANG_VEL_DEFAULT;
00041
00042 enum VMState { VM_IDLE, VM_MOVING, VM_SPINNING, VM_STOPPING, VM_HOLDING };
00043
00044 double calcRotVelocity(double & delta_theta);
00045 double calcTransVelocity(double & displacement);
00046 void translate(double dist, Pose & currPose, Pose &goalPose);
00047 void rotateRelative(double theta, Pose &currPose, Pose &goalPose);
00048 void rotateAbsolute(double theta, Pose &currPose, Pose &goalPose);
00049 void moveRelative(Pose & goalPose, Pose &currPose, Pose &goalPose);
00050 void moveAbsolute(Pose & goalPose, Pose &currPose, Pose &goalPose);
00051
00052 int main(int argc, char *argv[]){
00053 CommsManager myManager("SynchroMover");
00054 Logger myLogger("VectorMoverLogger");
00055 myManager.setRealName("SynchroMover");
00056 myManager.setHelpString("\nThis module abstracts the dynamics of a Synchro/Diff drive robot system to allow movement along an arbitrary vector.\n\n");
00057 myManager.parseOptions(argc,argv);
00058 RobotDrive myDrive(STRAT_ASSIGNED,"DriveClient");
00059 Egomotion myEgomotion(STRAT_ASSIGNED,"EgoClient");
00060
00061
00062 VectorMoverTransport myNavigator("SynchroMover");
00063
00064 char logbuf[1024];
00065
00066 bool haveGoalTheta, hasGoal;
00067 Pose goalPose(0,0,0),currPose(0,0,0),requestedPose(0,0,0);
00068 double trans=0, steer=0, displacement=0,delta_theta=0;
00069
00070 double desired_trans_vel=0, desired_ang_vel=0;
00071 double lasttrans=0,laststeer=0;
00072 VMState state=VM_IDLE;
00073
00074 myManager.registerConsumer(&myDrive);
00075 myManager.registerConsumer(&myEgomotion);
00076 myManager.registerSupplier(&myNavigator);
00077
00078 myDrive.requests.trans.setValue(0);
00079 myDrive.requests.angular.setValue(0);
00080 myDrive.requests.brake.setValue(false);
00081 myDrive.requests.angularLimit.setValue(MAX_ANG_VEL_DEFAULT);
00082 myDrive.requests.transLimit.setValue(MAX_TRANS_VEL_DEFAULT);
00083 myDrive.publishRequest();
00084
00085 myManager.setSleep(0.03);
00086
00087 trans=0;
00088 steer=0;
00089
00090 while(myManager.runUpdate()==STATE_RUN||
00091 myManager.getState()==STATE_IDLE){
00092
00093
00094
00095 if(myEgomotion.newData()){
00096 myEgomotion.getNextData();
00097 currPose=myEgomotion.data.location;
00098 g_logdebug << "Current: " << currPose.x() << " " << currPose.y() << endl;
00099 }
00100
00101
00102
00103 if(myNavigator.newRequest()){
00104 hasGoal=true;
00105 myNavigator.getNextRequest();
00106 if(myNavigator.requests.brake.getValue()){
00107 state=VM_HOLDING;
00108 }else{
00109 requestedPose=myNavigator.requests.goalPose.getValue();
00110 if(myNavigator.requests.absolute.getValue()){
00111
00112 if(myNavigator.requests.goalHasLocation.getValue()){
00113
00114 state=VM_MOVING;
00115 moveAbsolute(requestedPose,currPose,goalPose);
00116
00117 sprintf(logbuf,"Received request to move to %f, %f",requestedPose.x(),requestedPose.y());
00118 g_debug(logbuf);
00119 if(!myNavigator.requests.goalHasTheta.getValue()){
00120 goalPose.theta(currPose.theta());
00121 }
00122 }else{
00123 state=VM_SPINNING;
00124
00125 rotateAbsolute(requestedPose.theta(),currPose,goalPose);
00126 sprintf(logbuf,"Received request to rotate to %f",requestedPose.theta());
00127 g_debug(logbuf);
00128 }
00129
00130 }else{
00131
00132 if(myNavigator.requests.goalHasLocation.getValue()){
00133
00134 moveRelative(requestedPose,currPose,goalPose);
00135 if(myNavigator.requests.goalHasTheta.getValue()){
00136
00137
00138 }else{
00139
00140 goalPose.theta(currPose.theta());
00141 }
00142 sprintf(logbuf,"Received request to move to %f, %f, %f",requestedPose.x(),requestedPose.y(),requestedPose.theta());
00143 g_debug(logbuf);
00144 state=VM_MOVING;
00145
00146 }else if(myNavigator.requests.goalHasTheta.getValue()){
00147
00148 double temptheta=requestedPose.theta();
00149 sprintf(logbuf,"Received request to rotate relative %f",requestedPose.theta());
00150 g_debug(logbuf);
00151
00152 rotateRelative(temptheta,currPose,goalPose);
00153 state=VM_SPINNING;
00154 }else{
00155 double tempx=requestedPose.x();
00156
00157 translate(tempx,currPose,goalPose);
00158 sprintf(logbuf,"Received request to translate %f",tempx);
00159 g_debug(logbuf);
00160
00161 state=VM_MOVING;
00162 }
00163
00164 }
00165 }
00166 }
00167
00168
00169
00170 if (state == VM_MOVING){
00171 displacement = hypot(goalPose.x() - currPose.x(), goalPose.y() - currPose.y());
00172 if (displacement > CLOSE_ENOUGH_DISTANCE) {
00173 delta_theta = normalizeAngle(atan2(goalPose.y() - currPose.y(), goalPose.x() - currPose.x()) - currPose.theta());
00174 } else {
00175 delta_theta = normalizeAngle(goalPose.theta() - currPose.theta());
00176
00177 }
00178
00179 } else if (state == VM_SPINNING) {
00180 displacement = 0.0;
00181
00182 delta_theta = normalizeAngle(goalPose.theta() - currPose.theta());
00183 if (fabs(delta_theta) < CLOSE_ENOUGH_ANGLE) {
00184
00185 delta_theta = 0.0;
00186 }
00187 } else {
00188 displacement = 0.0;
00189 delta_theta = 0.0;
00190 }
00191
00192
00193
00194 switch(state){
00195 case VM_MOVING:
00196 hasGoal=true;
00197
00198 if(fabs(delta_theta) < M_PI/4){
00199 desired_trans_vel = calcTransVelocity(displacement);
00200 } else {
00201
00202 desired_trans_vel = 0.0;
00203 }
00204
00205 if(fabs(delta_theta) > CLOSE_ENOUGH_ANGLE){
00206 desired_ang_vel = calcRotVelocity(delta_theta);
00207 }
00208
00209 if ((fabs(displacement) < CLOSE_ENOUGH_DISTANCE)){
00210 state = VM_STOPPING;
00211 hasGoal=false;
00212 }
00213 break;
00214
00215 case VM_SPINNING:
00216 hasGoal=true;
00217 desired_trans_vel = 0.0;
00218 desired_ang_vel = calcRotVelocity(delta_theta);
00219
00220 if (fabs(delta_theta) < CLOSE_ENOUGH_ANGLE) {
00221
00222 state = VM_STOPPING;
00223 hasGoal=false;
00224 }
00225 break;
00226
00227 case VM_STOPPING:
00228 desired_trans_vel = 0.0;
00229 desired_ang_vel = 0.0;
00230 hasGoal=false;
00231 if ((fabs(trans) < 1e-6) && (fabs(steer) < 1e-6)){
00232 state = VM_IDLE;
00233 }
00234
00235 break;
00236
00237 case VM_HOLDING:
00238 hasGoal=false;
00239 desired_trans_vel = 0.0;
00240 desired_ang_vel = 0.0;
00241 break;
00242
00243 case VM_IDLE:
00244 break;
00245
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 if(state != VM_IDLE) {
00258 trans=desired_trans_vel;
00259 steer=desired_ang_vel;
00260 }else{
00261 trans=0;
00262 steer=0;
00263 }
00264
00265 myNavigator.data.hasGoal=hasGoal;
00266 myNavigator.data.distanceToGoal=displacement;
00267 myNavigator.data.angleToGoal=delta_theta;
00268 myNavigator.publishData();
00269
00270 lasttrans=trans;
00271 laststeer=steer;
00272
00273
00274
00275
00276 myDrive.requests.brake.setValue(false);
00277 myDrive.requests.trans.setValue(trans);
00278 myDrive.requests.angular.setValue(steer);
00279 myDrive.requests.angularLimit.setValue(max_ang_vel);
00280 myDrive.requests.transLimit.setValue(max_trans_vel);
00281 myDrive.publishRequest();
00282 }
00283
00284 myDrive.requests.trans.setValue(0);
00285 myDrive.requests.angular.setValue(0);
00286 myDrive.publishRequest();
00287
00288 myManager.runUpdate();
00289 sleep(1);
00290 myManager.cleanUp();
00291
00292 return 0;
00293 }
00294
00295 void moveAbsolute(Pose &requestedPose, Pose &currPose, Pose &goalPose){
00296 goalPose=requestedPose;
00297 }
00298
00299 void moveRelative(Pose &requestedPose, Pose &currPose, Pose &goalPose){
00300
00301 double dist=sqrt(pow(requestedPose.x(),2)+pow(requestedPose.y(),2));
00302 double angle=currPose.theta()+atan2(requestedPose.y(),requestedPose.x());
00303 requestedPose.x(dist*cos(angle)+currPose.x());
00304 requestedPose.y(dist*sin(angle)+currPose.y());
00305 requestedPose.theta(requestedPose.theta()+currPose.theta());
00306 goalPose=requestedPose;
00307
00308
00309
00310
00311
00312
00313 }
00314
00315 void rotateAbsolute(double theta, Pose &currPose, Pose &goalPose){
00316 Pose requestedPose;
00317 goalPose.x(currPose.x());
00318 goalPose.y(currPose.y());
00319 goalPose.theta(theta);
00320 }
00321
00322 void rotateRelative(double theta, Pose &currPose, Pose &goalPose){
00323 Pose requestedPose;
00324 requestedPose.x(currPose.x());
00325 requestedPose.y(currPose.y());
00326 requestedPose.theta(theta+currPose.theta());
00327 goalPose=requestedPose;
00328 }
00329
00330 void translate(double dist, Pose &currPose, Pose &goalPose){
00331 goalPose.x(currPose.x()+cos(currPose.theta())*dist);
00332 goalPose.y(currPose.y()+sin(currPose.theta())*dist);
00333
00334 }
00335
00336 double calcTransVelocity(double & displacement){
00337 double v;
00338 if(displacement < CLOSE_ENOUGH_DISTANCE){
00339 return 0;
00340 }
00341 if (displacement < DISPLACEMENT_ENVELOPE)
00342 v = max_trans_vel * displacement / DISPLACEMENT_ENVELOPE;
00343 else
00344 v = max_trans_vel;
00345 return v;
00346 }
00347
00348 double calcRotVelocity(double & delta_theta){
00349 double w;
00350 if(fabs(delta_theta) < CLOSE_ENOUGH_ANGLE){
00351
00352 return 0;
00353 }
00354
00355 if (fabs(delta_theta) < DELTA_THETA_ENVELOPE){
00356 w = max_ang_vel * delta_theta / DELTA_THETA_ENVELOPE;
00357 }else{
00358 w=max_ang_vel;
00359 if (delta_theta < 0)
00360 w = -w;
00361 }
00362
00363
00364 return w;
00365 }