Development Board: Servo "Ranger"



To ensure my Dedicated Servo Controller worked and was stable, I made a Servo "Ranger" program. It's a dual purpose design (discussed later) that allows the user to control 8 servos via two potentiometers.

One potentiometer selects the servo, and the other sets the position. While there are 8 servos to choose from, there is a 9th mode which displays both the total number of packets sent and the total number of errors that have occurred. An error occurs if the value "1" is not returned from the Dedicated Servo Controller after a packet has been transmitted.


Circumstances that could lead to errors

Any number of possibilities could result in a packet validation error, such as:

  • Noise on UART interface.
  • Dedicated Servo Controller doing something else during a packet reception.
  • Noise generated from Servo operation.
  • Slow/buggy code (such as incorrect context saving).

Most of the above possibilities will result in ambiguous UART data being received. Before the Dedicated Controller will update servo positions, the entire packet must pass a checksum. Each servo position is XORd together, then compared with the pre-calculated checksim. A failure will result in the controller sending back a "0" (which simply means 'bad packet'). If the packet passes the validation, then a "1" is returned ('good packet').


The "Ranger"

This project was really a dual purpose. As the name suggests (Servo Ranger), the program allows full control of a servo to "test" deflection angles. This is handy for discovering both the limitations and any linearization errors a servo may have. This is probably the long term role for this little board, so the project was named after it.

What does the rest of this article have to do with the Servo Ranger? The ranger checks every packet transmission and ensures the Dedicated Controller returns a "1". Any failures are clocked and displayed in mode 9 (as mentioned earlier). The project was not intended for long term use, rather for a real life crunch test on the dedicated controller, hence the open-board design below. I left it running for a couple of hours to see how stable the program was - Here's a picture after that time:


Over 900,000 packets (P) have been sent - a single error (E) is yet to occur.

As shown in the picture, over 900,000 packets have been transmitted. There were no errors recorded in that time frame, nor has there been an error in the 12+ hours I thought I would leave it on for.


A brief video of the project in operation:

(video of project not uploaded as yet)


Swordfish Program


And the source code itself. Note the use of the potentiometers - my new favorite way to do business!

Swordfish Program: Servo "Range Finder"
Device = 18F2620
Clock = 32
Config OSC = INTIO67,
       MCLRE = OFF
#option LCD_DATA = PORTB.0
#option LCD_RS = PORTB.4
#option LCD_EN = PORTB.5
Include "IntOSC8PLL.bas"
Include "USART.bas"
Include "ADC.bas"
Include "CONVERT.bas"
Include "LCD.bas"
// define valid servo range
Const Servo_Min = 600
Const Servo_Max = 2400
Const InitialPosition = 1000
Dim Servo(8) As Word,
    curServo As Word,
    curPosition As Word,
    Errors As Byte,
    TotalErrors As LongWord,
    TotalPackets As LongWord,
    ScreenRefresh As Boolean
// function that samples the Mode potentiometer and returns the desired decoded value
Function GetServoIndex() As Word
    Dim Segments, i As Byte
    Result = ADC.ReadMedian(1)     
    // split the 10 bit ADC resolution into known segments for the array
    Segments = 1023 / 9    
    // determine where the ADC result lies throughout the segments & return the desired array value
    i = 0
        If Result <= ((i+1) * Segments) Then
    Until i = 8
    Result = i
End Function    
Function GetServoPosition() As Word
    Dim tmpLongWord As LongWord
    Result = ADC.ReadMedian(0)
    tmpLongWord = Result * (Servo_Max-Servo_Min)
    Result = tmpLongWord / 1023 + Servo_Min
End Function
Sub RefreshLCD()
    LCD.WriteAt(1,1,"S:  E:  ")
    LCD.WriteAt(2,1,"Pos:    ")
    ScreenRefresh = False
End Sub
Sub SendServoPositions()
    Dim CRC As Word
    Dim i As Byte
    // send header
    // send each servo position
    For i = 0 To 7
    // calculate and send CRC
    CRC = 0
    For i = 0 To 7
        CRC = CRC Xor Servo(i)
    If TotalPackets = 1000000 Then
        TotalPackets = 0        
End Sub
// update all 8 servo positions
Sub InitialiseServos()
    Dim i As Byte
    For i = 0 To 7
        Servo(i) = InitialPosition
End Sub
Sub CheckControls()
    curServo = GetServoIndex
    If curServo  8 Then
        curPosition = GetServoPosition            
        Servo(curServo) = curPosition
End Sub
Sub UpdateDisplay()
    If curServo  8 Then
        If ScreenRefresh Then
        ScreenRefresh = True
End Sub
Sub CheckForConfirmation()
    If Not USART.WaitForTimeout(1,5) Then
        If Errors = 100 Then
            Errors = 0
        If TotalErrors = 1000000 Then
            TotalErrors = 0
End Sub
// Enable PLL
// initialize program
ADCON1 = %00001101
ADCON2 = %10101111 
LCD.WriteAt(1,1,"Servo   ")
LCD.WriteAt(2,1,"  Ranger")
LCD.WriteAt(1,1,"By      ")
LCD.WriteAt(2,1,"  Mitchy")
Errors = 0
TotalErrors = 0
TotalPackets = 0
// main program loop
While True   


Download the Swordfish program and Gerber files here: Servo Ranger Source Files


Thoughts comments and feedback are more then welcome.

Forum Activity

Member Access