The first step is to clearly define what the subsystem will do. In this case, the signal receiver reader, should take input from the device and output a useful representation of that signal. The device in question is very simple, it has four channels and outputs a pwm signal on each channel. The data which we are interested in, from the transmitter, is encoded in the form of the PWM signals' on-times. See my last post for a little more information on this device. This describes our first and second design constraints: take four channels as input and output data in a useful form.
In the image below we observe that the signals follow one after the other. This is useful since trying to interpret 4 signal lengths simultaneously (in parallel) would be a tricky endeavor for an Arduino. An important feature to note is the time between the signal blocks, all four signals which are very close to each other are from one single transmission. This leads to our third design constrain:, differentiate between different transmission blocks.
|Time Between Signals From The Same Transmission Block|
Next, let's look at the time between signal transitions in the image above. Given that it would be a waste to have the Arduino sitting around for however long it takes us to observe the 4 PWM signals we will utilize interrupts triggered by any of the 4 PWM signals. Between signals we have a time window of ~57.9μs (as seen above.) If we utilize a pin change interrupt library such as PinChangeInt we can expect interrupt completion times as high as 30-40μs, a little close for comfort. Therefore, the fourth design constraint is to ensure any operations between transitions(ie within interrupts) are concise. For an informative (and quite funny) read on the speed analysis of this library and its' interrupts check out their latest speed test documentation.
This brings us to another point. In understanding these signals it is important to understand minimums and maximums for on-times and off-times. This is effectively defining an expected behavior.
|All Signals Minimum On-Time|
|All Signals Maximum On-Time|
The two images above show the signals on-times when all are at minimum and maximum on-time. Determining on-times and off-times of individual signals can be done with the aid of an oscilloscope or logic analyzer.The length of both minimum and maximum on-times can be calculated with some simple simple algebra:
minimum_combined_signal_lengths = n*(min_length) + (n-1)(time_between_signals)
maximum_combined_signal_lengths = n*(max_length) + (n-1)(time_between_signals)
Example: min_combined = 4*(1.07e-3s) + (4-1)*(57.9e-6s) ≈ 4.45ms
Where n is the number of input PWM signals. The time between the end of the last signal's on-time from one transmission block to the first from the next can be calculated again with some simple algebra:
max_off_time = (1/Frequency) - (minimum_combined_signal_lengths)
min_off_time = (1/Frequency) - (maximum_combined_signal_lengths)
Example: max_off_time = (1/45.4(s^-1))-(4.45e-3) ≈ 17.58ms
Armed with this information we have our fifth constraint: utilize known on-times and off-times to sync data and signal when an error in the signal has occurred.
The last constraint is quite possibly the most important. The last constraint is to recognize when the receiver loses its' signal. The quadcopter and quite frankly any remote-controlled vehicle should have a fail-safe routine in the event that the communications link is lost. While that is outside of the job of this subsystem, this subsystem must recognize when the receiver has lost communications with our transmitter. To simulate this event all that has to be done is observe the receiver signals as we turn our transmitter off.
|Transmitter Signal Interrupted|
As can be seen in the images above, when the communications signal at the receiver is lost, the receiver defaults to only outputting a minimum on-time signal on the throttle only (channel 3 in the images above.) This is our last and final constraint: signal if the communications signal is lost.
Our design constraints, as outlined below, are not a complete list nor are they explicit instructions but they do serve as a good checklist so that we are not just typing away hoping our code does something useful.
- Take as input 4 channels.
- Output data in a useful form
- Differentiate between different transmission blocks
- Concise interrupt code.
- Utilize known on-times and off-times to sync data and signal when an error in the signal has occurred.
- Signal if the communications signal is lost.
Now start coding! It should be noted that I usually create a state diagram before I start coding haphazardly. You should have a plan to go with your constraints....
Always have a plan!