Sergeant82d
Joined: 01 Nov 2009 Posts: 55 Location: Central Oklahoma
|
Sabertooth 2x25 Driver |
Posted: Tue Jul 19, 2011 12:35 am |
|
|
Here is a driver for Dimension Engineering's Sabertooth line of motor controllers.
See the Dimension Engineering web page and manuals for more information www.dimensionengineering.com
Edited 07 July 2013: Minor changes to header comments only - no changes to driver files.
Edited 07 June 2012: Major changes -
- Separated header info from source file
- Added return value to each user function to report success
- Split motor command function into two - one to control each motor separately, and another to use the mixed-mode commands
Edited 22 September 2011: Renamed a few constants to better reflect their purpose.
Edited 28 August 2011: I standardized the function comments - no changes to the driver itself.
Edited 23 August 2011: I have cleaned up and made the driver functions more consistent in their arrangement, along with fixing a couple of minor bugs which could have caused unpredictable results.
sabertooth_2x25_driver.h
Code: |
/**********************************************************************************************
*
* Sabertooth_2x25_Driver.h
* Version 2.0.2
* 07 July, 2013
*
* Brad Hedges
* H & H Enterprises
* Stratford, Oklahoma
*
**********************************************************************************************
**********************************************************************************************
*
* This is a multi-purpose device driver to operate the Dimension Engineering Sabertooth series
* of H-Bridge motor controllers. These can be used to control permanent magnet DC motors
* between 6 & 30 volts, up to 25 amps continuous and 50 amps surge.
*
* This driver works in the "Packetized Serial" mode, which must be set with the DIP
* switches on the controller hardware. The driver defaults to operating only one
* Sabertooth, using the lowest physical address of 128. The address is configurable in
* the driver by assigning the address value to the constant "MOTOR_DRIVER_ADDRESS_x".
*
* The driver is written in the C language for Microchip PIC microcontrollers using CCS's
* PIC-C Compiler, and was developed using version 4.120 of that compiler. I have also used it
* with 32-bit PICs, using Microchip's C32 compiler.
*
* It should be easily convertible to other microcontrollers and compilers with minimal effort. I have
* annotated the three lines which would have to be modified for a different compiler or
* processor architecture.
*
* Dimension Engineering's web site is at: www.dimensionengineering.com
* CCS's web site is: www.ccsinfo.com
* Microchip's web site: www.microchip.com
*
*********************************************************************************************/
#ifndef sabertooth_2x25_driver_h
#define sabertooth_2x25_driver_h
#include <stdio.h> // Need to be able to use standard output "putchar" command
#include <stdint.h> // Include your standard types definition file to accomodate the C99 uint_x types
#define FALSE 0
#define TRUE 1
/**********************************************************************************************
**********************************************************************************************
* This is the only section that should require modification for non-PIC/non-CCS Compiler usage
*********************************************************************************************/
/* In this section you must make modifications to suit both your hardware, and your compiler
*
* Assign name to a MOTOR_STOP output pin for emergency stop routines
*
* The two macros are for use in your application code to halt all movement or
* re-enable it, using the MOTOR_STOP pin defined above.
*
* The Sabertooth requires only that a control pin be pulled low to completely disable
* the two motor outputs, and if unused, it can be left floating (you don't have to use that pin)
*
* Possible uses are bumper switches or other sensors, or during startup when you don't
* want the motors enabled until all systems are properly initialized */
/* TODO: Create a driver-wide #define file to include from a system hardware file, rather than assigning hardware
* in this header file. The intent is to assign all hardware I/O in "hardware.h", rather than
* in separate/distributed files.... */
#ifdef __PICC__ /** CCS Compiler */
#define MOTOR_STOP PIN_D5
#define mSTOP_ALL_MOTORS output_low(MOTOR_STOP);
#define mRESTART_ALL_STOPPED_MOTORS output_high(MOTOR_STOP);
#endif
#ifdef __C32__ /** Microchip PIC 32-Bit Compiler */
#define MOTOR_STOP 1 << 10 //PORTBbits.RB10
#define mSTOP_ALL_MOTORS mPORTBClearBits( MOTOR_STOP ) // output_low(MOTOR_STOP);
#define mRESTART_ALL_STOPPED_MOTORS mPORTBSetBits( MOTOR_STOP ) // output_high(MOTOR_STOP);
#endif
/**********************************************************************************************
* End of the only section that should require modification for non-PIC/non-CCS Compiler usage
**********************************************************************************************
*********************************************************************************************/
/**********************************************************************************************
* SETUP INFORMATION
*********************************************************************************************/
/* You must send the autobauding character to your Sabertooth during program initialization,
* before sending any commands to the device.
*
* This must be done each time the device powers up. */
#define mSEND_AUTOBAUD putchar(0xAA)
/* Each serial command to the hardware is checked for validity by the on-board processor */
#define CRC_MASK 0b01111111
/* Use desired hardware address, per hardware DIP switch settings */
#define MOTOR_DRIVER_ADDRESS_1 128
#define MOTOR_DRIVER_ADDRESS_2 129
#define MOTOR_DRIVER_ADDRESS_3 130
#define MOTOR_DRIVER_ADDRESS_4 131
#define MOTOR_DRIVER_ADDRESS_5 132
#define MOTOR_DRIVER_ADDRESS_6 133
#define MOTOR_DRIVER_ADDRESS_7 134
#define MOTOR_DRIVER_ADDRESS_8 135
/**********************************************************************************************
* COMMANDS
*********************************************************************************************/
#define COMMAND_LOW_LIMIT 0 // For bounds checking purposes only
#define DRIVE_FORWARD_1 0
#define DRIVE_REVERSE_1 1
#define SET_MIN_VOLTAGE 2
#define SET_MAX_VOLTAGE 3
#define DRIVE_FORWARD_2 4
#define DRIVE_REVERSE_2 5
#define DRIVE_MOTOR_1_7_BIT 6
#define DRIVE_MOTOR_2_7_BIT 7
#define DRIVE_FORWARD_MIXED 8
#define DRIVE_REVERSE_MIXED 9
#define DRIVE_TURN_RIGHT_MIXED 10
#define DRIVE_TURN_LEFT_MIXED 11
#define DRIVE_FWD_REV_7_BIT 12
#define DRIVE_TURN_7_BIT 13
#define SET_SERIAL_TIMEOUT 14
#define SET_BAUD_RATE 15
#define SET_RAMPING_RATE 16
#define SET_DEADBAND 17
/* If any more commands are added by the manufacturer in the future, increase
* COMMAND_HIGH_LIMIT to the highest command number in that new command set.
* As with the COMMAND_LOW_LIMIT, this is only used for bounds checking in a function.
*
* Yes, we could enumerate the commands, and that works better in MPLAB 8 debugging,
* but the macro viewer capability in the new MPLABX IDE that I am using is so neat
* that I changed it back to separate #defines so I could use it.
*
* Your call. 8^) */
#define COMMAND_HIGH_LIMIT 17
/**********************************************************************************************
* COMMAND DATA
*********************************************************************************************/
#define BAUDRATE_2400 1
#define BAUDRATE_9600 2
#define BAUDRATE_19200 3
#define BAUDRATE_38400 4
#define DEFAULT_BAUDRATE BAUDRATE_9600
#define MAX_MINIMUM_VOLTAGE 120
#define MIN_MINIMUM_VOLTAGE 0
#define DEFAULT_MINIMUM_VOLTAGE 0
#define MAX_MAXIMUM_VOLTAGE 128
#define MIN_MAXIMUM_VOLTAGE 0
#define DEFAULT_MAXIMUM_VOLTAGE 0
#define MAX_SERIAL_TIMEOUT 50
#define MIN_SERIAL_TIMEOUT 0
#define DEFAULT_SERIAL_TIMEOUT 0
#define MAX_RAMPING_VALUE 80
#define MIN_RAMPING_VALUE 0
#define DEFAULT_RAMPING_VALUE 1
#define MAX_DEADBAND 127
#define MIN_DEADBAND 0
#define DEFAULT_DEADBAND 3
/**********************************************************************************************
* FUNCTION PROTOTYPES
**********************************************************************************************
*
* *** NOTE *** If using the CCS Compiler, and only one single Sabertooth controller, you do not need the "address"
* variable. It is only needed if you are sending commands to more than one controller, or
* if you are using a compiler (such as Microchip's Cx/XCx series) which does not allow operator overloading.
*
*********************************************************************************************/
uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, uint8_t command2, uint8_t speed2, uint8_t address );
uint8_t control_motors_mixed ( uint8_t command, uint8_t speed, uint8_t address );
uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, uint8_t address );
uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, uint8_t address );
uint8_t set_serial_timeout ( uint8_t desired_timeout_period, uint8_t address );
uint8_t set_baudrate ( uint8_t desired_baudrate, uint8_t address );
uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, uint8_t address );
uint8_t set_deadband_range ( uint8_t desired_deadband, uint8_t address );
#endif
/**********************************************************************************************
* END OF SABERTOOTH 2x25 HEADER
*********************************************************************************************/
|
sabertooth_2x25_driver.c
Code: |
/**********************************************************************************************
*
* Sabertooth_2x25_Driver.c
* Version 2.0.2
* 07 July, 2013
*
* Brad Hedges
* H & H Enterprises
* Stratford, Oklahoma
*
**********************************************************************************************
**********************************************************************************************
*
* This is a multi-purpose device driver to operate the Dimension Engineering Sabertooth series
* of H-Bridge motor controllers. These can be used to control permanent magnet DC motors
* between 6 & 30 volts, up to 25 amps continuous and 50 amps surge.
*
* This driver works in the "Packetized Serial" mode, which must be set with the DIP
* switches on the controller hardware. The driver defaults to operating only one
* Sabertooth, using the lowest physical address of 128. The address is configurable in
* the driver by assigning the address value to the constant "MOTOR_DRIVER_ADDRESS_x".
*
* The driver is written in the C language for Microchip PIC microcontrollers using CCS's
* PIC-C Compiler, and was developed using version 4.120 of that compiler. I have also used it
* with 32-bit PICs, using Microchip's C32 compiler.
*
* It should be easily convertible to other microcontrollers and compilers with minimal effort. I have
* annotated the three lines which would have to be modified for a different compiler or
* processor architecture.
*
* Dimension Engineering's web site is at: www.dimensionengineering.com
* CCS's web site is: www.ccsinfo.com
* Microchip's web site: www.microchip.com
*
*********************************************************************************************/
#include "sabertooth_2x25_driver.h"
/**********************************************************************************************
* Function: uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, \
* uint8_t command2, uint8_t speed2, \
* uint8_t address )
*
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the commands to the send_command function,
* and then to the serial port
* Side Effects: None
* Overview: Checks commands for validity, and passes them to the serial port
* Notes: This function is valid for Sabertooth Commands 0, 1, 4 - 7
* These commands are for controlling two motors with individual settings, a single motor at a time
*
* Individual Motor Commands:
* 0: Drive Forward Motor 1
* 1: Drive Reverse Motor 1
* 4: Drive Forward Motor 2
* 5: Drive Reverse Motor 2
* 6: Drive 7-Bit Motor 1
* 7: Drive 7-Bit Motor 2
*
*********************************************************************************************/
uint8_t control_motors_sep ( uint8_t command1, uint8_t speed1, \
uint8_t command2, uint8_t speed2, \
uint8_t address ) {
// = MOTOR_DRIVER_ADDRESS_1 ) { // If your compiler allows overloading, feel free to un-comment the assignment
// and move it immediately after the "address" variable
if ( ( command1 < COMMAND_LOW_LIMIT || command1 > DRIVE_MOTOR_2_7_BIT ) || \
( command2 < COMMAND_LOW_LIMIT || command2 > DRIVE_MOTOR_2_7_BIT ) ) {
/* Set error code for invalid command
* Call a user error function to do whatever your application requires, such as:
* mSTOP_ALL_MOTORS; */
return FALSE;
}
else {
send_command ( command1, speed1, address );
send_command ( command2, speed2, address );
// Set error code for no error
return TRUE;
}
}
/**********************************************************************************************
* Function: uint8_t control_motors_mixed ( uint8_t command, uint8_t speed1, uint8_t address )
*
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the commands to the send_command function,
* and then to the serial port
* Side Effects: None
* Overview: Checks commands for validity, and passes them to the serial port
* Notes: This function is valid for Sabertooth Commands 8 - 13
* These commands are for controlling two motors simultaneously
*
* Mixed Mode Commands:
* 8: Drive Forward Mixed Mode
* 9: Drive Reverse Mixed Mode
* 10: Turn Right Mixed Mode
* 11: Turn Left Mixed Mode
* 12: Drive Forwards/Reverse 7 bit mode
* 13: Turn Left/Right 7 bit mode
*
*********************************************************************************************/
uint8_t control_motors_mixed ( uint8_t command, uint8_t speed, uint8_t address ) {
if ( command < DRIVE_FORWARD_MIXED || command > DRIVE_TURN_7_BIT ) {
/* Set error code for invalid command
* Call a user error function to do whatever your application requires, such as:
* mSTOP_ALL_MOTORS;
* return; */
return FALSE;
}
else {
send_command ( command, speed, address );
// Set error code for no error
return TRUE;
}
}
/**********************************************************************************************
* Function: uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: None
* Overview: Checks command for validity, and passes it to the serial port
* Notes: This function is valid for Sabertooth Command 2
*********************************************************************************************/
uint8_t set_minimum_controller_voltage ( uint8_t desired_minimum_voltage, uint8_t address ) {
uint8_t new_min_voltage = DEFAULT_MINIMUM_VOLTAGE;
if ( desired_minimum_voltage < MIN_MINIMUM_VOLTAGE || \
desired_minimum_voltage > MAX_MINIMUM_VOLTAGE ) {
new_min_voltage = DEFAULT_MINIMUM_VOLTAGE;
return FALSE; // Set error code for error
}
else {
new_min_voltage = desired_minimum_voltage;
}
send_command ( SET_MIN_VOLTAGE, new_min_voltage, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
*
* Pre-Condition: Do not use if powering Sabertooth from batteries, only needed for use with
* power supplies
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: If you change this from the default value of 30 Volts, you can not set it
* for more than 25 Volts. In order to reset it to a higher value, you must
* use the DEScribe software available from Dimension Engineering
* Overview: Checks command for validity, and passes it to the serial port
* Notes: This function is valid for Sabertooth Command 3
*********************************************************************************************/
uint8_t set_maximum_controller_voltage ( uint8_t desired_maximum_voltage, uint8_t address ) {
uint8_t new_max_voltage = DEFAULT_MAXIMUM_VOLTAGE;
if ( desired_maximum_voltage < MIN_MAXIMUM_VOLTAGE || \
desired_maximum_voltage > MAX_MAXIMUM_VOLTAGE ) {
new_max_voltage = DEFAULT_MAXIMUM_VOLTAGE;
return FALSE; // Set error code for error
}
else {
new_max_voltage = desired_maximum_voltage;
}
send_command ( SET_MAX_VOLTAGE, new_max_voltage, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: uint8_t set_serial_timeout ( uint8_t desired_timeout_period, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: None
* Overview: Checks command for validity, and passes it to the serial port
* Value received by the Sabertooth is in multiples of 100 milli-seconds
* EXAMPLE: '1' = 100 ms
* I set the max timeout value at a discretionary value of 5 seconds; you can
* set it as desired by changing the "MAX_SERIAL_TIMEOUT" constant #define,
* in the header file under "Command Data"
* Notes: This function is valid for Sabertooth Command 14
*********************************************************************************************/
uint8_t set_serial_timeout ( uint8_t desired_timeout_period, uint8_t address ) {
uint8_t new_timeout_period = DEFAULT_SERIAL_TIMEOUT;
if ( desired_timeout_period < MIN_SERIAL_TIMEOUT || \
desired_timeout_period > MAX_SERIAL_TIMEOUT ) {
new_timeout_period = DEFAULT_SERIAL_TIMEOUT;
return FALSE; // Set error code for error
}
else {
new_timeout_period = desired_timeout_period;
}
send_command ( SET_SERIAL_TIMEOUT, new_timeout_period, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: uint8_t set_baudrate ( uint8_t desired_baudrate, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: None
* Overview: Checks command for validity, and passes it to the serial port
* set_baudrate accepts baud values between 2,400 and 38,400 (commands 1-4),
* with a default value of 9,600 baud (command 2)
* Notes: This function is valid for Sabertooth Command 15
*********************************************************************************************/
uint8_t set_baudrate ( uint8_t desired_baudrate, uint8_t address ) {
static uint8_t new_baudrate = DEFAULT_BAUDRATE;
if ( desired_baudrate < BAUDRATE_2400 || \
desired_baudrate > BAUDRATE_38400 ) {
new_baudrate = DEFAULT_BAUDRATE;
return FALSE; // Set error code for error
}
else {
new_baudrate = desired_baudrate;
}
send_command ( SET_BAUD_RATE, new_baudrate, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: None
* Overview: Checks command for validity, and passes it to the serial port
* set_ramping_rate accepts the desired ramping rate, which must be a value between
* zero and eighty ( 0 - 80 )
* Notes: This function is valid for Sabertooth Command 16
*********************************************************************************************/
uint8_t set_ramping_rate ( uint8_t desired_ramping_rate, uint8_t address ) {
static uint8_t new_ramping_rate = DEFAULT_RAMPING_VALUE;
if ( desired_ramping_rate < MIN_RAMPING_VALUE || \
desired_ramping_rate > MAX_RAMPING_VALUE ) {
new_ramping_rate = DEFAULT_RAMPING_VALUE;
return FALSE; // Set error code for error
}
else {
new_ramping_rate = desired_ramping_rate;
}
send_command ( SET_RAMPING_RATE, new_ramping_rate, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: uint8_t set_deadband_range ( uint8_t desired_deadband, \
* uint8_t address = MOTOR_DRIVER_ADDRESS_1 )
* Pre-Condition: None
* Input: Receives command data from the application program
* Output: Sends the command to the send_command function,
* and then to the serial port; returns true or false to calling function, to
* verify valid commands received and processed
* Side Effects: None
* Overview: Checks command for validity, and passes it to the serial port
* set_deadband_range accepts the desired deadband, which must be a value
* between zero and 127
* Value is set as follows:
* ( 127 - command value ) < motors_off < ( 128 + command value )
* Notes: This function is valid for Sabertooth Command 17
*********************************************************************************************/
uint8_t set_deadband_range ( uint8_t desired_deadband, uint8_t address ) {
static uint8_t new_deadband = DEFAULT_DEADBAND;
if ( desired_deadband < MIN_DEADBAND || desired_deadband > MAX_DEADBAND ) {
new_deadband = DEFAULT_DEADBAND;
return FALSE; // Set error code for error
}
else {
new_deadband = desired_deadband;
}
send_command ( SET_DEADBAND, new_deadband, address );
return TRUE; // Set error code for no error
}
/**********************************************************************************************
* Function: static void send_command ( uint8_t command, uint8_t value, uint8_t address )
*
* Pre-Condition: None
* Input: Receives the command data from the driver functions
* Output: Sends the three commands plus their checksum to the serial port, and through
* that to the Sabertooth Motor Controller
* Side Effects: None
* Overview: None
* Notes: Static helper function, for use only by driver functions in this file
*********************************************************************************************/
/* Helper Command, for internal driver use only
* Defining it here, in the .c file, instead of in the .h file, to prevent
* compiler warning about it being declared "static", but never defined
* This is correct, since it is not for the user, only the user's functions */
static void send_command ( uint8_t command, uint8_t value, uint8_t address );
/*********************************************************************************************/
static void send_command ( uint8_t command, uint8_t value, uint8_t address ) {
assert ( command < COMMAND_HIGH_LIMIT);
putchar ( address );
putchar ( command );
putchar ( value );
putchar ( ( address + command + value ) & CRC_MASK );
}
/**********************************************************************************************
* END OF SABERTOOTH 2x25 DRIVER
*********************************************************************************************/
|
|
|