MakingThings
  • Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

servo.c

Go to the documentation of this file.
00001 /*********************************************************************************
00002 
00003  Copyright 2006-2008 MakingThings
00004 
00005  Licensed under the Apache License, 
00006  Version 2.0 (the "License"); you may not use this file except in compliance 
00007  with the License. You may obtain a copy of the License at
00008 
00009  http://www.apache.org/licenses/LICENSE-2.0 
00010  
00011  Unless required by applicable law or agreed to in writing, software distributed
00012  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
00013  CONDITIONS OF ANY KIND, either express or implied. See the License for
00014  the specific language governing permissions and limitations under the License.
00015 
00016 *********************************************************************************/
00017 
00018 // MakingThings - Make Controller Board - 2006
00019 
00020 /** \file servo.c 
00021   Servo Motor Controls.
00022   Methods for controlling up to 4 servo motors with the Make Application Board.
00023 */
00024 
00025 #include "servo.h"
00026 #include "io.h"
00027 #include "fasttimer.h"
00028 #include "config.h"
00029 
00030 #include "AT91SAM7X256.h"
00031 
00032 // These constants govern how long the pulse preamble is 
00033 // (SERVO_OFFSET) and how long the pulse can be (SERVO_MAX)
00034 // So... if you want the servo pulse to be 1ms-2ms, you'd 
00035 // set SERVO_MAX = 1000, SERVO_OFFEST = 1000
00036 // So... if you want the servo pulse to be 0.3ms-2.3ms, you'd 
00037 // set SERVO_MAX = 2000, SERVO_OFFEST = 300
00038 //#define SERVO_MAX_PULSE     1000
00039 #define SERVO_OFFSET  1000
00040 #define SERVO_MIN_POSITION  -512
00041 #define SERVO_MAX_POSITION  1536
00042 #define SERVO_MID_POSITION 512
00043 #define SERVO_CYCLE 2048
00044 #define SERVO_SAFE_MIN 0
00045 #define SERVO_SAFE_MAX 1023
00046 
00047 #if ( APPBOARD_VERSION == 50 )
00048   #define SERVO_0_IO IO_PA02
00049   #define SERVO_1_IO IO_PA02
00050   #define SERVO_2_IO IO_PA02
00051   #define SERVO_3_IO IO_PA02
00052 #endif
00053 #if ( APPBOARD_VERSION == 90 || APPBOARD_VERSION == 95 || APPBOARD_VERSION == 100 )
00054   #define SERVO_0_IO IO_PB24
00055   #define SERVO_1_IO IO_PA23
00056   #define SERVO_2_IO IO_PA21
00057   #define SERVO_3_IO IO_PA22
00058 #endif
00059 
00060 void DisableFIQFromThumb( void );
00061 void EnableFIQFromThumb( void );
00062 
00063 
00064 void Servo_IRQCallback( int id );
00065 
00066 static int Servo_Start( int index );
00067 static int Servo_Stop( int index );
00068 static int Servo_Init( void );
00069 static int Servo_Deinit( void );
00070 static int Servo_GetIo( int index );
00071 
00072 #define SERVO_COUNT 4
00073 
00074 typedef struct ServoControlS
00075 {
00076   int users;
00077   int speed;
00078   int positionRequested;
00079   int position;
00080   int pin;
00081   AT91S_PIO* pIoBase;
00082 } ServoControl;
00083 
00084 typedef struct ServoS
00085 {
00086   int users;
00087   int gap;
00088   int index;
00089   int state;
00090   FastTimerEntry fastTimerEntry;
00091   ServoControl* control[ SERVO_COUNT ];
00092 } Servo_;
00093 
00094 
00095 Servo_* Servo;
00096 
00097 /** \defgroup Servo Servo
00098   The Servo Motor subsystem controls speed and position control for up to 4 standard servo motors.
00099   Standard servos have a range of motion of approximately 180 degrees, although this varies from motor to motor.
00100   Be sure to plug in the connector with the correct orientation with regard to the GND/5V signals on the board.
00101 
00102   Because not all servo motors are created equal, and not all of them can be safely driven across all 180 degrees,
00103   the default (safe) range of motion is from values 0 to 1023.  The full range of motion is from -512 to 1536, but use this
00104   extra range cautiously if you don't know how your motor can handle it.  A little gentle experimentation should do the trick.
00105   
00106   You can also specify the speed with which the motors will respond to new position commands - a high
00107   value will result in an immediate response, while a lower value can offer some smoothing when appropriate.
00108   
00109   See the servo section in the <a href="http://www.makingthings.com/documentation/tutorial/application-board-overview/servos">
00110   Application Board overview</a> for more detailed info.
00111 * \ingroup Libraries
00112 * @{
00113 */
00114 
00115 /**
00116   Lock or unlock the I/O lines used by the servos.  
00117   Sets whether the specified Servo I/O is active.
00118   @param index An integer specifying which servo (0 - 3).
00119   @param state An integer specifying the active state - 1 (active) or 0 (inactive).
00120   @return Zero on success.
00121   
00122   \b Example
00123   \code
00124   // enable servo 2
00125   Servo_SetActive(2, 1);
00126   \endcode
00127 */
00128 int Servo_SetActive( int index, int state )
00129 {
00130   if ( index < 0 || index >= SERVO_COUNT )
00131     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00132 
00133   if ( state )
00134   {
00135     if( Servo == NULL )
00136     {
00137       int retVal = Servo_Init( );
00138       if( retVal != CONTROLLER_OK )
00139         return retVal;
00140     }
00141     return Servo_Start( index );
00142   }
00143   else
00144   {
00145     if( Servo == NULL )
00146       return -1;
00147 
00148     int retVal = Servo_Stop( index );
00149     if( retVal != CONTROLLER_OK )
00150       return retVal;
00151 
00152     if( --Servo->users <= 0 )
00153       retVal = Servo_Deinit( );
00154 
00155     return retVal;
00156   }
00157 }
00158 
00159 /**
00160   Check whether the I/O lines used by the servos are locked.
00161   @param index An integer specifying which servo (0-3).
00162   @return State - 1 (active) or 0 (inactive).
00163   
00164   \b Example
00165   \code
00166   if( Servo_GetActive(2) )
00167   {
00168     // Servo 2 is active
00169   }
00170   else
00171   {
00172     // Servo 2 is inactive
00173   }
00174   \endcode
00175 */
00176 int Servo_GetActive( int index )
00177 {
00178   if ( index < 0 || index >= SERVO_COUNT || Servo == NULL )
00179     return false;
00180   return Servo->control[ index ]->users > 0;
00181 }
00182 
00183 
00184 /** 
00185   Set the position of the specified servo motor.
00186   Most servos like to be driven within a "safe range" which usually ends up being somewhere around 110-120
00187   degrees range of motion, or thereabouts.  Some servos don't mind being driven all the way to their 180
00188   degree range of motion limit.  With this in mind, the range of values you can send to servos connected
00189   to the Make Controller Kit is as follows:
00190   - Values from 0-1023 correspond to the normal, or "safe", range of motion.  
00191   - You can also send values from -512 all the way up to 1536 to drive the servo through its full
00192   range of motion.
00193   
00194   Note that it is sometimes possible to damage your servo by driving it too far, so proceed with a bit of
00195   caution when using the extended range until you know your servos can handle it.
00196 
00197   @param index An integer specifying which servo (0 - 3).
00198   @param position An integer specifying the servo position (0 - 1023).
00199   @return status (0 = OK).
00200   
00201   \b Example
00202   \code
00203   // set servo 1 to midway through the "safe" range
00204   Servo_SetPosition(1, 512);
00205   \endcode
00206 */
00207 int Servo_SetPosition( int index, int position )
00208 {
00209   if ( index < 0 || index >= SERVO_COUNT )
00210     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00211 
00212   Servo_SetActive( index, 1 );
00213 
00214   if ( position < SERVO_MIN_POSITION )
00215     position = SERVO_SAFE_MIN;
00216   if ( position > SERVO_MAX_POSITION )
00217     position = SERVO_SAFE_MAX;
00218 
00219   position += SERVO_OFFSET;
00220 
00221   DisableFIQFromThumb();
00222   Servo->control[ index ]->positionRequested = position << 6;
00223   EnableFIQFromThumb();
00224 
00225   return CONTROLLER_OK;
00226 }
00227 
00228 /** 
00229   Set the speed at which a servo will move in response to a call to Servo_SetPosition().
00230   Higher values will result in a more immediate response, while lower values will more slowly step through
00231   all the intermediate values, achieving a smoother motion.  
00232   @param index An integer specifying which servo (0 - 3).
00233   @param speed An integer specifying the servo speed (0 - 1023).
00234   @return status (0 = OK).
00235   
00236   \b Example
00237   \code
00238   // set servo 1 half speed
00239   Servo_SetSpeed(1, 512);
00240   \endcode
00241 */
00242 int Servo_SetSpeed( int index, int speed )
00243 {
00244   if ( index < 0 || index >= SERVO_COUNT )
00245     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00246   
00247   Servo_SetActive( index, 1 );
00248 
00249   if ( speed < 1 )
00250     speed = 1;
00251   if( speed > 1023 )
00252     speed = 1023;
00253   DisableFIQFromThumb();
00254   Servo->control[ index ]->speed = speed << 6;
00255   EnableFIQFromThumb();
00256 
00257   return CONTROLLER_OK;
00258 }
00259 
00260 /** 
00261   Read the current position of a servo motor.
00262   @param index An integer specifying which servo (0 - 3).
00263   @return The position (0 - 1023), or 0 on error.
00264   
00265   \b Example
00266   \code
00267   int srv0_pos = Servo_GetPosition(0);
00268   // now srv0_pos is the current position
00269   \endcode
00270 */
00271 int Servo_GetPosition( int index )
00272 {
00273   if ( index < 0 || index >= SERVO_COUNT )
00274     return 0;
00275   
00276   Servo_SetActive( index, 1 );
00277   return (Servo->control[ index ]->position >> 6) - SERVO_OFFSET;
00278 }
00279 
00280 /** 
00281   Get the speed at which a servo will move in response to a call to Servo_SetPosition().
00282   Read the value previously set for the speed parameter.
00283   @param index An integer specifying which servo (0 - 3).
00284   @return The speed (0 - 1023), or 0 on error.
00285   
00286   \b Example
00287   \code
00288   int srv0_speed = Servo_GetSpeed(0);
00289   // now srv0_speed is the current speed
00290   \endcode
00291 */
00292 int Servo_GetSpeed( int index )
00293 {
00294   if ( index < 0 || index >= SERVO_COUNT )
00295     return 0;
00296   
00297   Servo_SetActive( index, 1 );
00298 
00299   return Servo->control[ index ]->speed >> 6;
00300 }
00301 
00302 /** @}
00303 */
00304 
00305 int Servo_Start( int index )
00306 {
00307   int status;
00308 
00309   if ( index < 0 || index >= SERVO_COUNT )
00310     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00311 
00312   ServoControl* sc = Servo->control[ index ];  
00313   if ( sc->users == 0 )
00314   {
00315     int io = Servo_GetIo( index );
00316 
00317     // Try to lock the servo output
00318     status = Io_Start( io, true );
00319     if ( status != CONTROLLER_OK )
00320     {
00321       // Damn
00322       Servo->users--;
00323       sc->users--;
00324       return status;
00325     }
00326 
00327     Io_SetPio( io, true );
00328     Io_SetValue( io, true );
00329     Io_SetDirection( io, IO_OUTPUT );
00330 
00331     sc->position = (SERVO_MID_POSITION + SERVO_OFFSET) << 6;
00332     sc->speed = 1023 << 6;
00333     sc->users++;
00334   }
00335 
00336   return CONTROLLER_OK;
00337 }
00338 
00339 int Servo_Stop( int index )
00340 {
00341   if ( index < 0 || index >= SERVO_COUNT )
00342     return CONTROLLER_ERROR_ILLEGAL_INDEX;
00343 
00344   ServoControl* sc = Servo->control[ index ]; 
00345 
00346   if ( sc->users <= 0 )
00347     return CONTROLLER_ERROR_TOO_MANY_STOPS;
00348 
00349   if ( --sc->users == 0 )
00350   {
00351     int io = Servo_GetIo( index );
00352     //Io_SetInput( io );
00353     Io_SetDirection( io, IO_INPUT );
00354     Io_Stop( io );
00355   }
00356 
00357   return CONTROLLER_OK;
00358 }
00359 
00360 
00361 int Servo_GetIo( int index )
00362 {
00363   int io = -1;
00364   switch ( index )
00365   {
00366     case 0:
00367       io = SERVO_0_IO;
00368       break;
00369     case 1:
00370       io = SERVO_1_IO;
00371       break;
00372     case 2:
00373       io = SERVO_2_IO;
00374       break;
00375     case 3:
00376       io = SERVO_3_IO;
00377       break;
00378   }
00379   return io;
00380 }
00381 
00382 int Servo_Init()
00383 {
00384   Servo = MallocWait( sizeof( Servo_ ), 100 );
00385 
00386   Servo->users = 0;
00387   int i;
00388   for( i = 0; i < SERVO_COUNT; i++ )
00389   {
00390     Servo->control[ i ] = NULL;
00391     Servo->control[ i ] = MallocWait( sizeof( ServoControl ), 100 );
00392 
00393     ServoControl* s = Servo->control[ i ];
00394     s->users = 0;
00395     s->positionRequested = (SERVO_MID_POSITION + SERVO_OFFSET) << 6;
00396     switch( i )
00397     {
00398       case 0:
00399         s->pIoBase = AT91C_BASE_PIOB;
00400         s->pin = AT91C_PIO_PB24;
00401         break;
00402       case 1:
00403         s->pIoBase = AT91C_BASE_PIOA;
00404         s->pin = AT91C_PIO_PA23;
00405         break;
00406       case 2:
00407         s->pIoBase = AT91C_BASE_PIOA;
00408         s->pin = AT91C_PIO_PA21;
00409         break;
00410       case 3:
00411         s->pIoBase = AT91C_BASE_PIOA;
00412         s->pin = AT91C_PIO_PA22;
00413         break;
00414     }
00415   }
00416 
00417   // Global init stuff
00418   Servo->state = 0;
00419   Servo->gap = 1882; // forces 64'ish cycles a second (1894 + 2012 = 3906, 3906 * 4 = 15624, 15624 * 64 = 999936)
00420   Servo->index = 0;
00421 
00422   FastTimer_InitializeEntry( &Servo->fastTimerEntry, Servo_IRQCallback, 0, 2000, true );
00423   FastTimer_Set( &Servo->fastTimerEntry );
00424 
00425   return CONTROLLER_OK;
00426 }
00427 
00428 int Servo_Deinit()
00429 {
00430   // Disable the device
00431   // AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
00432   FastTimer_Cancel( &Servo->fastTimerEntry );
00433   int i;
00434   for( i = 0; i < SERVO_COUNT; i++ )
00435     Free( Servo->control[i] );
00436   Free( Servo );
00437   Servo = NULL;
00438   return CONTROLLER_OK;
00439 }
00440 
00441 void Servo_IRQCallback( int id )
00442 {
00443   (void)id;
00444   int period;
00445 
00446   switch ( Servo->state )
00447   {
00448     case 0:
00449     {
00450       if ( ++Servo->index >= SERVO_COUNT || Servo->index < 0 )
00451         Servo->index = 0;
00452       ServoControl* s = Servo->control[ Servo->index ];
00453       
00454       if ( s->position != s->positionRequested )
00455       {
00456         int diff = s->positionRequested - s->position;
00457         if ( diff < 0 )
00458         {
00459           s->position -= s->speed;
00460           if ( s->position < s->positionRequested )
00461             s->position = s->positionRequested;
00462         }
00463         else
00464         {
00465           s->position += s->speed;
00466           if ( s->position > s->positionRequested )
00467             s->position = s->positionRequested;
00468         }
00469       }
00470 
00471       period = s->position >> 6;
00472       if ( period >= (SERVO_MIN_POSITION + SERVO_OFFSET) && period <= (SERVO_MAX_POSITION + SERVO_OFFSET) )
00473         s->pIoBase->PIO_CODR = s->pin;
00474       else
00475         period = SERVO_MAX_POSITION;
00476       FastTimer_SetTime( &Servo->fastTimerEntry, period );
00477       Servo->state = 1;
00478       break;
00479     }
00480     case 1:
00481     {
00482       ServoControl* s = Servo->control[ Servo->index ];
00483       period = s->position >> 6;
00484       s->pIoBase->PIO_SODR = s->pin;
00485       FastTimer_SetTime( &Servo->fastTimerEntry, Servo->gap + ( SERVO_CYCLE - period ) );
00486       Servo->state = 0;
00487       break;
00488     }
00489   }
00490 }
00491 
00492 #ifdef OSC // defined in config.h
00493 
00494 /** \defgroup ServoOSC Servo - OSC
00495   Control Servo motors with the Application Board via OSC.
00496   \ingroup OSC
00497   
00498   \section devices Devices
00499   There are 4 Servo controllers available on the Application Board, numbered 0 - 3.\n
00500   See the servo section in the Application Board user's guide for more information
00501   on hooking up servos to the board.
00502   
00503   \section properties Properties
00504   Each servo controller has three properties:
00505   - position
00506   - speed
00507   - active
00508 
00509   \par Position
00510   The \b position property corresponds to the position of the servo motor within its range of motion.
00511   This value can be both read and written.  
00512   \par 
00513   Most servos like to be driven within a "safe range" which usually ends up being somewhere around 110-120
00514   degrees range of motion, or thereabouts.  Some servos don't mind being driven all the way to their 180
00515   degree range of motion limit.  With this in mind, the range of values you can send to servos connected
00516   to the Make Controller Kit is as follows:
00517   - Values from 0-1023 correspond to the normal, or "safe", range of motion.  
00518   - You can also send values from -512 to 1536 to drive the servo through its full
00519   range of motion.
00520   \par
00521   Note that it is sometimes possible to damage your servo by driving it too far, so proceed with a bit of
00522   caution when using the extended range until you know your servos can handle it.
00523   \par
00524   To set the first servo to one quarter its position, send the message
00525   \verbatim /servo/0/position 256 \endverbatim
00526   Leave the argument value off to read the position of the servo:
00527   \verbatim /servo/0/position \endverbatim
00528   
00529   \par Speed
00530   The \b speed property corresponds to the speed with which the servo responds to changes 
00531   of position.
00532   This value can be both read and written, and the range of values is 0 - 1023.  A speed of 1023
00533   means the servo responds immediately, and lower values will result in slower, and smoother, responses.  
00534   \par
00535   To set the speed of the first servo to just under full speed, send a message like
00536   \verbatim /servo/0/speed 975 \endverbatim
00537   Adjust the argument value to one that suits your application.\n
00538   Leave the argument value off to read the position of the servo:
00539   \verbatim /servo/0/speed \endverbatim
00540   
00541   \par Active
00542   The \b active property corresponds to the active state of the servo.
00543   If the servo is set to be active, no other tasks will be able to
00544   write to the same I/O lines.  If you're not seeing appropriate
00545   responses to your messages to a servo, check the whether it's 
00546   locked by sending a message like
00547   \verbatim /servo/3/active \endverbatim
00548 */
00549 
00550 #include "osc.h"
00551 #include "string.h"
00552 #include "stdio.h"
00553 
00554 // Need a list of property names
00555 // MUST end in zero
00556 static char* ServoOsc_Name = "servo";
00557 static char* ServoOsc_PropertyNames[] = { "active", "position", "speed", 0 }; // must have a trailing 0
00558 
00559 int ServoOsc_PropertySet( int index, int property, int value );
00560 int ServoOsc_PropertyGet( int index, int property );
00561 
00562 // Returns the name of the subsystem
00563 const char* ServoOsc_GetName( )
00564 {
00565   return ServoOsc_Name;
00566 }
00567 
00568 // Now getting a message.  This is actually a part message, with the first
00569 // part (the subsystem) already parsed off.
00570 int ServoOsc_ReceiveMessage( int channel, char* message, int length )
00571 {
00572   int status = Osc_IndexIntReceiverHelper( channel, message, length, 
00573                                            SERVO_COUNT, ServoOsc_Name,
00574                                            ServoOsc_PropertySet, ServoOsc_PropertyGet, 
00575                                            ServoOsc_PropertyNames );
00576 
00577   if ( status != CONTROLLER_OK )
00578     return Osc_SendError( channel, ServoOsc_Name, status );
00579   return CONTROLLER_OK;
00580 }
00581 
00582 // Set the index LED, property with the value
00583 int ServoOsc_PropertySet( int index, int property, int value )
00584 {
00585   switch ( property )
00586   {
00587     case 0:
00588       Servo_SetActive( index, value );
00589       break;
00590     case 1:
00591       Servo_SetPosition( index, value );
00592       break;
00593     case 2:
00594       Servo_SetSpeed( index, value );
00595       break;
00596   }
00597   return CONTROLLER_OK;
00598 }
00599 
00600 // Get the index LED, property
00601 int ServoOsc_PropertyGet( int index, int property )
00602 {
00603   int value = 0;
00604   switch ( property )
00605   {
00606     case 0:
00607       value = Servo_GetActive( index );
00608       break;
00609     case 1:
00610       value = Servo_GetPosition( index );
00611       break;
00612     case 2:
00613       value = Servo_GetSpeed( index );
00614       break;
00615   }
00616   
00617   return value;
00618 }
00619 
00620 #endif

The Make Controller Kit is an open source project maintained by MakingThings.
MakingThings code is released under the Apache 2.0 license.
Bug tracker, development wiki and status can be found at http://dev.makingthings.com.
This document was last updated on 18 May 2009.