|
Due to the servos in the pan and tilt unit requiring defined signals to operate some form of digital controller was required. The system also called for some form of control to be possible from a host PC.
Initially experiments were carried out with a PIC microcontroller with a program written by Dr Jim Herd to drive the servo signals. The PIC would take 6bit commands and drive up to 4 servos. Commands came from a test program written in C++ which interfaced with the PIC through a USB Brick. The way the PIC software worked was, it would check which servo was addressed in the command and then delay between 1-2ms and then wait 18ms. The problem with this approach was that only one servo could be addressed at a time. Therefore there would be a slight delay between the pan servo finishing a move and the tilt servo starting a move. This produced a slow pan/tilt unit which was not acceptable. After upgrading a personal computer to the latest version of Microsoft Windows, Named Vista, it was discovered that the PC driver for the USB brick was not compatible with Vista. Other initiations of the brick were limited software support and only 16 control lines meant another solution was researched.
Through research of servo control methods, some prewritten Verilog code was located[xxi] which would drive the servos through an FPGA. This meant that two blocks could be created to drive the two servos simultaneously, and also a control system could be implemented on one piece of hardware. The Cyclone II FPGA was available within the department and this was chosen as the target for the control system.
The code required several modifications. The initial was that the clock speed in the code was originally 25MHz however the Cyclone II was configured to run at 50MHz. To change this, the value of clock divisions was changed from 98 to 195. The control to these blocks came from a serial module however this was changed so that desired position was input into the block and a strobe line to perform the move.

Figure 19 - RC Servo Drive Module
Code was also found from the same source that implemented an RS232 decoder meaning characters could be sent from a controlling computer to the FPGA command unit. This code too required a small change, however this only needed the new data line to be brought outside the module so that the other blocks would know when a command had been received. The block was setup to receive at 115200 baud, 8bits, no parity and 1 stop bit.
Since commands were transferred over the link using 8 bit commands, it was decided to use this as the command size for the controller, since it would avoid any complex systems to join received commands together. A simple 8 bit command set was devised, using bits 0 and 1 of the received data as the command code. The four options (00, 01, 10, 11) each having an assigned function. Initially command 01 and 10 set the pan and tilt servo positions respectively to the values in bits 2 to 7. This however only used 6bits of accuracy in servo positions, which wasn’t enough. Command 00 was therefore implemented with a sub-command being bits 2 & 3. The four combinations of the subcommand set the lower 4 bits and upper 4 bits of the pan and tilt servos. Meaning a pan move would take two commands to perform.
The command DoMove is used to make the servo drive blocks update their position from the desired position register. This means that you can make the servo perform the move once you have finished setting up the servo positions, since this requires multiple commands. The Command DoCommand is simple a waste time command whose only purpose is to create a second NewData pulse in the system to perform the command previously set.

To set the x (pan) servo to position would mean 10010111 sending commands 01110000 and 10010100.

Figure 20 – Complete Schematic of Controller
The inputs of the circuit are the RS232 transmit and receive lines (trans and recei above) which provide the inputs into the serial decoder block. The other input is the clock of 50MHz, required to synchronise the circuit and also decode the time dependant serial signals. The serial decoder module has the ability to return data on the serial bus however this is not implemented in the circuit at the present time. The main outputs are the X and Y servo signal lines, the modulation data output (to modulator) and the modulator enable line. The values of the X and Y servos are output to a string of LEDs on the Cyclone II board for debugging.
|
Purpose:
|
Takes the raw digital stream from the UART chip and converts the serial data to parallel (8bits). Also signals when new data has been received.
|
|
Inputs:
|
· RxD
· Clk
· GPin
|
® Receive line from the UART chip
® Clock line to time the operation
® Data to be transmitted when data received (Not Used)
|
|
Outputs:
|
· Txd
· GPout
· NewData
|
® Transmit line from the UART chip (Not Used)
® Data received in parallel format
® Flag to signal that new data has been received
|
|
Block was prewritten[xxii] and uses two other Verilog files, called async_transmitter and async_receiver. These are the files that contain the main code that strip out the data for transmitting and receiving data on the serial port. It is essential these two files are in the same folder as the SerialModule file. To function correctly the files need to know the speed of the serial port (baud rate) and also the clock speed of the chip. The baud rate and clock speed is set inside the files as parameters. The operation of the async files is not discussed here but is available at the reference above. The SerialModule simply waits for data to be received and transmits a response back. In the circuit the response is always 0 as its not implemented. A slight modification was made to bring the NewData line outside the module.
|
|
Purpose:
|
Takes a desired position and sets up a pulse to drive a servo motor.
|
|
Inputs:
|
· DesiredPos
· Clk
· Change
|
® The desired position of the servo (8bits)
® Clock
® Update the servo position to the desired position
|
|
Outputs:
|
· RCservo_pulse
· Position
|
® Pulse stream to servo control line
® Current position of the servo
|
|
Again block was prewritten and needed modification. A full listing and description is available from the sourcexxi. The pulse length varies between 1ms + (position*3.9uS), the tick count is used to generate the 3.9uS delay. This required modification to work under the 50Mhz clock. The parameter ClockDiv was set to 196 and the pulse count register was extended to prevent it overflowing. The RS232 part of the code was removed and the perform change signal was implemented. The position data was brought inside and out the module as a number of registers.
|
|
Purpose:
|
Decodes commands received on serial port and performs the desired action on the outputs.
|
|
Inputs:
|
· CommIn
· Clk
· DataAv
|
® The 8 bit input command received from serial block
® Clock
® Flag that new data has been receiver (From Serial)
|
|
Outputs:
|
· LaserEn
· Xpos
· Ypos
· DoMove
· ModData
· ModEnable
|
® Former LaserEn line, Now Output3
® Desired position of X (pan) servo
® Desired position of Y (tilt) servo
® Signal to move servos to desired position
® 6bit data to modulate by PIC
® Line to enable the pic modulator
|
|
The function of this block is to take the 8 bits that have been output from the SerialModule and strip out the command bits to determine which command is being addressed from Table 2 above. It performs this on the rising edge of the DataAv line from the SerialModule.
The way it performs this is by using a number of multiple nested switch-case statements. The first (outermost) switch determines what bits 1 and 0 are. If they are 00 (8bit servo position) then it uses another switch to determine which nibble of which servo is being addressed using bits 3 and 2 of the original CommIn data. The command ‘other commands’ also uses a nested switch statement. The concept is best illustrated in the pseudo code on the next page.
During the development stage it was discovered that the commands wouldn’t decode properly, in fact what would happen was that it would take a second command to perform the action of the first and then the third would perform the action of the second. This is believed to be a problem with the timing of the commands, and likely caused when the multiple commands execute at once. To solve this problem a wasted command was used which performed no action. Other methods were also employed to solve this such as a state machine which extended the length of the DataAv signal from the SerialModule to 5 clock periods. This implementation works and is available on the attached CD, “xyservo3” project. Since time was limited, it was not possible to develop this version further and the simpler implementation of the extra command was used.
7654|32|10 <- Bit Number CommIn = xxxx|xx|xx
|
|
On positive edge of NewData signal… Do the following
If (bit1 & bit0 is 00) Command is 8bit servo positions so check next 2 bits…
If (bit3 & bit2 is 00) set lower 4 bits of desired X position to (bit7 to 4)
If (bit3 & bit2 is 01) set upper 4 bits of desired X position to (bit7 to 4)
If (bit3 & bit2 is 10) set lower 4 bits of desired Y position to (bit7 to 4)
If (bit3 & bit2 is 11) set lower 4 bits of desired Y position to (bit7 to 4)
If (bit1 & bit0 is 01) Command is move both servos (6bits)…..
Set Upper 6 bits of desired X & Y position to (bit 7 to 2)
If (bit1 & bit0 is 10) Command is set modulator data (6bits)…..
Set Upper 6 bits of desired X & Y position to (bit 7 to 2)
If (bit1 & bit0 is 11) Command is another command so check remaining 6bits…..
If (bit7 to 2 is 000000) set output3 to be LOW
If (bit7 to 2 is 000001) set output3 to be HIGH
If (bit7 to 2 is 000010) add one to the desired X servo position
If (bit7 to 2 is 000011) subtract one from the desired X servo position
If (bit7 to 2 is 000100) subtract one from the desired Y servo position
If (bit7 to 2 is 000101) add one to the desired Y servo position
If (bit7 to 2 is 000110) set modulator enable line to be LOW
If (bit7 to 2 is 000111) set modulator enable line to be LOW
If (bit7 to 2 is 111110) Do nothing
If (bit7 to 2 is 111111) Set servo position to desired position
End
|
In order to verify the operation of the controller and test the commands, a test program was designed in Borland C++ Builder. With this program all the commands could be sent over the serial link to the controller.

Figure 21 - Test Program GUI
Once of the main features of the program is the grey square. By clicking activate scan, the user can move the mouse over the area to move the head to any position within the 8bit range of the servos. To send this data requires four 8 bit commands.
Using the slider bar in the middle a value can be sent to the PIC microcontroller which is modulated into a RC5 command as the data bits. The Enable and Disable buttons simple enable and disable the modulation line. The Out3 button is used to turn output 3 on the FPGA on or off. This was originally used to turn the laser on and off in initial development, however when the method was switched to IR, the line in the wiring had to be used for the IR circuit.
The X and Y servo positions can be set roughly to any value within the range of travel to a resolution of 6 bits. This operation is performed in a single 8 bit command. The move left, right, up and down buttons all simply add or subtract 1 from the current coordinate position.
Since the program was used on multiple systems using different COM ports, initially upon starting up, the program attempts to open COM port 1. If this is unsuccessful then it attempts to open COM port 2. If this again is unsuccessful an error message is displayed. A Fully commented listing of the program is available on the attached CD. The main functions and operation is discussed below.
FormLoad
This is the function that runs when the program is first opened. The purpose of this function is to open the COM port at the specified speed. First it tries to open COM1, if this is unavailable, it opens COM2.
SendCommand
This command takes an integer value passed to it and converts it to a char and then writes this char to the serial port. It is converted to a char as these are 8 bits and is what the serial port writing function requires. After the command has been written the DoCommand value is sent. No check is made if the value passed is greater than the max (255) however this will produce an error when the program attempts to cast a number greater than 255 (Maximum value of a char).
ModData
This function sets up the modulation data command using a modulation value that is passed to it, and then writes this value to the serial port. The modulation value is shifted 4 bit places to the left and then 2 (10bin) is added to it for the command number. A DoCommand then follows. The FPGA then outputs this value to the PIC.
Move
The purpose of this function is to move both servos to a 6 bit position (0 to 63). The function sets up the command and sends it, followed by a MoveServos command to actually perform the move. The position value is shifted 4 bit places to the left and then 1 (01bin) is added to it for the command number.
MoveAccurately
This function sends 5 commands on the serial port to move the servos to a specified position with 8 bit accuracy. To do this is sends the 4 nibbles of the two 8bit positions (X&Y) one by one by setting up the commands using bit shifting and addition of the command numbers. See command table or commented code for further information.
Example of X position = 10010111, Upper Nibble = 1001, Lower Nibble = 0111.
Upper 4 bits of X position command = 0100 = 4 decimal Lower 4 bits of X position command = 0000 = 0 decimal
1st command to send: shift upper nibble (1001) four places to the left = 1001 0000
now add command value (0100 for upper) = 1001 0100 now send command.
2nd command to send: shift lower nibble (0111) four places to the left = 0111 0000
now add command value (0000 for upper) = 0111 0000 now send command. Now send MoveServos command.
ScanButtonClick
This function is executed when the user clicks on the button which says “Activate Scan” or “Deactivate Scan” depending upon the current state. Its purpose is to either enable or disable the automatic movement which occurs when the user pans their mouse over the grey scan area shape.
ScanAreaMouseMove
This is the function that is called every time the user hovers the mouse over the scan area. The function is passed the coordinates of the mouse relative to the shapes top left corner as X and Y. The shape has been deliberately set to 255 pixels high and 255 wide, the same as the number of positions possible with the servos. This means every pixel uniquely defines a coordinate position possible with the pan and tilt head. Since the origin of the shape is top left, and the origin of the servos is the top right, the x-position is calculated at 255-X. The function, if activated will perform a servo move to position ( (255-X) , (Y) ) and update the caption below the shape to display the current position.
ModValueBarChange
This function is called when the Modulation Value slider bar changes value. This function simply updates the label below showing which value has been selected.
AutoMoveButtonClick
This function is called when the AutoMove button is clicked. Its function is to enable or disable the automatic movement of the servos depending upon the position of the slider. When disabled the user needs to click the Move servos button. Clicking the button inverts the current state.
XYPosBarChange
This function is called when the XY Position slider bar changes value. If automove is enabled then it automatically sends the move command to the servos to move both servos to a rough 6 bit position.
Rest of ButtonClick functions
The remaining functions are all functions called when a button is clicked. They set the modulation value, enable/disable the modulation, move both servos, move a servo one position, enable/disable the output3 and exit the program. See program for more information.
|