Our software design is very structured and well organized. All the tasks are performed in the endless while(1) loop in main(). The program checks cricket-feelers for obstacles, runs a main statemachine() that performs all cricket normal functions; it checks for remote IR control signals and executes control tasks accordingly. The last two functions in main() sends out pwm signals to the three motors, with signal high-time specified by the two statemachines.
Here, we will step through these main tasks to give you a picture of the logic behind this circket robot.
When the cricket bumps into something, The feeler switch(es) is(are) closed. Input "PINA.4" and/or"PINA.5" is(are) set to logic "0". "cricketstate" is set to "righthit" or "lefthit" to tell the main statemachine to perform "backup" and "turnleft"/"turnright" tasks. We'd like the cricket to make a noise when it hits an obstacle, so in these two functions, a random number is grabbed from main(), to randomly choose a song and song duration. (For cricket song generation, please refer to Timer0 and Timer1 ISR section.)
Cricket Operation Main Statemachine
We used a statemachine approach to code up the cricket operation, as statemachine scheme has proved to be very useful and logic throughout our lab exercises. The statemachine switches among "walkforward", "back up", "turnleft", "turnright", and "dance chacha". (Note: they are different from the state names in our code.)
Basically, these different movements are controlled by the pwm signals sent out to the 3 motors. Therefore, the main function of the statemachine is to change pwm high-times(logic "1") to vary the motor-shaft turning angles and legs-position combinations.
Initially, we programmed the legs to move almost at the same time. It turned out that the cricket had a little balance problems while it walked. We then figured out that we needed to move the center legs first before moving the right-side and left-side legs. This was implemented by adding an additional state between center and side legs movement, which means the side legs are delayed by exactly one state transition time "dt".
"back up" is pretty much the same as "walkforward", except that the center legs positions have to be reversed for the cricket to go backwards. "turnleft" or "turnright" follows a similar idea. Only one side of the legs is moved while the cricket turns. Again, it's just a matter of manipulating pwm high-time combinations for the three motors. Although the final code looks very simple, we were very confused about the legs movement for quite a while. We had to mimic the cricket legs motion ourselves to figure out exactly how the legs work. We had a lot of fun arguing and drawing pictures.
The most amusing part of this project is that we have programmed the cricket to be an excellent cha-cha-cha dancer. It is indeed one of our favorite operations. The Cricket moves its left (or right) legs forward one step, and then move back for the next rhythmic period. Then the Cricket changes its moving legs from one side to another side. It steps its legs forward and then backward at the same rate. When the Cricket does move fast enough, you can see clearly its steps, just like a professional cha-cha-cha dancer.
This statemachine is really a IR control signal decoder. Here we will explain how the Sony remote control protocol works:
- The data codes are sent using pulse coding. - Each packet of data codes contains 12 bits and start header.
- The length of the header for our Sony remote is 650us (measured using oscilloscope)
- The 12-bit data codes are made up of a 7-bit button code, followed by a 5-bit device ID code to specify the object for which the signal is meant (i.e, TV, stereo, VCR…)
- Input to the IR detector is always high if no button is pushed. A button press produces a control DataStream of "0"s and "1"s.
- A zero = length of 120us
- A one = length of 180us
For each button press DataStream, the last 5-bit device ID codes are the same if we uses the TV mode. We only need to decode the first 7-bit code to figure out which button is pressed.
To measure the length of the header, a "0" or a"1", we used External Interrupt0 service routine. Please see the External ISR section for details.
In this statemachine, start header of 650us is pre-checked to confirm a valid IR control signal. Given a valid IR signal, we detect the first 7-bit pattern. A variable called "remotetime" is used as an intermediate computation variable, which stores the incoming bit from IR remote. As a new bit is received, the old bit is shifted to the right if it is a "0", and if it's a "1", a "OR" operation to the old "remotetime" in addition to the right shift is needed in order to pad this new "1". Once 7 bits have been padded together, the "remotetime", which contains the button code, is copied to another variable "remote" as the IR control signal identification.
This statemachine is executed on every External Interrupt.
IR control switching function-IRcontrol()
This function performs the execution of different IR control command from user based the signal identification variable "remote". It is simply a bit switch statement. Again, we manipulate pwm high-time to control the cricket leg movement. To stop the cricket, we reset the main statemachine to initial state and center the cricket legs; to make the cricket move forward faster, we reduce the main statemachine transition time; to make the cricket turn of back up, we change the pwm high-time of the three motors; to reset the cricket back to normal operation, we just reset all IR control flags to 0, and cricketstate to cricketwalk; to play cricket songs, we specify the song number, burst frequency, song duration; to let the cricket dance cha-cha-cha, we changed mainstatemachine to chacha state.
Implementation is very simple and clear, and it didn't take us long to code it up.
Interrupt Service Routine
1. Timer0 ISR
Timer0 is used as a task timer for our program. Timing variables for each tasks are decremented by 1 on every timer0 interrupt, which is initialized to 0.1ms.
We toggle PORTA.0, PORTA.1, PORTA.2 on specified pwm high and low time to control shafts turning angles.
There are three tasks needed to generate cricket songs. These task timers are only decremented if the duration is bigger than 0. This increases the timing accuracy for other tasks when cricket songs are not played.
2. Timer1 ISR
Timer1 is used to generate cricket song burst frequency. PORTC is toggled on every Timer1 CompareA on match interrupt. This is exactly the same as lab3 exercise.
3. External Interrupt0 ISR
External Interrupt0 is used to detect IR remote signal. It's configured to interrupt on falling edge to detect the start header, and then reconfigured to interrupt on rising edge to detect the 7-bit of "0"s and "1"s for button press decoding.