The AimBot rig is to be controlled remotely. To achieve this we are using a standard RC remote of the same type that's normally used with RC cars and planes. The reciever for this unit uses very little power, and is in a very handy size for our rig.
The control and reciever |
The reciever puts out a PWM signal, and every joystick and button is designated it's own PWM chanel,
For our rig we will be using 4 chanels:
- X-axis joystick
- Y-axis joystick
- Mode switch
- Picture trigger
Every chanel is input to separate digital pins on the Arduino.
Interrupts
In the Arduino program every pin gets set up with a hardware interrupt that runs a interrupt function when the pin state changes. This interrupt is run immediately when the state changes, and interrupts all other code execution. After the interrupt routine is run the code returns to whatever it was doing before it got interrupted.
The code that runs during the interrupt checks the state of the pin that called the interrupt and checks the current time from the internal microseconds counter. The next time the pin state changes the last recorded time is subtracted from the current time, which gives the length of the pulse. The pulse length is then stored in a global variable so it can be accessed by other parts of the program. The image above shows the PWM pulse, where T is one of the pulse lengths we want to measure.
Time and memory
The function code uses micros() to get the current time, this returns a unsigned long (32 bit), that overflows every 70 minutes or so.
Elapsed time is stored in a uint16, this gives us the ability to measure frequencies down to 15 Hz before overflow occurs. The picture below shows the calculation regarding this:
The lowest possible frequency for the PWM signal is around 50 Hz, giving us good margins before overflow.
The counter value is also declared volatile to remove the write-protection, allowing the value to be updated from the interrupt without interfering with the rest of the program.
Advantages over other methods
The Arduino has a ready made library for reading pulse-width modulated signals. The function sigin() can be used for this purpose. We considered using this function, but upon closer examination we decided not to. The reason is that the sigin() function hangs upon call, until the pulse has passed. For a 50 Hz signal this would use about 20 ms per chanel.
Reading the signal using interrupts on the other hand only records the current time of every pass and allows the rest of the program code to continue executing almost immediately.