So now that our control box device has sent 4 data packets on their way to the microcontroller on board the ROV, we have to figure out a way to process and decode those packets in a manner to causes the vehicle to respond in the manner intended by the operator. There is very little going on inside the main loop of the program as most things here are interrupt driven. The configuration of the appropriate modules of the PIC is similar to that found on the control box device so I won't repeat the explanation here. Before we begin receiving and decoding signals, we first need to initialize the 6 thruster ESCs.
Prior to entering the main loop and in the configuration section of the code you will see a call to a subroutine named "ESCinit".
It should be noted that this call needs to take place AFTER configuring the PWM and UART modules since PWM signals are used as part of the initialization process and an alert is sent via UART to the control box to signal a successful initialization. ESC initialization only takes place once during startup and is not called again unless the device is reset. "ESCinit" is found in the motorStuff.asm file. The subroutine can be seen below:
The subroutine is essentially sending a "stopped" signal to all 6 ESCs for four seconds as per the ESC data sheet. PORTD holds the values to be ANDed with the PWM signals being sent to the quad AND gate ICs. Pins 0-3 of PORTD are each connected to one of the four inputs on the "forward" AND gate IC. Pins 4-7 are each connected to one of the four inputs on the "reverse" AND gate IC. Therefore, by loading the binary number 00001111 into PORTD, we are sending this 1500uS "stopped" signal to the four corner thruster ESCs via the forward labeled AND gate IC. The two up/Down thrusters are controlled directly through the CCPR3L PWM module and have nothing to do with the AND gates.
Just before the ESCinit routine exits, it transmits the number 2 to the topside control box. Once this value is received by the topside MCU, an interrupt is triggered and upon seeing the value "2", the "ESCready" subroutine is called. This subroutine can be found in the indicators_and_warnings.asm file of the control box project. It quite simply turns on an LED of the control box that lets the user know that the ESCs are initialized and ready to receive signals.
The simple main loop can be seen below:
Bit #1 of the "readyThrust" is set in our interrupt service routine upon the reception of all 4 data packets and cleared upon sending the appropriate signals to all 6 motor ESCs. This prevents any data being sent to the ESCs until we have all of the required values needed to move the ROV in the correct direction. Once this is the case, the subroutine "processThrusterStream" is called. So essentially, UART receptions are continually causing interrupts and after every 4th interrupt, the subroutine "readyThrust" is called. Lets take a look at the interrupts.
There are two events (as of the moment) that will trigger an interrupt on board the ROV. They are: 1) An alert of the leak detector module, and 2) A UART reception. Since UART reception is somewhat more complicated let's take a look at that one first.
The first thing the ISR does is determine the source of the interrupt:
Since we are discussing UART reception interrupts, we will assume that the receive interrupt flag if the PIR1 register has been set. This will take us to the "UartReceive" label.
Once at this point, the first thing done is a call made to the "Receive" subroutine which is found in the uart.asm file and is shown below:
The following screen shot shows how we determine what type of data is contained in the packet. We first do a quick subtraction to see if the value in the data packet is between 0-7. These values could only be codes for the directional state since they fall outside of the range of values that could be used to configure the duty cycle of the PWM module. The state data should always be the first packet received of the 4 total. Once the state data is received a counter is started (from the number 1). Once the next UART reception triggers an interrupt, the data in the packet will be outside of an acceptable range of values for "state" and the counter is checked. Since the counter is at "1" the next data packet will placed into the "forwardSpeed" variable. This is the value that will be used for the PWM module to generate a duty cycle for the forward rotating thrusters. The counter is then incremented and checked again upon the next interrupt. Likewise, the next data packet will be placed into the variable named "reverseSpeed". This is the value to be used by the PWM module generating a duty cycle for the reverse rotating thrusters. The counter is again incremented. The fourth and last data packet (of the set) is loaded into the variable named "upDownSpeed". This value is used to generate the PWM signal for the two up/down thrusters when we want to dive or surface. After reception of the 4th packet, the counter is reset to "1" and the process is repeated. Once again, a screen-shot of the above explanation is shown below:
Notice also that upon reception of the 4th packet (up/down data) the first bit of "readyThrust" is set. When this bit is tested in the main loop (and found to be set) we know that all four packets have been received and we can then go one to process that data into values to be sent to the ESCs. By only starting the counter after reception of the "state" data packet and not allowing any change in speed/direction to be sent to the ESCs until all 4 packets are received, we prevent the order of the packets from getting mixed up and the wrong data packets from getting placed into the wrong variables.
Processing the data packets
Once the "readyThrust" flag is set and we have all four packets, we make a call to the "processThrusterStream" found in the motorStuff.asm file.
Here, the values of all four packets are used to determine the direction our ROV needs to move. Everything depends on the value found in "state" so that is what is checked first. The value of state (a number from 0-7) is loaded into the work register and a lookup table is called. The table is shown below:
The number in the work register is added to the program counter which causes the counter to end up in a section of the table that places a different value into the work register and returns back to where we left off in the "processThrusterStream" subroutine. This value is then placed into PORTD. PORTD is connected to one input on each of the 2 quad AND gate ICs. Now when PWM values are placed into CCPR1L (connected to the "forward speed" AND gate IC), CCPR2L (connected to the "reverse speed" AND gate IC), the appropriate signals get sent to the appropriate ESCs. This may not seem very intuitive when described with words and it took me a little time to devise this scheme, but hopefully by studying the schematic and code for a while it will make sense to you. Lastly, before exiting the "processThrusterStream" subroutine, bit #1 of "readyThrust" is cleared so the whole process can begin over again when we get back to the main loop of our program.
Leak detector interrupt
The other source for an interrupt is via the leak detector module. This tiny module can also be purchased from Blue Robotics and has four probes that can be placed throughout the water-tight compartment via adhesive sponges. Upon moisture saturation, a high signal is sent from the module. I have the leak detector connected to PORTB (which is configured for an "interrupt on change".
As you can see, the code for leak (1) is sent topside 3 successive times (just to be sure it gets through). The topside MCU receives this code and lights an LED as well as sounds a piezo buzzer to alert the operator of the situation. It is important to note that when the detector module senses water, the signal will be forever high. This would cause a never ending loop of leak detector interrupts which would prevent us from doing anything other than detecting leaks! In order to prevent such a scenario and allow the user to bring the vehicle to the surface upon leak detection, "interrupt on change" for PORTB is disabled after the leak is detected and signal sent topside.
Perhaps it's time to take a break from assembly programming for a bit and take a look at my choice of battery that I am using to power the vehicle.