There were three software components to our hovercraft project: the client, the server, and the PIC.
The client is a graphical user interface (GUI) written in Python that allows a user to control the hovercraft's direction, speed, and whether it is on or off.
The server is also written in Python and is the interpreter between the client and the PIC.
The firmware on the PIC was written in C and it receives signals from the Python server via USB and then transfers them into voltages to be sent to appropriate places.
The Python was responsible for the client end and the server end of things. The client is very simple, it is an application written in PyGTK which brings up a little purple window with some buttons and sliders.
The user can control the direction and the velocity using buttons, arrow keys, or sliders, while the power (whether the ShopVac is on or off) is controlled by an On button and an Off button.
When the GUI receives an event from the keyboard or the mouse it figures out what the user was telling it to do and then uses a socket that it has opened with the server to send data.
The data is a small string that conveys which motor the user wanted to change, and what was desired.
For example, if the user wanted to change the direction of the hover craft and they hit the right arrow key the client would send "RL###" to the server
(where ### is the new position) - RL represents to the server that we are talking about the Right-Left motor, and the number represents the value that the server should convey to the PIC.
The server then figures out based on an if statement what to send to the PIC via USB.
The server has an open USB connection with the PIC and it has Vendor_Requests that it can send that the PIC understands.
So when the server receives "RL100" it goes through an if statement until it finds the vendor_request that corresponds to the RL motor.
It then uses the usb.control_write() method to write (in this case) 100 with that vendor_request.
When the PIC receives a message via USB it looks up in its loop what its supposed to do with that vendor_request as described below.
The firmware on the PIC18F4455 was written in an 18-bit variant of C, compiled with a C18 plugin for MPLAB, and installed on the PIC with MPLAB. A large portion of the code was supplied by Professor Minch [specifically, the pragma section, the Device, Configuration and String arrays, and the InitUSB, ProcessSetupToken, ServiceUSB, StandardRequests, ProcessOutToken, ProcessInToken, SendDescriptorPacket, and ClassRequests routines].
The void main(void) routine consists of instructions to configure the device as a USB peripheral, configure all the I/O registers, and a main event loop.
The main event loop [while(1)] contains little more than a for-loop. This inner loop [for(i = 0; i < 3; i++)]reads each of the potentiometers, converting them to a 10-bit digital number from the analog signal on the potentiometer. The 8 most-significant bits of this number [ADRESH] are saved in POT_BUFFER[i], for later access. Then the direction of the i-th motor is changed based on whether or not these 8 bits are greater than POT_BOUNDS[i] [which can be set with a vendor request]. The effect of this if-else block inside the for loop is negative feedback, causing each motor to seek a user-given position.
After the for loop, a thermometer code representing one of the potentiometer values is displayed on PORTB.
No PWM is used. The circuit is configured such that 2 digital output pins are connected via transistors to either side of each motor. So, to turn a motor off, both pins are set to 0, so there's no voltage differential across the motor. To turn a motor on forward, one pin is set high, and the other low; for the other direction, the pins are switched.