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

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