Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

dcmotor.c

Go to the documentation of this file.
00001 /*
00002    dcmotor.c
00003 
00004    DC motor simulation
00005 
00006    From Benjamin C. Kuo, "Automatic Control Systems," Fourth Edition,
00007    pp. 176-186.
00008 
00009    Units are SI for all quantities. Note that back EMF constant Kb is
00010    identically equal to Torque Constant in SI units, so Ki is omitted
00011    from interface and replaced with Kb in calculations.
00012 
00013    Modification history:
00014 
00015    26-Apr-2000 WPS added some code to try using a simpler simulation
00016    model if Jm or La are equal to zero. (At least it avoids a divide by
00017    zero.)
00018    12-Apr-2000 WPS removed redundant second include of inifile.h
00019    23-Sep-1999  WPS replaced stdio functions with inet_file functions
00020    which work under CE.
00021    23-Sep-1999 WPS initialized suspicious return retval from dcmotorGetParameters
00022    27-Jan-1999 WPS added "volatile"'s to avoid NT optimization problem.
00023    23-Mar-1998  FMP included <string.h>, as I should have
00024    17-Mar-1998  FMP added section arg to dcmotorIniLoad()
00025    9-Sep-1997  FMP added dcmotorResetState();
00026    17-Aug-1997  FMP took out etime() call in dcmotorRunCycle-- need to
00027    add a function to get real time-- etime() in rcs library does this,
00028    but we don't want to include all of that here
00029    2-May-1997  FMP fixed bug in dcmotorRunCycle() where I left deltaT
00030    unset if cycleTime was not <= 0.0. This bug, of course, cost me a week.
00031    25-Apr-1997  FMP added lastTime and etime() for real-time sim
00032    24-Apr-1997  FMP added dcmotorIniLoad()
00033    17-Apr-1997  FMP created from C part of original dcmotor.c
00034 */
00035 
00036 #ifndef NO_STDIO_SUPPORT
00037 #ifdef UNDER_CE
00038 #include "rcs_ce.h"             /* RCS_CE_ATOF() */
00039 #else
00040 #include <stdio.h>
00041 #endif
00042 #include "inetfile.hh"          /* inet_file_open() */
00043 #include "inifile.h"
00044 #include "rcs_prnt.hh"          /* rcs_print() */
00045 #include <string.h>
00046 #endif
00047 #include "dcmotor.h"            /* these decls */
00048 
00049 /* ident tag */
00050 #ifndef __GNUC__
00051 #ifndef __attribute__
00052 #define __attribute__(x)
00053 #endif
00054 #endif
00055 
00056 static char __attribute__((unused)) ident[] = "$Id: dcmotor.c,v 1.3 2000/10/27 20:34:42 terrylr Exp $";
00057 
00058 #define PARAMETERS_SET 0x01
00059 #define CYCLE_TIME_SET 0x02
00060 #define OFFSET_SET 0x04
00061 #define REVS_PER_UNIT_SET 0x08
00062 #define ALL_SET (PARAMETERS_SET | CYCLE_TIME_SET | OFFSET_SET | REVS_PER_UNIT_SET)
00063 
00064 /* Conversion factors */
00065 /* oz-in * 0.00708 = newton-meters */
00066 /* foot-pounds * 1.359 = newton-meters */
00067 #define OZ_IN_TO_N_M 0.00708
00068 #define LB_FT_TO_N_M 1.359
00069 
00070 int dcmotorInit(DC_MOTOR_STRUCT * dcmotor)
00071 {
00072   if (0 == dcmotor)
00073   {
00074     return -1;
00075   }
00076 
00077   /* parameters */
00078   dcmotor->Ra = 0.0;
00079   dcmotor->La = 0.0;
00080   dcmotor->Kb = 0.0;
00081   dcmotor->Jm = 0.0;
00082   dcmotor->Bm = 0.0;
00083 
00084   /* internal vars */
00085   dcmotor->configured = 0;
00086   dcmotor->cycleTime = 0.0;
00087   dcmotor->offset = 0.0;
00088   dcmotor->revsPerUnit = 0.0;
00089   dcmotor->lastTime = -1.0;
00090 
00091   /* state vars */
00092   return dcmotorResetState(dcmotor);
00093 }
00094 
00095 int dcmotorResetState(DC_MOTOR_STRUCT * dcmotor)
00096 {
00097   /* state vars */
00098   dcmotor->ia = 0.0;
00099   dcmotor->dia = 0.0;
00100   dcmotor->wm = 0.0;
00101   dcmotor->dwm = 0.0;
00102   dcmotor->thm = 0.0;
00103   dcmotor->dthm = 0.0;
00104 
00105   return 0;
00106 }
00107 
00108 int dcmotorSetCycleTime(DC_MOTOR_STRUCT * dcmotor, double seconds)
00109 {
00110   if (0 == dcmotor)
00111   {
00112     return -1;
00113   }
00114 
00115   /* note that seconds <= 0.0 means use real time */
00116   dcmotor->cycleTime = seconds;
00117   dcmotor->configured |= CYCLE_TIME_SET;
00118 
00119   return 0;
00120 }
00121 
00122 double dcmotorGetCycleTime(DC_MOTOR_STRUCT * dcmotor)
00123 {
00124   if (0 == dcmotor ||
00125       ! (dcmotor->configured & CYCLE_TIME_SET))
00126   {
00127     return 0.0;
00128   }
00129 
00130   return dcmotor->cycleTime;
00131 }
00132 
00133 int dcmotorSetParameters(DC_MOTOR_STRUCT * dcmotor, DC_MOTOR_STRUCT params)
00134 {
00135   if (0 == dcmotor)
00136   {
00137     return -1;
00138   }
00139 
00140   dcmotor->Ra = params.Ra;
00141   dcmotor->La = params.La;
00142   dcmotor->Kb = params.Kb;
00143   dcmotor->Jm = params.Jm;
00144   dcmotor->Bm = params.Bm;
00145 
00146   dcmotor->configured |= PARAMETERS_SET;
00147 
00148   return 0;
00149 }
00150 
00151 DC_MOTOR_STRUCT dcmotorGetParameters(DC_MOTOR_STRUCT * dcmotor)
00152 {
00153   DC_MOTOR_STRUCT retval;
00154 
00155   if (0 == dcmotor)
00156   {
00157      /* parameters */
00158     retval.Ra=0;                        /* armature resistance, ohms */
00159     retval.La=0;                        /* armature inductance, henries */
00160     retval.Kb=0;                        /* back emf constant, V/rad/s, N-m/amp */
00161     retval.Jm=0;                        /* motor rotor inertia, N-m-s^2 */
00162     retval.Bm=0;                        /* viscous friction coefficient, N-m/rad/sec */
00163 
00164   /* state vars */
00165     retval.ia=0;                        /* armature current */
00166     retval.dia=0;                       /* derivative of above */
00167     retval.wm=0;                        /* angular velocity of motor */
00168     retval.dwm=0;                       /* derivative of above */
00169     retval.thm=0;                       /* angular position of motor */
00170     retval.dthm=0;                      /* derivative of above */
00171     retval.lastTime=0;          /* timestamp of last cycle */
00172 
00173   /* internal vars */
00174     retval.configured=0;
00175     retval.cycleTime=0;         /* copy of arg to setCycleTime() */
00176     retval.offset=0;
00177     retval.revsPerUnit=0;
00178     return retval;
00179   }
00180 
00181   return *dcmotor;
00182 }
00183 
00184 int dcmotorSetOffset(DC_MOTOR_STRUCT * dcmotor, double _offset)
00185 {
00186   if (0 == dcmotor)
00187   {
00188     return -1;
00189   }
00190 
00191   dcmotor->offset = _offset;
00192   dcmotor->configured |= OFFSET_SET;
00193 
00194   return 0;
00195 }
00196 
00197 double dcmotorGetOffset(DC_MOTOR_STRUCT * dcmotor)
00198 {
00199   if (0 == dcmotor ||
00200       ! (dcmotor->configured & OFFSET_SET))
00201   {
00202     return 0.0;
00203   }
00204 
00205   return dcmotor->offset;
00206 }
00207 
00208 int dcmotorSetRevsPerUnit(DC_MOTOR_STRUCT * dcmotor, double _revsPerUnit)
00209 {
00210   if (0 == dcmotor ||
00211       _revsPerUnit <= 0.0)
00212   {
00213     return -1;
00214   }
00215 
00216   dcmotor->revsPerUnit = _revsPerUnit;
00217   dcmotor->configured |= REVS_PER_UNIT_SET;
00218 
00219   return 0;
00220 }
00221 
00222 double dcmotorGetRevsPerUnit(DC_MOTOR_STRUCT * dcmotor)
00223 {
00224   if (0 == dcmotor ||
00225       ! (dcmotor->configured & REVS_PER_UNIT_SET))
00226   {
00227     return 0.0;
00228   }
00229 
00230   return dcmotor->revsPerUnit;
00231 }
00232 
00233 double dcmotorGetOutput(DC_MOTOR_STRUCT * dcmotor)
00234 {
00235   if (0 == dcmotor ||
00236       dcmotor->configured != ALL_SET)
00237   {
00238     return 0.0;
00239   }
00240 
00241   return dcmotor->thm + dcmotor->offset;
00242 }
00243 
00244 double dcmotorRunCycle(volatile DC_MOTOR_STRUCT * dcm, volatile double ea)
00245 {
00246   volatile double deltaT;
00247   volatile double now;
00248 
00249   if (0 == dcm ||
00250       dcm->configured != ALL_SET)
00251     {
00252       return 0.0;
00253     }
00254 
00255   /* calculate deltaT */
00256   if (dcm->cycleTime <= 0.0)
00257     {
00258       /* if cycleTime <= 0.0, we want to use real time stamps */
00259       if (dcm->lastTime <= 0.0)
00260         {
00261           /* first time through */
00262           dcm->lastTime = 0.0;
00263           deltaT = 0.0;         /* results will all be zero */
00264         }
00265       else
00266         {
00267           /* FIXME-- get current time in 'now', instead of 0 */
00268           now = 0.0;
00269           deltaT = now - dcm->lastTime;
00270           dcm->lastTime = now;
00271         }
00272     }
00273   else
00274     {
00275       deltaT = dcm->cycleTime;
00276     }
00277 
00278   /* calculate differentials */
00279 
00280   if(dcm->La != 0.0)
00281     {
00282       dcm->dia = deltaT *
00283         (-dcm->Ra * dcm->ia -
00284          dcm->Kb * dcm->wm +
00285          ea) / dcm->La;
00286     }
00287   else if (dcm->Ra != 0.0)
00288     {
00289       dcm->dia = (ea - dcm->Kb * dcm->wm)/dcm->Ra - dcm->ia;
00290     }
00291   else
00292     {
00293       dcm->dia = -dcm->ia;
00294       if(dcm->Kb != 0.0)
00295         {
00296           dcm->wm = ea/dcm->Kb;
00297         }
00298       else
00299         {
00300           dcm->wm = 0.0;
00301         }
00302     }
00303 
00304   if(dcm->Jm != 0.0)
00305     {
00306       dcm->dwm = deltaT *
00307         (dcm->Kb * dcm->ia -
00308          dcm->Bm * dcm->wm) / dcm->Jm; /* Ki == Kb, Tl = 0 */
00309     }
00310   else if(dcm->Bm != 0.0)
00311     {
00312       dcm->dwm = (dcm->Kb * dcm->ia)/dcm->Bm - dcm->wm;
00313     }
00314   else
00315     {
00316       dcm->dwm = -dcm->wm;
00317       dcm->ia = 0.0;
00318     }
00319 
00320   dcm->dthm = deltaT * dcm->wm;
00321 
00322   /* update state vars with differentials */
00323 
00324   dcm->ia += dcm->dia;
00325   dcm->wm += dcm->dwm;
00326   dcm->thm += dcm->dthm;
00327 
00328   /* return motor position */
00329 
00330   return dcm->thm + dcm->offset;
00331 }
00332 
00333 int dcmotorIniLoad(DC_MOTOR_STRUCT * dcmotor, const char * filename, const char *section)
00334 {
00335 #ifndef NO_STDIO_SUPPORT
00336 
00337   DC_MOTOR_STRUCT dcm;
00338   double cycleTime;
00339   double offset;
00340   double revsPerUnit;
00341   int retval = 0;
00342   const char *inistring;
00343   enum {TORQUE_UNITS_INVALID = 0,
00344         N_M,
00345         OZ_IN,
00346         LB_FT
00347         } torque_units;
00348 
00349 #ifndef UNDER_CE
00350   FILE *fp;
00351 
00352   if (NULL == (fp = fopen(filename, "r")))
00353   {
00354     rcs_print_error( "can't open ini file %s\n", filename);
00355     return -1;
00356   }
00357 #else
00358   INET_FILE *fp;
00359 
00360   if (NULL == (fp = inet_file_open(filename, "r")))
00361   {
00362     rcs_print_error( "can't open ini file %s\n", filename);
00363     return -1;
00364   }
00365 #endif
00366 
00367   /* look up torque units */
00368   if (NULL != (inistring = iniFind(fp, "TORQUE_UNITS", section)))
00369   {
00370     /* found the entry in the ini file */
00371     if (!strcmp(inistring, "N_M"))
00372     {
00373       torque_units = N_M;
00374     }
00375     else if (!strcmp(inistring, "LB_FT"))
00376     {
00377       torque_units = LB_FT;
00378     }
00379     else if (!strcmp(inistring, "OZ_IN"))
00380     {
00381       torque_units = OZ_IN;
00382     }
00383     else
00384     {
00385       torque_units = TORQUE_UNITS_INVALID;
00386       rcs_print_error( "bad torque units specified in ini file: %s\n",
00387               inistring);
00388       retval = -1;
00389     }
00390   }
00391   else
00392   {
00393     /* not in ini file-- use default */
00394     torque_units = N_M;
00395   }
00396 
00397   if (NULL != (inistring = iniFind(fp, "ARMATURE_RESISTANCE", section)))
00398   {
00399 #ifndef UNDER_CE
00400     if (1 != sscanf((char *) inistring, "%lf", &dcm.Ra))
00401     {
00402       /* found, but invalid */
00403       rcs_print_error( "invalid ARMATURE_RESISTANCE: %s\n", inistring);
00404       retval = -1;
00405     }
00406 #else
00407     dcm.Ra = RCS_CE_ATOF(inistring);
00408 #endif
00409   }
00410   if (NULL != (inistring = iniFind(fp, "ARMATURE_INDUCTANCE", section)))
00411   {
00412 #ifndef UNDER_CE
00413     if (1 != sscanf((char *) inistring, "%lf", &dcm.La))
00414     {
00415       /* found, but invalid */
00416       rcs_print_error( "invalid ARMATURE_INDUCTANCE: %s\n", inistring);
00417       retval = -1;
00418     }
00419 #else
00420     dcm.La = RCS_CE_ATOF(inistring);
00421 #endif
00422   }
00423   if (NULL != (inistring = iniFind(fp, "BACK_EMF_CONSTANT", section)))
00424   {
00425 #ifndef UNDER_CE
00426     if (1 != sscanf((char *) inistring, "%lf", &dcm.Kb))
00427     {
00428       /* found, but invalid */
00429       rcs_print_error( "invalid BACK_EMF_CONSTANT: %s\n", inistring);
00430       retval = -1;
00431     }
00432 #else
00433     dcm.Kb = RCS_CE_ATOF(inistring);
00434 #endif
00435   }
00436   if (NULL != (inistring = iniFind(fp, "ROTOR_INERTIA", section)))
00437   {
00438 #ifndef UNDER_CE
00439     if (1 != sscanf((char *) inistring, "%lf", &dcm.Jm))
00440     {
00441       /* found, but invalid */
00442       rcs_print_error( "invalid ROTOR_INERTIA: %s\n", inistring);
00443       retval = -1;
00444     }
00445 #else
00446     dcm.Jm = RCS_CE_ATOF(inistring);
00447 #endif
00448     switch (torque_units)
00449     {
00450     case OZ_IN:
00451       dcm.Jm *= OZ_IN_TO_N_M;
00452       break;
00453     case LB_FT:
00454       dcm.Jm *= LB_FT_TO_N_M;
00455       break;
00456     default:
00457       break;
00458     }
00459   }
00460   if (NULL != (inistring = iniFind(fp, "DAMPING_FRICTION_COEFFICIENT", section)))
00461   {
00462 #ifndef UNDER_CE
00463     if (1 != sscanf((char *) inistring, "%lf", &dcm.Bm))
00464     {
00465       /* found, but invalid */
00466       rcs_print_error( "invalid DAMPING_FRICTION_COEFFICIENT: %s\n", inistring);
00467       retval = -1;
00468     }
00469 #else
00470     dcm.Bm = RCS_CE_ATOF(inistring);
00471 #endif
00472     switch (torque_units)
00473     {
00474     case OZ_IN:
00475       dcm.Bm *= OZ_IN_TO_N_M;
00476       break;
00477     case LB_FT:
00478       dcm.Bm *= LB_FT_TO_N_M;
00479       break;
00480     default:
00481       break;
00482     }
00483   }
00484 
00485   if (retval == 0)
00486   {
00487     dcmotorSetParameters(dcmotor, dcm);
00488   }
00489 
00490   if (NULL != (inistring = iniFind(fp, "CYCLE_TIME", section)))
00491   {
00492 #ifndef UNDER_CE
00493     if (1 != sscanf((char *) inistring, "%lf", &cycleTime))
00494     {
00495       /* found, but invalid */
00496       rcs_print_error( "invalid CYCLE_TIME: %s\n", inistring);
00497       retval = -1;
00498     }
00499     else
00500     {
00501       dcmotorSetCycleTime(dcmotor, cycleTime);
00502     }
00503 #else
00504     cycleTime = RCS_CE_ATOF(inistring);
00505     dcmotorSetCycleTime(dcmotor, cycleTime);
00506 #endif
00507   }
00508 
00509   if (NULL != (inistring = iniFind(fp, "SHAFT_OFFSET", section)))
00510   {
00511 #ifndef UNDER_CE
00512     if (1 != sscanf((char *) inistring, "%lf", &offset))
00513     {
00514       /* found, but invalid */
00515       rcs_print_error( "invalid OFFSET: %s\n", inistring);
00516       retval = -1;
00517     }
00518     else
00519     {
00520       dcmotorSetOffset(dcmotor, offset);
00521     }
00522 #else
00523     offset = RCS_CE_ATOF(inistring);
00524     dcmotorSetOffset(dcmotor, offset);
00525 #endif
00526   }
00527 
00528   if (NULL != (inistring = iniFind(fp, "REVS_PER_UNIT", section)))
00529   {
00530 #ifndef UNDER_CE
00531     if (1 != sscanf((char *) inistring, "%lf", &revsPerUnit))
00532     {
00533       /* found, but invalid */
00534       rcs_print_error( "invalid REVS_PER_UNIT: %s\n", inistring);
00535       retval = -1;
00536     }
00537     else
00538     {
00539       dcmotorSetRevsPerUnit(dcmotor, revsPerUnit);
00540     }
00541 #else
00542     revsPerUnit = RCS_CE_ATOF(inistring);
00543     dcmotorSetRevsPerUnit(dcmotor, revsPerUnit);
00544 #endif
00545   }
00546 
00547   /* close inifile */
00548 #ifndef UNDER_CE
00549   fclose(fp);
00550 #else
00551   inet_file_close(fp);
00552 #endif
00553 
00554   return retval;
00555 
00556 #else
00557 
00558   return -1;
00559 
00560 #endif /* not STDIO_SUPPORT */
00561 }

Generated on Sun Dec 2 15:27:36 2001 for EMC by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001