Mindstorms 3rd Party ROBOTC Drivers RobotC
[Home] [Download] [Submit a bug/suggestion] [ROBOTC Forums] [Blog] [Support this project]

holitdata-motormux.h

Go to the documentation of this file.
00001 /*!@addtogroup other
00002  * @{
00003  * @defgroup holitdata HDS Motor MUX
00004  * Holit Data Systems Motor MUX
00005  * @{
00006  */
00007 
00008 /*
00009  * $Id: holitdata-motormux.h 133 2013-03-10 15:15:38Z xander $
00010  */
00011 
00012 #ifndef __HDMMUX_H__
00013 #define __HDMMUX_H__
00014 /** \file holitdata-motormux.h
00015  * \brief Holit Data Systems Motor MUX driver
00016  *
00017  * holitdata-motormux.h provides an API for the Holit Data Systems Motor MUX.
00018  *
00019  * Changelog:
00020  * - 0.1: Initial release
00021  * - 0.2: Replaced array structs with typedefs\n
00022  *        Uses new split off include file MMUX-common.h
00023  *
00024  * Credits:
00025  * - Big thanks to Holit Data Systems for providing me with the hardware necessary to write and test this.
00026  * - Thanks to Cheh from Holit Data Systems for the extensive testing and subsequent bug reports :)
00027  *
00028  * TODO:
00029  * - Add support for multiple MUXes per sensor port
00030  * - Ramping up and down of motors
00031  *
00032  * License: You may use this code as you wish, provided you give credit where its due.
00033  *
00034  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 3.59 AND HIGHER. 
00035 
00036  * \author Xander Soldaat (xander_at_botbench.com)
00037  * \date 20 February 2011
00038  * \version 0.2
00039  * \example holitdata-motormux-test1.c
00040  * \example holitdata-motormux-test2.c
00041  */
00042 
00043 #pragma systemFile
00044 
00045 #ifndef __COMMON_H__
00046 #include "common.h"
00047 #endif
00048 
00049 #ifndef __MMUX_H__
00050 #include "common-MMUX.h"
00051 #endif
00052 
00053 // device address - byte 0
00054 #define HDMMUX_I2C_ADDR         0x02  /*!< HDMMUX I2C device address */
00055 
00056 // Command type - byte 1
00057 #define HDMMUX_CMD_MOTOR        0x01
00058 #define HDMMUX_CMD_ADDRCHNG     0x02
00059 #define HDMMUX_CMD_RST_TACH_A   0x03
00060 #define HDMMUX_CMD_RST_TACH_B   0x04
00061 #define HDMMUX_CMD_RST_TACH_C   0x05
00062 
00063 // motor indicator - byte 2
00064 #define HDMMUX_MOTOR_A          0x01
00065 #define HDMMUX_MOTOR_B          0x02
00066 #define HDMMUX_MOTOR_C          0x03
00067 
00068 #define HDMMUX_MOTOR_OTHER      0x04
00069 #define HDMMUX_MOTOR_RIGHT      0x02
00070 #define HDMMUX_MOTOR_LEFT       0x00
00071 
00072 // rotation parameters - byte 3
00073 #define HDMMUX_ROT_FORWARD      (0x01 << 6)
00074 #define HDMMUX_ROT_REVERSE      (0x02 << 6)
00075 #define HDMMUX_ROT_STOP         (0x03 << 6)
00076 
00077 #define HDMMUX_ROT_CONSTSPEED   (0x01 << 4)
00078 #define HDMMUX_ROT_RAMPUP       (0x02 << 4)
00079 #define HDMMUX_ROT_RAMPDOWN     (0x03 << 4)
00080 
00081 #define HDMMUX_ROT_UNLIMITED    (0x00 << 2)
00082 #define HDMMUX_ROT_DEGREES      (0x01 << 2)
00083 #define HDMMUX_ROT_ROTATIONS    (0x02 << 2)
00084 #define HDMMUX_ROT_SECONDS      (0x03 << 2)
00085 
00086 #define HDMMUX_ROT_POWERCONTROL (0x01 << 1)
00087 
00088 #define HDMMUX_ROT_BRAKE        0x01
00089 #define HDMMUX_ROT_FLOAT        0x00
00090 
00091 tByteArray HDMMUX_I2CRequest;    /*!< Array to hold I2C command data */
00092 tByteArray HDMMUX_I2CReply;      /*!< Array to hold I2C reply data */
00093 
00094 // Function prototypes
00095 void HDMMUXinit();
00096 bool HDMMUXreadStatus(tSensors link, ubyte &motorStatus, long &tachoA, long &tachoB, long &tachoC);
00097 bool HDMMUXsendCommand(tSensors link, ubyte mode, ubyte channel, ubyte rotparams, long duration, byte power, byte steering);
00098 bool HDMMotor(tMUXmotor muxmotor, byte power);
00099 bool HDMotorStop(tMUXmotor muxmotor);
00100 bool HDMotorStop(tMUXmotor muxmotor, bool brake);
00101 void HDMMotorSetRotationTarget(tMUXmotor muxmotor, float rottarget);
00102 void HDMMotorSetTimeTarget(tMUXmotor muxmotor, float timetarget);
00103 void HDMMotorSetEncoderTarget(tMUXmotor muxmotor, long enctarget);
00104 long HDMMotorEncoder(tMUXmotor muxmotor);
00105 bool HDMMotorEncoderReset(tMUXmotor muxmotor);
00106 bool HDMMotorEncoderResetAll(tSensors link);
00107 bool HDMMotorBusy(tMUXmotor muxmotor);
00108 void HDMMotorSetBrake(tMUXmotor muxmotor);
00109 void HDMMotorSetFloat(tMUXmotor muxmotor);
00110 void HDMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed);
00111 void HDMMotorSetRamping(tMUXmotor muxmotor, ubyte ramping);
00112 
00113 /*
00114  * Initialise the mmuxData array needed for keeping track of motor settings
00115  */
00116 void HDMMUXinit(){
00117   for (int i = 0; i < 4; i++) {
00118     memset(mmuxData[i].runToTarget[0], false, 4);
00119     memset(mmuxData[i].brake[0], true, 4);
00120     memset(mmuxData[i].pidcontrol[0], true, 4);
00121     memset(mmuxData[i].target[0], 0, 4*4);
00122     memset(mmuxData[i].ramping[0], HDMMUX_ROT_CONSTSPEED, 4);
00123     memset(mmuxData[i].targetUnit[0], HDMMUX_ROT_UNLIMITED, 4);
00124     mmuxData[i].initialised = true;
00125   }
00126 }
00127 
00128 
00129 /**
00130  * Read the status of the motors and tacho counts of the MMUX
00131  *
00132  * motorStatus is made of 3 bits, 1: motor is running, 0: motor is idle\n
00133  * bit 0: motor A\n
00134  * bit 1: motor B\n
00135  * bit 2: motor C\n
00136  *
00137  * @param link the MMUX port number
00138  * @param motorStatus status of the motors
00139  * @param tachoA Tacho count for motor A
00140  * @param tachoB Tacho count for motor B
00141  * @param tachoC Tacho count for motor C
00142  * @return true if no error occured, false if it did
00143  */
00144 bool HDMMUXreadStatus(tSensors link, ubyte &motorStatus, long &tachoA, long &tachoB, long &tachoC) {
00145   memset(HDMMUX_I2CRequest, 0, sizeof(tByteArray));
00146 
00147   HDMMUX_I2CRequest[0]  = 10;               // Message size
00148   HDMMUX_I2CRequest[1]  = HDMMUX_I2C_ADDR; // I2C Address
00149 
00150   if (!writeI2C(link, HDMMUX_I2CRequest, HDMMUX_I2CReply, 13))
00151     return false;
00152 
00153   motorStatus = HDMMUX_I2CReply[0];
00154 
00155   // Assemble and assign the encoder values
00156   tachoA = (HDMMUX_I2CReply[1] << 24) + (HDMMUX_I2CReply[2] << 16) + (HDMMUX_I2CReply[3] << 8) + (HDMMUX_I2CReply[4] << 0);
00157   tachoB = (HDMMUX_I2CReply[5] << 24) + (HDMMUX_I2CReply[6] << 16) + (HDMMUX_I2CReply[7] << 8) + (HDMMUX_I2CReply[8] << 0);
00158   tachoC = (HDMMUX_I2CReply[9] << 24) + (HDMMUX_I2CReply[10] << 16) + (HDMMUX_I2CReply[11] << 8) + (HDMMUX_I2CReply[12] << 0);
00159 
00160   return true;
00161 }
00162 
00163 
00164 /**
00165  * Send a command to the MMUX.
00166  *
00167  * Note: this is an internal function and shouldn't be used directly
00168  * @param link the MMUX port number
00169  * @param mode the mode the MMX should operate in, controlling motors, resetting tachos or settings new address
00170  * @param channel the motors the command applies to
00171  * @param rotparams the additional parameters that make up the command
00172  * @param duration the number of units (can be seconds, rotations or degrees) the command should be run for
00173  * @param power the amount of power to be applied to the motor(s)
00174  * @param steering used for syncronised movement to control the amount of steering
00175  * @return true if no error occured, false if it did
00176  */
00177 bool HDMMUXsendCommand(tSensors link, ubyte mode, ubyte channel, ubyte rotparams, long duration, byte power, byte steering) {
00178   memset(HDMMUX_I2CRequest, 0, sizeof(tByteArray));
00179 
00180   HDMMUX_I2CRequest[0]  = 10;               // Message size
00181   HDMMUX_I2CRequest[1]  = HDMMUX_I2C_ADDR; // I2C Address
00182   HDMMUX_I2CRequest[2]  = mode;
00183   HDMMUX_I2CRequest[3]  = channel;
00184   HDMMUX_I2CRequest[4]  = rotparams;
00185   HDMMUX_I2CRequest[5]  = (duration >> 24) & 0xFF;
00186   HDMMUX_I2CRequest[6]  = (duration >> 16) & 0xFF;
00187   HDMMUX_I2CRequest[7]  = (duration >>  8) & 0xFF;
00188   HDMMUX_I2CRequest[8]  = (duration >>  0) & 0xFF;
00189   HDMMUX_I2CRequest[9]  = power;
00190   HDMMUX_I2CRequest[10] = (byte)(steering & 0xFF);
00191 
00192   return writeI2C(link, HDMMUX_I2CRequest);
00193 }
00194 
00195 
00196 /**
00197  * Run motor with specified speed.
00198  *
00199  * @param muxmotor the motor-MUX motor
00200  * @param power power the amount of power to apply to the motor, value between -100 and +100
00201  * @return true if no error occured, false if it did
00202  */
00203 bool HDMMotor(tMUXmotor muxmotor, byte power) {
00204   ubyte command = 0;
00205   bool retval = true;
00206   long target = mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)];
00207 
00208   command |= (mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]) ? HDMMUX_ROT_BRAKE : HDMMUX_ROT_FLOAT;
00209   command |= mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)];
00210   command |= (mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)]) ? HDMMUX_ROT_POWERCONTROL : 0;
00211   command |= (power > 0) ? HDMMUX_ROT_FORWARD : HDMMUX_ROT_REVERSE;
00212   command |= mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)];
00213 
00214   retval = HDMMUXsendCommand((tSensors)SPORT(muxmotor), HDMMUX_CMD_MOTOR, (ubyte)MPORT(muxmotor) + 1, command, target, abs(power), 0);
00215 
00216   // Reset the data
00217   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_UNLIMITED;
00218   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = 0;
00219 
00220   return retval;
00221 }
00222 
00223 
00224 /**
00225  * Stop the motor. Uses the brake method specified with HDMMotorSetBrake or HDMMotorSetFloat.
00226  * The default is to use braking.
00227  *
00228  * @param muxmotor the motor-MUX motor
00229  * @return true if no error occured, false if it did
00230  */
00231 bool HDMotorStop(tMUXmotor muxmotor) {
00232   ubyte command = 0;
00233   bool retval = true;
00234 
00235   command |= (mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]) ? HDMMUX_ROT_BRAKE : HDMMUX_ROT_FLOAT;
00236   command |= HDMMUX_ROT_STOP;
00237 
00238   retval = HDMMUXsendCommand((tSensors)SPORT(muxmotor), HDMMUX_CMD_MOTOR, (ubyte)MPORT(muxmotor) + 1, command, 0, 0, 0);
00239 
00240   // Reset the data
00241   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_UNLIMITED;
00242   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = 0;
00243 
00244   return retval;
00245 }
00246 
00247 
00248 /**
00249  * Stop the motor. This function overrides the preconfigured braking method.
00250  *
00251  * @param muxmotor the motor-MUX motor
00252  * @param brake when set to true: use brake, false: use float
00253  * @return true if no error occured, false if it did
00254  */
00255 bool HDMotorStop(tMUXmotor muxmotor, bool brake) {
00256   ubyte command = 0;
00257   bool retval = true;
00258 
00259   command |= (brake) ? HDMMUX_ROT_BRAKE : HDMMUX_ROT_FLOAT;
00260   command |= HDMMUX_ROT_STOP;
00261 
00262   retval = HDMMUXsendCommand((tSensors)SPORT(muxmotor), HDMMUX_CMD_MOTOR, (ubyte)MPORT(muxmotor) + 1, command, 0, 0, 0);
00263 
00264   // Reset the data
00265   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_UNLIMITED;
00266   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = 0;
00267 
00268   return retval;
00269 }
00270 
00271 
00272 /**
00273  * Set rotation target for specified mux motor. Rotations can be specified in
00274  * increments of 0.01.  To rotate the motor 10.54 degrees, specify a value of 10.54.
00275  *
00276  * @param muxmotor the motor-MUX motor
00277  * @param rottarget the rotation target value
00278  * @return true if no error occured, false if it did
00279  */
00280 void HDMMotorSetRotationTarget(tMUXmotor muxmotor, float rottarget) {
00281   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = (long)(rottarget * 100);
00282   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_ROTATIONS;
00283 }
00284 
00285 
00286 /**
00287  * Set time target for specified mux motor. Seconds can be specified in
00288  * increments of 0.01.  To rotate the motor for 10.21 seconds, specify a value of 10.21.
00289  *
00290  * @param muxmotor the motor-MUX motor
00291  * @param timetarget the time target value in seconds.
00292  * @return true if no error occured, false if it did
00293  */
00294 void HDMMotorSetTimeTarget(tMUXmotor muxmotor, float timetarget) {
00295   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = (long)(timetarget * 100);
00296   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_SECONDS;
00297 }
00298 
00299 
00300 /**
00301  * Set encoder target for specified mux motor.
00302  *
00303  * @param muxmotor the motor-MUX motor
00304  * @param enctarget the encoder target value in degrees.
00305  * @return true if no error occured, false if it did
00306  */
00307 void HDMMotorSetEncoderTarget(tMUXmotor muxmotor, long enctarget) {
00308   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = enctarget;
00309   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = HDMMUX_ROT_DEGREES;
00310 }
00311 
00312 
00313 /**
00314  * Fetch the current encoder value for specified motor channel
00315  *
00316  * @param muxmotor the motor-MUX motor
00317  * @return the current value of the encoder
00318  */
00319 long HDMMotorEncoder(tMUXmotor muxmotor) {
00320   long encA  = 0;
00321   long encB  = 0;
00322   long encC  = 0;
00323   ubyte dummy = 0;
00324 
00325   HDMMUXreadStatus((tSensors)SPORT(muxmotor), dummy, encA, encB, encC);
00326 
00327   switch ((ubyte)MPORT(muxmotor)) {
00328     case 0: return encA;
00329     case 1: return encB;
00330     case 2: return encC;
00331   }
00332 
00333   return 0;
00334 }
00335 
00336 
00337 /**
00338  * Reset target encoder for specified motor channel, use only at
00339  * the start of your program.  If you are using the standard NXT wheels
00340  * you will not run into problems with a wrap-around for the first 500kms
00341  * or so.
00342  *
00343  * @param muxmotor the motor-MUX motor
00344  * @return true if no error occured, false if it did
00345  */
00346 bool HDMMotorEncoderReset(tMUXmotor muxmotor) {
00347   ubyte mode = 0;
00348 
00349   switch ((ubyte)MPORT(muxmotor)) {
00350     case 0: mode = HDMMUX_CMD_RST_TACH_A; break;
00351     case 1: mode = HDMMUX_CMD_RST_TACH_B; break;
00352     case 2: mode = HDMMUX_CMD_RST_TACH_C; break;
00353   }
00354 
00355   return HDMMUXsendCommand((tSensors)SPORT(muxmotor), mode, 0, 0, 0, 0, 0);
00356 }
00357 
00358 
00359 /**
00360  * Reset all encoders on the specified motor-MUX. Use only at
00361  * the start of your program.  If you are using the standard NXT wheels
00362  * you will not run into problems with a wrap-around for the first 500kms
00363  * or so.
00364  *
00365  * @param link the MMUX port number
00366  * @return true if no error occured, false if it did
00367  */
00368 bool HDMMotorEncoderResetAll(tSensors link) {
00369   if (!HDMMUXsendCommand(link, HDMMUX_CMD_RST_TACH_A, 0, 0, 0, 0, 0))
00370     return false;
00371 
00372   if (!HDMMUXsendCommand(link, HDMMUX_CMD_RST_TACH_B, 0, 0, 0, 0, 0))
00373     return false;
00374 
00375   if (!HDMMUXsendCommand(link, HDMMUX_CMD_RST_TACH_C, 0, 0, 0, 0, 0))
00376     return false;
00377 
00378   return true;
00379 }
00380 
00381 
00382 /**
00383  * Check if the specified motor is running or not.
00384  *
00385  * @param muxmotor the motor-MUX motor
00386  * @return true if the motor is still running, false if it's idle
00387  */
00388 bool HDMMotorBusy(tMUXmotor muxmotor) {
00389   long dummy  = 0;
00390   ubyte motorStatus = 0;
00391 
00392   HDMMUXreadStatus((tSensors)SPORT(muxmotor), motorStatus, dummy, dummy, dummy);
00393 
00394   switch ((ubyte)MPORT(muxmotor)) {
00395     case 0: return ((motorStatus & 0x01) == 0x01);
00396     case 1: return ((motorStatus & 0x02) == 0x02);
00397     case 2: return ((motorStatus & 0x04) == 0x04);
00398   }
00399 
00400   return true;
00401 }
00402 
00403 
00404 /**
00405  * Set the stopping method for the specified motor to brake.
00406  *
00407  * @param muxmotor the motor-MUX motor
00408  */
00409 void HDMMotorSetBrake(tMUXmotor muxmotor) {
00410   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = true;
00411 }
00412 
00413 
00414 /**
00415  * Set the stopping method for the specified motor to float.
00416  *
00417  * @param muxmotor the motor-MUX motor
00418  */
00419 void HDMMotorSetFloat(tMUXmotor muxmotor) {
00420   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = false;
00421 }
00422 
00423 
00424 /**
00425  * Set the motor speed control for the specified motor.
00426  *
00427  * @param muxmotor the motor-MUX motor
00428  * @param constspeed whether or not to use speed control
00429  */
00430 void HDMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed) {
00431   mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)] = true;
00432 }
00433 
00434 
00435 /**
00436  * Set the motor ramping type the specified motor.
00437  * ramping can be one of\n
00438  * - HDMMUX_ROT_CONSTSPEED
00439  * - HDMMUX_ROT_RAMPUP
00440  * - HDMMUX_ROT_RAMPDOWN
00441  *
00442  * @param muxmotor the motor-MUX motor
00443  * @param ramping the type of ramping to be used
00444  */
00445 void HDMMotorSetRamping(tMUXmotor muxmotor, ubyte ramping) {
00446   mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)] = ramping;
00447 }
00448 
00449 #endif //  __HDMMUX_H__
00450 
00451 /*
00452  * $Id: holitdata-motormux.h 133 2013-03-10 15:15:38Z xander $
00453  */
00454 /* @} */
00455 /* @} */