Include Files: <Coal_Basin_Servo2.h>
Constructor: Coal_Basin_Servo2 servo(ch,left,right); where the 3 arguments are:
ch channel of PCA9685 to which servo is attached
left,right Timings for servo movements
Public Methods:
Coal_Basin_Servo2(int,int,int); where arguments are as above
void begin( );
void do_servo(int direction); (direction =LEFT/RIGHT)
int current_pos(); returns LEFT or RIGHT
This project develops a class/library for controlling servos to drive the points of a model railway.
The project is part of a larger project known as the "Coal Basin" illustrated below.
The circuit is shown below. The Coal Basin has 14 points so 14 servos are required. The chosen microcontroller does not have sufficient pins to control 14 servos and it falls well short of being able to deliver the required power to 14 servos. To overcome these obstacles a special interface the PCA9685 along with a separate power supply is used.
The NANO will send over a serial port to the PCA9685 data that specifies the servo of interest and the required timing. The PCA685 will generate PWM signals of a given period and duty cycle that control up to 16 servos. 16 sevos if driven to their stops can draw a large current so a hefty separate power pack is used.
If the servos are "driven" passed any stops to their MAX values they will draw significant current and burn out. As a result the servo swings must be limited. The required swings, due to differences in the servos, mechanical linkages and differences in the physical mounting will be different for each servo/point. In creating a servo object the desired left and right settings need to be specified. That is an object of the form servo(channel,left_time,right_time) where channel refers to how the object is wired to the PCA9685. The left and right times will need to be found by Measurment.
The code for the header file Coal_Basin_Servo2.h is shown in the collapsible box below.
The main feature is the class definition that includes the public methods:
The constructor Coal_Basin_Servo2 where the channel to which the servo is attached and the left and right times.
The begin( ) operation that inialises the servo. Note the arguments used in the constructor could alternatively be included as begin arguments
The method void do_servo(int dir); that will move the servo left or right.
The variable current_pos that will store the state of a servo so that no action is taken if the servos already in the direction required.
There is also a define #define SERVO_DELAY 100. When a servo is changed it will stay active for 100mS and then turns off. Note due to the 20mS period of the servo signal the consequences are that if the delay is set to less than 20 there will be one pulse only to the servo, delays of less than 40 will allow 2 pulses etc. By experiment most servos appeared to work with just one pulse and the delay test could be eliminated. For safety the delay is set at 100 (mS).
The implementation file is given in the collapsible box below. The main features are:
The program relies on the standard library <Adafruit_PWMServoDriver.h> that in turn requires the <Wire.h> library for communication with the micro controller.
An object, pwm of the type is created. The parameter 0x40 is the address on the serial bus of the PCA9685 board. This address is hardwire but can be changed using jumper pins.
In the constructor the arguments are set to private variables. In addition, the variable current_pos containing the current position of the points is set to LEFT to ensure in the begin function do_serv(RIGHT) will set the points to RIGHT
The begin function calls Adafruit_PWMServoDriver function. pwm.setPWMFreq(50) will set the PWM to 50 hertz making the period of the servo pulse 20mS.
The do_servo ( ) function will do nothing if the current position is the same as the requested position. If they are different the servos will be set to LEFT or RIGHT as required.
After a time determined by constant SERVO_DELAY (see Header File) the servos are turned off.
The full test demonstration/code for 16 servos is given in the collapsible box. More information about the timings is given in the Testing and Appendix sections.
The main features of the file are:
A Coal_Basin_Servo2 is created for each servo.
Each servo object is attached to an output pin of the PCA9685. This is the first argument.
The second and third arguments are the LEFT and RIGHT timings for the servo. See Testing section following and Appendix for more detail
For each servo object there is a begin( ) operation that initializes each servo object.
The demonstration routine terns servos 1 through 8 LEFT and RIGHT in turn using the public method do_servo(direction).
The photo shows a typical servo set up beneath the baseboard of a railway track.
The arm should be placed in the centre position before the servo is mounted under the railway baseboard - trying to change the arm position upside down under the baseboard is difficult and losing the retaining screw is a certainty.
Adjusting the servo timings can be very messy. It is suggested that a drawing be made of the layout and the required actions specified.
For the servo arrangement given above to move the points to the left in summary the set time should be increased.
Once the servo(s) are mounted with the arm as close to its centre position as possible:
If a servo tester is available may be used to determine the final timings, otherwise the following procedure may be used.
To the *.ino code add a Coal_Basin_Servo2 object with time set to 200 which will set the servo in one direction.
Coal_Basin_Servo2 servox(13,200,200); //where PCA9685 pin 13 is assumed
In the program loop execute the following code:
void loop( ){
servox.do_servo (LEFT);
delay(2000);
servox.do_servo (RIGHT);
delay(2000);
}
With identical timings the servo should be in one extreme or the other. Assume the points end up in the RIGHT position this implies 200 is a good starting point for the second time argument.
Leaving the second argument at 200 modify the first argument to 250 for examle. ie Coal_Basin_Servo2 servox(13,250,200);
Keep increasing the left time until the points move to the left position.
Since is likely that when right the points are hard on increase the right time until the points are not a definite right then back track one step.
The results should give the final timings.
In the project the servo turnings are specified by numbers such as 250 or 350. The relationship between these numbers, the pulse width and the servo positions is summarized below.
The basic timings of the servo motor are shown.
The PCA9685 will generate the required PWM signals.
Typically servos will require a period of 20mS or 50Hz. This will be the maximum value of the 12 bit counter in the PCA9685. That is 20mS is equivalent to 4096 counts.
The servos require pulses in the range 1mS (Maximum anticlockwise) through to 2mS (Maximum Clockwise). As illustrated these require the timing counter to operate in the range of approximately 200 to 400 counts.
These values are typical and counts of 150 through 450 might be necessary
Note these values are only approximate and taking into the account all the other servo variables (eg linkages) the best solution is probably to determine the settings by experimentation.
------------------------- End of Presentation----------------------------