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

mindsensors-motormux.h

Go to the documentation of this file.
00001 /*!@addtogroup mindsensors
00002  * @{
00003  * @defgroup msmmux NXT Motor MUX
00004  * NXT Motor MUX
00005  * @{
00006  */
00007 
00008 /*
00009  * $Id: mindsensors-motormux.h 133 2013-03-10 15:15:38Z xander $
00010  */
00011 
00012 #ifndef __MSMMUX_H__
00013 #define __MSMMUX_H__
00014 /** \file mindsensors-motormux.h
00015  * \brief Mindsensors Motor MUX driver
00016  *
00017  * mindsensors-motormux.h provides an API for the Mindsensors Motor MUX.
00018  *
00019  * Changelog:
00020  * - 0.1: Initial release
00021  *
00022  * Credits:
00023  * - Big thanks to Mindsensors for providing me with the hardware necessary to write and test this.
00024  *
00025  * License: You may use this code as you wish, provided you give credit where its due.
00026  *
00027  * THIS CODE WILL ONLY WORK WITH ROBOTC VERSION 3.59 AND HIGHER. 
00028 
00029  * \author Xander Soldaat (xander_at_botbench.com)
00030  * \date 05 April 2010
00031  * \version 0.1
00032  * \example mindsensors-motormux-test1.c
00033  * \example mindsensors-motormux-test2.c
00034  */
00035 
00036 #pragma systemFile
00037 
00038 #ifndef __COMMON_H__
00039 #include "common.h"
00040 #endif
00041 
00042 #ifndef __MMUX_H__
00043 #include "common-MMUX.h"
00044 #endif
00045 
00046 #define MSMMUX_I2C_ADDR         0x06  /*!< MSMMUX I2C device address */
00047 
00048 // Motor control registers
00049 #define MSMMUX_REG_CMD          0x41  /*!< Command register */
00050 
00051 #define MSMMUX_MOT_OFFSET       0x42  /*!< Motor regiser offset */
00052 #define MSMMUX_TARG_ENC         0x00  /*!< Target encoder value */
00053 #define MSMMUX_POWER            0x04  /*!< Motor power */
00054 #define MSMMUX_TARG_TIME        0x05  /*!< Time target value */
00055 #define MSMMUX_CMD_B            0x06  /*!< Command B register - for future use */
00056 #define MSMMUX_CMD_A            0x07  /*!< Command A regiser */
00057 #define MSMMUX_ENTRY_SIZE       0x08  /*!< Number of registers per motor channel */
00058 #define MSMMUX_TACHO_MOT1       0x62  /*!< Tacho count for motor 1 */
00059 #define MSMMUX_TACHO_MOT2       0x66  /*!< Tacho count for motor 2 */
00060 #define MSMMUX_STATUS_MOT1      0x72  /*!< Status for motor 1 */
00061 #define MSMMUX_STATUS_MOT2      0x73  /*!< Status for motor 2 */
00062 
00063 // PID registers
00064 #define MSMMUX_KP_TACHO         0x7A  /*!< Kp for Tachometer Position Control */
00065 #define MSMMUX_KI_TACHO         0x7C  /*!< Ki for Tachometer Position Control */
00066 #define MSMMUX_KD_TACHO         0x7E  /*!< Kd for Tachometer Position Control */
00067 #define MSMMUX_KP_SPEED         0x80  /*!< Kp for Speed Control */
00068 #define MSMMUX_KI_SPEED         0x82  /*!< Ki for Speed Control */
00069 #define MSMMUX_KD_SPEED         0x84  /*!< Kd for Speed Control */
00070 #define MSMMUX_PASSCOUNT        0x86  /*!< Encoder count tolerance when motor is moving */
00071 #define MSMMUX_TOLERANCE        0x87  /*!< Encoder count tolerance when motor is getting close to target */
00072 
00073 // Motor mode commands
00074 #define MSMMUX_CMD_RESET_ALL    0x52  /*!< Reset the tachos and motor values */
00075 #define MSMMUX_CMD_START_BOTH   0x53  /*!< Start both motors with parameters in motor registers */
00076 #define MSMMUX_CMD_FLOAT_MOT1   0x61  /*!< Stop motor 1 and allow to float */
00077 #define MSMMUX_CMD_FLOAT_MOT2   0x62  /*!< Stop motor 2 and allow to float */
00078 #define MSMMUX_CMD_FLOAT_BOTH   0x63  /*!< Stop both motors and allow to float */
00079 #define MSMMUX_CMD_BRAKE_MOT1   0x41  /*!< Stop motor 1 and brake */
00080 #define MSMMUX_CMD_BRAKE_MOT2   0x42  /*!< Stop motor 2 and brake */
00081 #define MSMMUX_CMD_BRAKE_BOTH   0x43  /*!< Stop both motors and brake */
00082 #define MSMMUX_CMD_RESET_MOT1   0x72  /*!< Reset the encoder count for motor 1 */
00083 #define MSMMUX_CMD_RESET_MOT2   0x73  /*!< Reset the encoder count for motor 2 */
00084 
00085 // Motor status fields
00086 #define MSMMUX_STAT_SPEED_CTRL  (0x01 << 0) /*!< Motor is programmed to move at a fixed speed. */
00087 #define MSMMUX_STAT_RAMPING     (0x01 << 1) /*!< Motor is currently ramping up or down */
00088 #define MSMMUX_STAT_POWERED     (0x01 << 2) /*!< Motor is powered, does not imply movement */
00089 #define MSMMUX_STAT_POS_CTRL    (0x01 << 3) /*!< Motor is either moving towards target or holding position. */
00090 #define MSMMUX_STAT_BRAKED      (0x01 << 4) /*!< Motor is braked.  0 means motor is floating */
00091 #define MSMMUX_STAT_OVERLOADED  (0x01 << 5) /*!< Set to 1 when motor can't achieve desired speed */
00092 #define MSMMUX_STAT_TIMED       (0x01 << 6) /*!< Motor is running for a specified duration */
00093 #define MSMMUX_STAT_STALLED     (0x01 << 7) /*!< Motor is stalled */
00094 
00095 // commandA fields
00096 #define MSMMUX_CMD_SPEED        0x01  /*!< Speed control of your motor */
00097 #define MSMMUX_CMD_RAMP         0x02  /*!< Ramp the speed up or down */
00098 #define MSMMUX_CMD_RELATIVE     0x04  /*!< Make encoder target relative to current position */
00099 #define MSMMUX_CMD_TACHO        0x08  /*!< Use the encoder target to control motor */
00100 #define MSMMUX_CMD_BRK          0x10  /*!< Whether to brake (1) or float (0) when motor has reached its target */
00101 #define MSMMUX_CMD_HOLDPOS      0x20  /*!< Motor will hold position when this is enabled and push back when moved */
00102 #define MSMMUX_CMD_TIME         0x40  /*!< Use the time target to control the motor */
00103 #define MSMMUX_CMD_GO           0x80  /*!< Instruct the MUX to start the motors using the current registers */
00104 
00105 #define MSMMUX_RAMP_NONE        0x00  /*!< Use no ramping at all */
00106 #define MSMMUX_RAMP_UP_DOWN     0x03  /*!< Use ramping to bring motor up to speed or to a halt */
00107 
00108 #define MSMMUX_ROT_UNLIMITED    0x00  /*!< Allow motor to rotate forever (or until batteries run out, of course) */
00109 #define MSMMUX_ROT_DEGREES      0x01  /*!< Use encoder target to control motor (ie rotate motor X number of degrees) */
00110 //#define MSMMUX_ROT_ROTATIONS    0x02
00111 #define MSMMUX_ROT_SECONDS      0x03  /*!< Use time target to control motor (ie run for X seconds) */
00112 
00113 
00114 tByteArray MSMMUX_I2CRequest;    /*!< Array to hold I2C command data */
00115 tByteArray MSMMUX_I2CReply;      /*!< Array to hold I2C reply data */
00116 
00117 // Function prototypes
00118 void MSMMUXinit();
00119 bool MSMMUXreadStatus(tMUXmotor muxmotor, ubyte &motorStatus);
00120 bool MSMMUXsendCommand(tSensors link, ubyte channel, long setpoint, byte speed, ubyte seconds, ubyte commandA, ubyte address = MSMMUX_I2C_ADDR);
00121 bool MSMMUXsendCommand(tSensors link, ubyte command, ubyte address = MSMMUX_I2C_ADDR);
00122 bool MSMMUXsetPID(tSensors link, unsigned int kpTacho, unsigned int kiTacho, unsigned int kdTacho, unsigned int kpSpeed, unsigned int kiSpeed, unsigned int kdSpeed, ubyte passCount, ubyte tolerance, ubyte address = MSMMUX_I2C_ADDR);
00123 // bool MSMMUXsetPID(tSensors link, int kpTacho, int kiTacho, int kdTacho, int kpSpeed, int kiSpeed, int kdSpeed, ubyte passCount, ubyte tolerance, ubyte address = MSMMUX_I2C_ADDR);
00124 bool MSMMotor(tMUXmotor muxmotor, byte power, ubyte address = MSMMUX_I2C_ADDR);
00125 bool MSMotorStop(tMUXmotor muxmotor, ubyte address = MSMMUX_I2C_ADDR);
00126 bool MSMotorStop(tMUXmotor muxmotor, bool brake, ubyte address = MSMMUX_I2C_ADDR);
00127 void MSMMotorSetRotationTarget(tMUXmotor muxmotor, long target);
00128 void MSMMotorSetTimeTarget(tMUXmotor muxmotor, int target);
00129 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target);
00130 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target, bool relative);
00131 long MSMMotorEncoder(tMUXmotor muxmotor, ubyte address = MSMMUX_I2C_ADDR);
00132 bool MSMMotorEncoderReset(tMUXmotor muxmotor, ubyte address = MSMMUX_I2C_ADDR);
00133 bool MSMMotorEncoderResetAll(tSensors link, ubyte address = MSMMUX_I2C_ADDR);
00134 bool MSMMotorBusy(tMUXmotor muxmotor, ubyte address = MSMMUX_I2C_ADDR);
00135 bool MSMMotorStalled(tMUXmotor muxmotor, ubyte address = MSMMUX_I2C_ADDR);
00136 void MSMMotorSetBrake(tMUXmotor muxmotor);
00137 void MSMMotorSetFloat(tMUXmotor muxmotor);
00138 void MSMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed);
00139 void MSMMotorSetRamping(tMUXmotor muxmotor, bool ramping);
00140 
00141 
00142 /*
00143  * Initialise the mmuxData array needed for keeping track of motor settings
00144  */
00145 void MSMMUXinit(){
00146   for (int i = 0; i < 4; i++) {
00147     memset(mmuxData[i].runToTarget[0], false, 4);
00148     memset(mmuxData[i].brake[0], true, 4);
00149     memset(mmuxData[i].pidcontrol[0], true, 4);
00150     memset(mmuxData[i].target[0], 0, 4*4);
00151     memset(mmuxData[i].ramping[0], MSMMUX_RAMP_NONE, 4);
00152     memset(mmuxData[i].targetUnit[0], MSMMUX_ROT_UNLIMITED, 4);
00153     mmuxData[i].initialised = true;
00154   }
00155 }
00156 
00157 
00158 /**
00159  * Read the status byte of the specified motor
00160  *
00161  * @param muxmotor the motor-MUX motor
00162  * @param motorStatus status of the motor
00163  * @param address I2C address of the sensor (optional)
00164  * @return true if no error occured, false if it did
00165  */
00166 bool MSMMUXreadStatus(tMUXmotor muxmotor, ubyte &motorStatus, ubyte address) {
00167 
00168   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00169 
00170   MSMMUX_I2CRequest[0] = 2;               // Message size
00171   MSMMUX_I2CRequest[1] = MSMMUX_I2C_ADDR; // I2C Address
00172 
00173   switch ((byte)MPORT(muxmotor)) {
00174     case 0: MSMMUX_I2CRequest[2] = MSMMUX_STATUS_MOT1; break;
00175     case 1: MSMMUX_I2CRequest[2] = MSMMUX_STATUS_MOT2; break;
00176   }
00177 
00178   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest, MSMMUX_I2CReply, 1))
00179     return false;
00180 
00181   motorStatus = MSMMUX_I2CReply[0];
00182 
00183   return true;
00184 }
00185 
00186 
00187 /**
00188  * Send a command to the MMUX.
00189  *
00190  * Note: this is an internal function and shouldn't be used directly
00191  * @param link the MMUX port number
00192  * @param channel the channel the command should apply to
00193  * @param setpoint the encoder count the motor should move to
00194  * @param speed the speed the motor should move at
00195  * @param seconds the number of seconds the motor should run for.  Note that this takes precedence over the encoder target
00196  * @param commandA the command to be sent to the motor
00197  * @param address I2C address of the sensor (optional)
00198  * @return true if no error occured, false if it did
00199  */
00200 bool MSMMUXsendCommand(tSensors link, ubyte channel, long setpoint, byte speed, ubyte seconds, ubyte commandA, ubyte address) {
00201   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00202 
00203   MSMMUX_I2CRequest[0] = 10;               // Message size
00204   MSMMUX_I2CRequest[1] = address;          // I2C Address
00205   MSMMUX_I2CRequest[2] = MSMMUX_MOT_OFFSET + (channel * MSMMUX_ENTRY_SIZE);
00206   MSMMUX_I2CRequest[3] = (setpoint >>  0) & 0xFF;
00207   MSMMUX_I2CRequest[4] = (setpoint >>  8) & 0xFF;
00208   MSMMUX_I2CRequest[5] = (setpoint >> 16) & 0xFF;
00209   MSMMUX_I2CRequest[6] = (setpoint >> 24) & 0xFF;
00210   MSMMUX_I2CRequest[7] = (speed & 0xFF);
00211   MSMMUX_I2CRequest[8] = seconds;
00212   MSMMUX_I2CRequest[9] = 0;
00213   MSMMUX_I2CRequest[10] = commandA;
00214 
00215   // make sure the targetUnit is reset for the next time
00216   mmuxData[link].targetUnit[channel] = MSMMUX_ROT_UNLIMITED;
00217 
00218   // send the command to the mmux
00219   return writeI2C(link, MSMMUX_I2CRequest);
00220 
00221 }
00222 
00223 
00224 /**
00225  * Send a command to the MMUX.
00226  *
00227  * Note: this is an internal function and shouldn't be used directly
00228  * @param link the MMUX port number
00229  * @param command the command to be sent to the motor
00230  * @param address I2C address of the sensor (optional)
00231  * @return true if no error occured, false if it did
00232  */
00233 bool MSMMUXsendCommand(tSensors link, ubyte command, ubyte address) {
00234   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00235 
00236   MSMMUX_I2CRequest[0] = 3;               // Message size
00237   MSMMUX_I2CRequest[1] = address; // I2C Address
00238   MSMMUX_I2CRequest[2] = MSMMUX_REG_CMD;
00239   MSMMUX_I2CRequest[3] = command;
00240 
00241   return writeI2C(link, MSMMUX_I2CRequest);
00242 }
00243 
00244 
00245 /**
00246  * Configure the internal PID controller.  Tweaking these values will change the
00247  * behaviour of the motors, how they approach their target, how they maintain speed, etc.
00248  * These settings do not persist, disconnecting the MUX will reset these values to their
00249  * defaults.  These settings are MUX-wide, so will apply to how BOTH motors are controlled.
00250  *
00251  * Please refer to the User Guide for more detailed information on how these parameters
00252  * should be used.
00253  *
00254  * @param link the MMUX port number
00255  * @param kpTacho Kp for Tachometer Position Control
00256  * @param kiTacho Ki for Tachometer Position Control
00257  * @param kdTacho Kd for Tachometer Position Control
00258  * @param kpSpeed Kp for Speed Control
00259  * @param kiSpeed Ki for Speed Control
00260  * @param kdSpeed Kd for Speed Control
00261  * @param passCount Encoder count tolerance when motor is moving
00262  * @param tolerance Encoder count tolerance when motor is getting close to target
00263  * @param address I2C address of the sensor (optional)
00264  * @return true if no error occured, false if it did
00265  */
00266 bool MSMMUXsetPID(tSensors link, unsigned int kpTacho, unsigned int kiTacho, unsigned int kdTacho, unsigned int kpSpeed, unsigned int kiSpeed, unsigned int kdSpeed, ubyte passCount, ubyte tolerance, ubyte address) {
00267   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00268 
00269   MSMMUX_I2CRequest[0] = 16;               // Message size
00270   MSMMUX_I2CRequest[1] = address; // I2C Address
00271   MSMMUX_I2CRequest[2] = MSMMUX_KP_TACHO;
00272   MSMMUX_I2CRequest[3] = kpTacho & 0xFF;
00273   MSMMUX_I2CRequest[4] = (kpTacho >> 8) & 0xFF;
00274   MSMMUX_I2CRequest[5] = kiTacho & 0xFF;
00275   MSMMUX_I2CRequest[6] = (kiTacho >> 8) & 0xFF;
00276   MSMMUX_I2CRequest[7] = kdTacho & 0xFF;
00277   MSMMUX_I2CRequest[8] = (kdTacho >> 8) & 0xFF;
00278   MSMMUX_I2CRequest[9] = kpSpeed & 0xFF;
00279   MSMMUX_I2CRequest[10] = (kpSpeed >> 8) & 0xFF;
00280   MSMMUX_I2CRequest[11] = kiSpeed & 0xFF;
00281   MSMMUX_I2CRequest[12] = (kiSpeed >> 8) & 0xFF;
00282   MSMMUX_I2CRequest[13] = kdSpeed & 0xFF;
00283   MSMMUX_I2CRequest[14] = (kdSpeed >> 8) & 0xFF;
00284   MSMMUX_I2CRequest[15] = passCount;
00285   MSMMUX_I2CRequest[16] = tolerance;
00286 
00287   return writeI2C(link, MSMMUX_I2CRequest);
00288 }
00289 
00290 
00291 /**
00292  * Run motor with specified speed.
00293  *
00294  * @param muxmotor the motor-MUX motor
00295  * @param power power the amount of power to apply to the motor, value between -100 and +100
00296  * @param address I2C address of the sensor (optional)
00297  * @return true if no error occured, false if it did
00298  */
00299 bool MSMMotor(tMUXmotor muxmotor, byte power, ubyte address) {
00300   ubyte commandA = 0;
00301   commandA += (mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)]) ? MSMMUX_CMD_SPEED : 0;
00302   commandA += (mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)] != MSMMUX_RAMP_NONE) ? MSMMUX_CMD_RAMP : 0;
00303   commandA += (mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)]) ? MSMMUX_CMD_BRK : 0;
00304   commandA += (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] == MSMMUX_ROT_DEGREES) ? MSMMUX_CMD_TACHO : 0;
00305   commandA += (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] == MSMMUX_ROT_SECONDS) ? MSMMUX_CMD_TIME : 0;
00306   commandA += (mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)]) ? MSMMUX_CMD_RELATIVE : 0;
00307   commandA += MSMMUX_CMD_GO;
00308 
00309   switch (mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)]) {
00310     case MSMMUX_ROT_UNLIMITED: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), 0, power, 0, commandA, address);
00311     case MSMMUX_ROT_DEGREES:   return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)], power, 0, commandA, address);
00312     case MSMMUX_ROT_SECONDS:   return MSMMUXsendCommand((tSensors)SPORT(muxmotor), (ubyte)MPORT(muxmotor), 0, power, mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)], commandA, address);
00313   }
00314   return true;
00315 }
00316 
00317 
00318 /**
00319  * Stop the motor. Uses the brake method specified with MSMMotorSetBrake or MSMMotorSetFloat.
00320  * The default is to use braking.
00321  *
00322  * @param muxmotor the motor-MUX motor
00323  * @param address I2C address of the sensor (optional)
00324  * @return true if no error occured, false if it did
00325  */
00326 bool MSMotorStop(tMUXmotor muxmotor, ubyte address) {
00327   if (MPORT(muxmotor) == 0)
00328     return MSMotorStop(muxmotor, mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)], address);
00329   else if (MPORT(muxmotor) == 1)
00330     return MSMotorStop(muxmotor, mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)], address);
00331   return true;
00332 }
00333 
00334 
00335 /**
00336  * Stop the motor. This function overrides the preconfigured braking method.
00337  *
00338  * @param muxmotor the motor-MUX motor
00339  * @param brake when set to true: use brake, false: use float
00340  * @param address I2C address of the sensor (optional)
00341  * @return true if no error occured, false if it did
00342  */
00343 bool MSMotorStop(tMUXmotor muxmotor, bool brake, ubyte address) {
00344   if (MPORT(muxmotor) == 0)
00345     return MSMMUXsendCommand((tSensors)SPORT(muxmotor), brake ? MSMMUX_CMD_BRAKE_MOT1 : MSMMUX_CMD_FLOAT_MOT1, address);
00346   else if (MPORT(muxmotor) == 1)
00347     return MSMMUXsendCommand((tSensors)SPORT(muxmotor), brake ? MSMMUX_CMD_BRAKE_MOT2 : MSMMUX_CMD_FLOAT_MOT2, address);
00348   return true;
00349 }
00350 
00351 
00352 /**
00353  * Set rotation target for specified mux motor.
00354  *
00355  * @param muxmotor the motor-MUX motor
00356  * @param target the rotation target value
00357  * @return true if no error occured, false if it did
00358  */
00359 void MSMMotorSetRotationTarget(tMUXmotor muxmotor, long target) {
00360   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target * 360;
00361   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00362 }
00363 
00364 
00365 /**
00366  * Set time target for specified mux motor. Seconds can be specified in
00367  * increments of 1 second with an upper limit of 255 seconds.
00368  *
00369  * @param muxmotor the motor-MUX motor
00370  * @param target the time target value in seconds [1-255]
00371  * @return true if no error occured, false if it did
00372  */
00373 void MSMMotorSetTimeTarget(tMUXmotor muxmotor, int target) {
00374   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00375   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_SECONDS;
00376 }
00377 
00378 
00379 /**
00380  * Set encoder target for specified mux motor.  Target is relative to current position.
00381  *
00382  * @param muxmotor the motor-MUX motor
00383  * @param target the encoder target value in degrees.
00384  * @return true if no error occured, false if it did
00385  */
00386 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target) {
00387   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00388   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00389   mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)] = true;
00390 }
00391 
00392 
00393 /**
00394  * Set encoder target for specified mux motor.
00395  *
00396  * @param muxmotor the motor-MUX motor
00397  * @param target the encoder target value in degrees.
00398  * @param relative specified target is relative to current position.
00399  * @return true if no error occured, false if it did
00400  */
00401 void MSMMotorSetEncoderTarget(tMUXmotor muxmotor, long target, bool relative) {
00402   mmuxData[SPORT(muxmotor)].target[MPORT(muxmotor)] = target;
00403   mmuxData[SPORT(muxmotor)].targetUnit[MPORT(muxmotor)] = MSMMUX_ROT_DEGREES;
00404   mmuxData[SPORT(muxmotor)].relTarget[MPORT(muxmotor)] = relative;
00405 }
00406 
00407 
00408 /**
00409  * Fetch the current encoder value for specified motor channel
00410  *
00411  * @param muxmotor the motor-MUX motor
00412  * @param address I2C address of the sensor (optional)
00413  * @return the current value of the encoder
00414  */
00415 long MSMMotorEncoder(tMUXmotor muxmotor, ubyte address) {
00416   long result;
00417 
00418   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00419 
00420   MSMMUX_I2CRequest[0] = 2;               // Message size
00421   MSMMUX_I2CRequest[1] = address; // I2C Address
00422 
00423   switch ((byte)MPORT(muxmotor)) {
00424     case 0: MSMMUX_I2CRequest[2] = MSMMUX_TACHO_MOT1; break;
00425     case 1: MSMMUX_I2CRequest[2] = MSMMUX_TACHO_MOT2; break;
00426   }
00427 
00428   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest,  MSMMUX_I2CReply, 4))
00429     return 0;
00430 
00431   result = MSMMUX_I2CReply[0] + (MSMMUX_I2CReply[1]<<8) + (MSMMUX_I2CReply[2]<<16) + (MSMMUX_I2CReply[3]<<24);
00432 
00433   return result;
00434 }
00435 
00436 
00437 /**
00438  * Reset target encoder for specified motor channel, use only at
00439  * the start of your program.  If you are using the standard NXT wheels
00440  * you will not run into problems with a wrap-around for the first 500kms
00441  * or so.
00442  *
00443  * @param muxmotor the motor-MUX motor
00444  * @param address I2C address of the sensor (optional)
00445  * @return true if no error occured, false if it did
00446  */
00447 
00448 bool MSMMotorEncoderReset(tMUXmotor muxmotor, ubyte address) {
00449   switch((byte)MPORT(muxmotor)) {
00450     case 0: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), MSMMUX_CMD_RESET_MOT1, address); break;
00451     case 1: return MSMMUXsendCommand((tSensors)SPORT(muxmotor), MSMMUX_CMD_RESET_MOT2, address); break;
00452   }
00453   return false;
00454 }
00455 
00456 
00457 /**
00458  * Reset all encoders on the specified motor-MUX. Use only at
00459  * the start of your program.  If you are using the standard NXT wheels
00460  * you will not run into problems with a wrap-around for the first 500kms
00461  * or so.
00462  *
00463  * @param link the MMUX port number
00464  * @param address I2C address of the sensor (optional)
00465  * @return true if no error occured, false if it did
00466  */
00467 bool MSMMotorEncoderResetAll(tSensors link, ubyte address) {
00468   return MSMMUXsendCommand(link, MSMMUX_CMD_RESET_ALL, address);
00469 }
00470 
00471 
00472 /**
00473  * Check if the specified motor is running or not.
00474  *
00475  * @param muxmotor the motor-MUX motor
00476  * @param address I2C address of the sensor (optional)
00477  * @return true if the motor is still running, false if it's idle
00478  */
00479 bool MSMMotorBusy(tMUXmotor muxmotor, ubyte address) {
00480   ubyte status = 0;
00481   ubyte commandA = 0;
00482 
00483   // Fetch the last sent commandA
00484   memset(MSMMUX_I2CRequest, 0, sizeof(tByteArray));
00485 
00486   MSMMUX_I2CRequest[0] = 2;               // Message size
00487   MSMMUX_I2CRequest[1] = address; // I2C Address
00488   MSMMUX_I2CRequest[2] = MSMMUX_MOT_OFFSET + (MPORT(muxmotor) * MSMMUX_ENTRY_SIZE) + MSMMUX_CMD_A;
00489 
00490   if (!writeI2C((tSensors)SPORT(muxmotor), MSMMUX_I2CRequest, MSMMUX_I2CReply, 1))
00491     return false;
00492 
00493   commandA = MSMMUX_I2CReply[0];
00494 
00495   // If commandA is 0 then the motor can't be busy.
00496   if (commandA == 0)
00497     return false;
00498 
00499   if (!MSMMUXreadStatus(muxmotor, status, address))
00500     return false;
00501 
00502   if ((commandA & MSMMUX_ROT_UNLIMITED) == MSMMUX_ROT_UNLIMITED)
00503     return ((status & MSMMUX_STAT_POWERED) != 0);
00504   else if ((commandA & MSMMUX_ROT_DEGREES) == MSMMUX_ROT_DEGREES)
00505     return ((status & MSMMUX_STAT_POS_CTRL) != 0);
00506   else if ((commandA & MSMMUX_ROT_SECONDS) == MSMMUX_ROT_SECONDS)
00507     return ((status & MSMMUX_STAT_TIMED) != 0);
00508 
00509   return false;
00510 }
00511 
00512 
00513 /**
00514  * Check if the specified motor is running or not.
00515  *
00516  * @param muxmotor the motor-MUX motor
00517  * @param address I2C address of the sensor (optional)
00518  * @return true if the motor is still running, false if it's idle
00519  */
00520 bool MSMMotorStalled(tMUXmotor muxmotor, ubyte address) {
00521   ubyte status = 0;
00522   if (!MSMMUXreadStatus(muxmotor, status, address))
00523     return false;
00524 
00525   return ((status & MSMMUX_STAT_STALLED) != 0);
00526 }
00527 
00528 
00529 /**
00530  * Set the stopping method for the specified motor to brake.
00531  *
00532  * @param muxmotor the motor-MUX motor
00533  */
00534 void MSMMotorSetBrake(tMUXmotor muxmotor) {
00535   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = true;
00536 }
00537 
00538 
00539 /**
00540  * Set the stopping method for the specified motor to float.
00541  *
00542  * @param muxmotor the motor-MUX motor
00543  */
00544 void MSMMotorSetFloat(tMUXmotor muxmotor) {
00545   mmuxData[SPORT(muxmotor)].brake[MPORT(muxmotor)] = false;
00546 }
00547 
00548 
00549 /**
00550  * Set the motor speed control for the specified motor.
00551  *
00552  * @param muxmotor the motor-MUX motor
00553  * @param constspeed use speed control to ensure motor speed stays constant under varying load
00554  */
00555 void MSMMotorSetSpeedCtrl(tMUXmotor muxmotor, bool constspeed) {
00556   mmuxData[SPORT(muxmotor)].pidcontrol[MPORT(muxmotor)] = true;
00557 }
00558 
00559 
00560 /**
00561  * Set the ramping control for the specified motor.
00562  *
00563  * @param muxmotor the motor-MUX motor
00564  * @param ramping use ramping for starting and stopping the motor
00565  */
00566 void MSMMotorSetRamping(tMUXmotor muxmotor, bool ramping) {
00567   mmuxData[SPORT(muxmotor)].ramping[MPORT(muxmotor)] = (ramping) ? MSMMUX_RAMP_UP_DOWN : MSMMUX_RAMP_NONE;
00568 }
00569 
00570 #endif //  __MSMMUX_H__
00571 
00572 /*
00573  * $Id: mindsensors-motormux.h 133 2013-03-10 15:15:38Z xander $
00574  */
00575 /* @} */
00576 /* @} */