Sorry I've been quiet for so long but I thought I'd share an update on the coding and electronics side of the project. It's been pretty interesting project so far and lots of lessons learned. So here's a rundown of the latest changes and why they are important.
The original publication on
Github was a working and functioning version of the Lawgiver with all of the same components we are still using. It worked, and worked very well. A lot of what I learned and some changes recently posted all stem with experimenting with different features of the Arduino microcontroller, working with a larger OLED, reading from the voice recognition circuit, and the functionality we wanted to replicate the Lawgiver we saw on screen. We wanted the features to feel polished.
As far as the microcontroller was concerned, we knew the Nano was best based on the space we were working with. We also knew we'd be pushing it with the number of components needed, and the number of pin outs we had to work with on the Nano. The basic approach with these small Arduino boards is that they run in a continuous loop, and in every loop you check for signals from inputs, and create output signals that make components do something like play a sound or turn on an LED. Immediately I figured that we would have trouble performing all the necessary operations in the main loop, which turned out to be true actually.
Originally, I started with using Interrupt Service Routines (ISR) for handling the trigger and reload inputs. The thought was that it could reduce time to read those signals because they needed to be debounce the signal inputs to prevent false positives and ensure the button is actually pressed. This processing takes time and multiple (read previous) cycles to determine. This approach proved to not work well at all. With a little investigation I concluded that the ISR does exactly the same thing that the main loop does but with no debouncing. Another downside is the way the ISR works, it basically stops (interrupts) the main loop while it's processing so you must be very quick, you don't want to spend a lot of time in the ISR routine otherwise the performance of the main loop suffers. Easy decision, rip it out and use the standard solution.
The first pass of the main code was to check all the input signals every time, and always write to the components that need it. This worked okay, but certain operations could be found lagging under different conditions. For example, checking the state of the fire trigger or ammo reload inputs would take multiple cycles to detect an action, or checking the voice recognition would have to make a serial communication on every cycle. These operations affect the timing of every other operation in the loop. Another huge consideration was both the LEDs and the OLED. Initiating an LED sequence which is timed and takes many cycles to complete. The OLED turns out to be the most costly operation of all the components having to write strings and draw shapes on the screen, and it has to redraw the entire screen every time. The BIG point here is both time and speed of the main loop are very critical.
So the main changes that really made a huge difference were to focus the main loop on only performing actions that were necessary and in the right order. First, the OLED display is only updated when something has changed like ammo fired or mode change, and it only happens after the other components have been initiated, namely the audio and LED sequence. This saved a ton of time. Next, it didn't make sense to always check the voice recognition module for inputs if another action had taken place since audio would be playing back which interferes with detecting a human voice. This seemingly made reading the VR module more reliable. But one final adjustment was necessary.
As I was putting in the strobing effect for the Rapid fire mode, the LED sequence would NOT execute properly. The initial flash would pause momentarily, just long enough to notice with the eye. I tried playing with different timings, using different sequence of commands but I couldn't get it to run properly. It was so vexing! This is where I really noticed the OLED operation causing a long enough delay to mess up the timing sequence on the LED strobe. In the end, I changed the OLED operation to wait for the LED sequence to complete before changing the display. It's subtle but it worked out beautifully. I'm still researching other options to actually speed up the write operations for the OLED which have lead to learning about a few ideas I can experiment with in the future, but I'm saving that for when I have more time to write some alternate implementations.
This has been a dream project for me. Chris
Props3D and I have been working on it literally for over a year now but it's been so worth it. We certainly appreciate all the feedback and excitement from everyone here on the RPF!