View on GitHub

ECE 4760 Glove Controlled Tilt Maze

Emmi Wyttenbach (ezw2), Ryan Chan (rc627), Cameron Camacho (cgc98)

Home High Level Design Program/Hardware Design Results Conclusion Appendix (Code, Files, etc.)

The Control Glove

Accelerometer

The MPU-6050 accelerometer we used communicates with the PIC over i2c. We fortunately discovered a previous ECE 4760 project (3DOF Stewart Platform) that used the same accelerometer we had, so we were able to adopt part of their code to read the accelerometer data. Their code contained several helper functions such as i2c_read, which enabled us to read various registers containing the data we wanted. The accelerometer values were updated in a thread that ran every 1ms. This was also where we calculated the values being sent to the motors. Initially, we were having problems with jitter, since the accelerometer readings were sensitive and fluctuated quite significantly. To address this, we created filter_x and filter_y variables, which low-passed the readings. We then used the filtered readings to create a direct mapping between the accelerometer values and pwm signal.

Accelerometer on glove
Low pass filter on accelerometer readings

Finger Sensors

For the finger sensors, we cut up a perfboard into 5 pieces (one for each finger) to be used as contact plates. The plate on the thumb is connected to 3.3V and the plates on the other fingers are conencted to an input pin. These sensors essentially behaved as buttons, where connecting the plate on a finger to the plate on the thumb closed a switch and pulled the voltage on the pin high. The four inputs were connected to pins 0-3 on Port Y. In order to address problems regarding debouncing, we implemented a thread to poll the state of each pin every 30ms (determined by human reaction speed) and utilized a button FSM for each input. bit_val is the value of one of four pins on the port expander corresponding to the specific finger we want to check.

Finger sensor fsm

The Maze

Physical Structure

The physical structure of our maze was made out of both 3D printed (from PLA plastic) and laser cut (from 1/8 inch birch wood) pieces, which we designed ourselves in Autodesk Fusion 360. We 3D printed the intricate parts that would be difficult to laser cut or assemble from laser cut pieces, such as the cones, servo doors, and maze itself. We laser cut the large and more basic parts that would take a 3D printer too long to print or would exceed the bed size of the 3D printer, such as the base for our maze. The CAD files (in STL and DXF formats) can be found in the Appendix page of this website.

Servos

The servos are controlled using PWM, which we implemented using output-compare peripherals on the PIC. We configured the output-compares to PWM mode, then connected them to timer2 and mapped them to different pins on the PIC. Then, in the ISR for timer2, which generated an interrupt every 1 millisecond (44,000 clock cycles), we wrote the updated pwm values, which were calculated in the accelerometer thread. We used a timer interrupt instead of a regular thread because we wanted to update the PWM duty cycles at precise intervals.

maze top view
x and y servos used to control tilt

For our game, we needed to control a total of seven servos; two for the tilt of the maze and five for the trap doors. However, the PIC only has five output-compare peripherals and each unique pwm signal requires its own. To get around this issue, we noted that the five servos for the trap doors will never need to move at the same time (due to the way in which we designed the game). This meant that we could output one pwm signal from the PIC, connect it to the COM OUT/IN pin of a demultiplexer, and use three additional pins for the demux select signal (labeled A, B and C in the diagram). Based on the select signal, the demux would send this pwm signal to one of the five servos.

IR sensors

To implement ball detection, we placed an IR LED on one side of each hole, and an IR receiver diode in series with a resistor that goes to ground. A signal pin connected to the PIC is placed between the diode and resistor. The resistance of the IR receiver diode changes depending on whether it detects infrared light (high when no IR is detected and low when it is detected). When the ball falls through it momentarily prevents the light from reaching the sensor, causing the diode resistance to greatly increase and making voltage drop across the resistor change from 3.08V to about 0.2V. We found that a higher resistance value for the resistor in series with the IR receiver allowed for a higher change in voltage across it, which is why we replaced our original design using 330 Ohms with 1 kOhms.

ir sensors
IR detection circuits

The IR signal inputs are connected to pins 0-4 on Port Z of the port expander, where we configured interrupts for each of these five pins. In order to trigger an interrupt on the PIC, we attached an external interrupt to RPA2, the PIC pin that communicates with Port Z. However, this means that the ISR will be entered upon a change in value on any of the port expander pins with interrupts enabled, without a direct way of determining which specific pin caused the interrupt. To solve this issue, we added a function that reads the Port Z interrupt capture register (which stores the state of the port when the interrupt was triggered) so that we could compare the new port values to the previous ones and determine which one changed. Then, based on the value of the destination hole, we set a win_round flag which is used in the after_round game state to display the appropriate message.

funnels
Funnels used to catch the ball as it falls through the maze

TFT Display

To display the images on the TFT, we first converted our images to bitmaps using this website, then rewrote the tft_drawBitmap function in the tft graphics source file to draw rectangles for each pixel in the image. The size of this rectangle was passed in as a parameter so we could decide how much we wanted to scale the image by. Though it is rather slow to loop through each element in a bitmap and draw a rectangle for each pixel, we decided that this was an acceptable sacrifice due to the fact that we only need to print everything once. This means that it will not interfere with the timing of the game, since after the thread runs at the beginning, it is not scheduled again until the start of the next round.

TFT Maze Display

Program Design

To control the game flow, we created a game state enum consisting of before_round, playing_round and after_round. We included a button in our circuit that, when pressed, would change the game state depending on the current game state, as illustrated in the figure below. To generate a random number for the destination, we utilized the ADC to generate a random seed. This involved taking two readings from a floating pin and summing them together, with the first reading left shifted by one and the second left shifted by 5. We then were able to call the rand() function and receive different random numbers upon resetting the PIC. To get a number between 0 and 4, we computed the randomized number mod 5. Using this number, we were able to create a direct mapping between each finger and the remaining doors.

Game Flow Button FSM