Difference between revisions of "S16: Fantastic Four"
Proj user4 (talk | contribs) (→Schedule) |
Proj user4 (talk | contribs) (→Team Members & Responsibilities) |
||
(147 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== '''Smart Alarm Clock for the Stubborn Sleeper''' == | == '''Smart Alarm Clock for the Stubborn Sleeper''' == | ||
+ | [[File:CMPE244 S16 FantasticFour Clock with LED Disp and RGB Lighting.jpeg|centre|600px]] | ||
== Abstract == | == Abstract == | ||
− | This smart alarm clock encapsulates a variety of features that are intended to wake up a stubborn sleeper who cannot get up in the | + | This smart alarm clock encapsulates a variety of features that are intended to wake up a stubborn sleeper who cannot get up in the morning. As opposed to your average alarm clock, this alarm clock has the ability to wake up the user using dynamic lighting combined with customizable sounds. An external unit, which is placed beneath the mattress, has a bass shaker built in to vibrate the mattress to aid in helping the user get out of bed. The external mattress unit also has a flex sensor that can detect whether the user is in bed or not, and is used to turn off the alarm once the user gets out of bed. |
+ | |||
+ | [[File:CMPE244 S16 FantasticFour Functional Block Diagram.png|centre|800px]] | ||
== Objectives & Introduction == | == Objectives & Introduction == | ||
Line 37: | Line 28: | ||
* Sara Sepasian | * Sara Sepasian | ||
− | ** | + | ** RGB LEDs |
* Michael Jaradah | * Michael Jaradah | ||
− | ** | + | ** Breakout board schematic capture and layout, RGB LEDs, Wireless Mesh Network, Shaker, Flex Sensor |
* Rabeel Elahi | * Rabeel Elahi | ||
− | ** | + | ** 8X8 LED Matrix Displays, Alarm API integration with RTOS, Wireless Mesh Network, Flex Sensor |
* Farhan Naeem | * Farhan Naeem | ||
− | ** | + | ** Hardware architecture, board layout, software architecture, mechanical design and integration, audio module |
== Schedule == | == Schedule == | ||
− | |||
{| class="wikitable" | {| class="wikitable" | ||
Line 67: | Line 57: | ||
* Finish first revision of enclosure | * Finish first revision of enclosure | ||
| Completed | | Completed | ||
− | | | + | | |
* Decided not to use BLE module due to time constraint | * Decided not to use BLE module due to time constraint | ||
− | + | | | |
|- | |- | ||
|- | |- | ||
Line 78: | Line 68: | ||
* Create alarm state machine diagram | * Create alarm state machine diagram | ||
* Create functional block diagram | * Create functional block diagram | ||
− | |||
| Completed | | Completed | ||
| | | | ||
Line 87: | Line 76: | ||
| 3/29 | | 3/29 | ||
| Schematic capture, BOM & design review | | Schematic capture, BOM & design review | ||
+ | * Finalize schematic; start laying out parts onto PCB | ||
+ | * Finalize parts and generate BOM | ||
+ | * Verify all parts meet design requirements | ||
| Completed | | Completed | ||
| | | | ||
Line 103: | Line 95: | ||
| 4/5 | | 4/5 | ||
| Board layout & design review | | Board layout & design review | ||
+ | * Finalize PCB layout and verify wiring | ||
+ | * Finalize hardware and software designs | ||
| Completed | | Completed | ||
| | | | ||
Line 127: | Line 121: | ||
| 5/1 | | 5/1 | ||
| Software module development | | Software module development | ||
+ | * Start writing API for all peripherals | ||
+ | * Start writing RTOS Tasks | ||
+ | * Implement state machine into RTOS Tasks | ||
+ | * | ||
| Completed | | Completed | ||
| | | | ||
Line 135: | Line 133: | ||
| 5/7 | | 5/7 | ||
| Software integration | | Software integration | ||
+ | * Test all peripherals | ||
+ | * Integrate peripherals into RTOS tasks | ||
+ | * Test state machine | ||
| Completed | | Completed | ||
− | | | + | | |
| | | | ||
|- | |- | ||
Line 142: | Line 143: | ||
! scope="row"| 8 | ! scope="row"| 8 | ||
| 5/15 | | 5/15 | ||
− | | | + | | Debug and test |
| Completed | | Completed | ||
| | | | ||
Line 150: | Line 151: | ||
== Parts List & Cost == | == Parts List & Cost == | ||
− | + | ||
+ | [https://www.adafruit.com/products/1381 VS1053 Codec + MicroSD Breakout] x1 (~$25) | ||
+ | |||
+ | [https://www.adafruit.com/products/1052 8x8 matrix displays] x4 (~$13) | ||
+ | |||
+ | [https://www.adafruit.com/products/1712 Stereo 2.8W Class D Audio Amplifier] x1 (~$10) | ||
+ | |||
+ | [http://www.amazon.com/E-store-Ws2812b-Individually-Addressable-Nonwaterproof/dp/B019DYZNU0?ie=UTF8&psc=1&redirect=true&ref_=oh_aui_detailpage_o00_s00 RGB LED strip (144 LEDS/m)] x1 | ||
+ | |||
+ | [http://www.mouser.com/Search/ProductDetail.aspx?R=AS04008CO-Rvirtualkey66500000virtualkey665-AS04008COR 2W 8OHM OVL SHP SPKR] x2 (~$6) | ||
+ | |||
+ | [http://www.amazon.com/TDA7492-Digital-Audio-Amplifier-Board/dp/B00KX3HKOI?ie=UTF8&psc=1&redirect=true&ref_=oh_aui_detailpage_o00_s00 50W Amplifier] x1 (~$15) | ||
+ | |||
+ | [http://www.amazon.com/Dayton-Audio-TT25-8-Tactile-Transducer/dp/B009RGJ47S?ie=UTF8&psc=1&redirect=true&ref_=od_aui_detailpages00 Bass shaker] x1 (~$21) | ||
+ | |||
+ | [http://www.amazon.com/SPECTRA-SYMBOL-SYMBOLFLEX-SENSOR-2-2/dp/B00FPXIV6M/ref=sr_1_1?ie=UTF8&qid=1464238029&sr=8-1&keywords=flex+sensor Flex Sensor] x1 (~$8) | ||
+ | |||
+ | [https://oshpark.com/ PCB] x1 ($40) | ||
+ | |||
+ | Custom Made Enclosure | ||
== Design & Implementation == | == Design & Implementation == | ||
− | |||
=== Hardware Design === | === Hardware Design === | ||
− | [[File:CMPE244_S16_FantasticFour_PCB.png|centre| | + | |
+ | ===== Hardware Architecture ===== | ||
+ | [[File:CMPE244 S16 FantasticFour System Block Diagram.png|centre|800px|thumb|Hardware Architecture]] | ||
+ | |||
+ | ===== Breakout Board Schematic ===== | ||
+ | [[File:Cmpe244 S16 FantasticFour Schematic.png|centre|800px|thumb|Breakout Board Schematic]] | ||
+ | |||
+ | ===== Breakout Board PCB ===== | ||
+ | [[File:CMPE244_S16_FantasticFour_PCB.png|centre|600px|thumb|Breakout Board Layout]] | ||
Line 167: | Line 194: | ||
After the schematic and board files were completed, we went with a US-based PCB fab company called OshPark. This company is known for their purple PCB's, being very reliable, and having quick turn around time. In addition to this, their website is very user friendly and designed to be for hobbyist. They do not require any gerber files, and generate every file they need by uploading the .sch and .brd files. From there, they automatically generate the files and go through the design checking process. In total, the PCB took 11 days from submission of payment to receiving the board. | After the schematic and board files were completed, we went with a US-based PCB fab company called OshPark. This company is known for their purple PCB's, being very reliable, and having quick turn around time. In addition to this, their website is very user friendly and designed to be for hobbyist. They do not require any gerber files, and generate every file they need by uploading the .sch and .brd files. From there, they automatically generate the files and go through the design checking process. In total, the PCB took 11 days from submission of payment to receiving the board. | ||
+ | |||
+ | |||
+ | ===== Flex Sensor ===== | ||
+ | |||
+ | The flex resistor was used in the project to detect whether a user was in the bed or not. Two flex resistors were tested and used, with one resistor being more accurate than the other, giving better values. The flex sensor was 4.5" in length. As the sensor is flexed, the resistance across the sensor increases. Using the ADC pins on the board, we were able to view the data of the resistor flex when somebody was in bed, and call a sender function to the alarm clock. | ||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour Flex Resistor.jpg|center|300px|thumb|Flex Resistor]] | ||
+ | |||
+ | =====Transducer Mini Bass Shaker ===== | ||
+ | |||
+ | The transducer bass shaker was used in the project to vibrate the user who was staying in bed even after their alarm had gone off. This puck was extremely powerful depending the vibration level that was desired. For our use case, we started making patterns such as SOS, Long Vibration, Short Vibration, Pulse, Heartbeat, and even a custom pattern function for the user to define their own. The patterns became more and more rigorous depending on the users snooze count. | ||
+ | |||
+ | The puck was interfaced through a slave SJOne board, which was separate from the alarm clock master device. In addition, we used a Pulse Width Modulation (PWM) to control the vibrations, as well as a voltage dividing circuit. For the wiring schematic, the bass shaker puck was wired to a 50W amplifier, which required a 12V source. A voltage dividing circuit was then added to the amplifier in order to step down the SJOne board's output voltage from 3.3V (actually around 2.6V, due to the PWM) to 500mV. The bass shaker was then brought down to a desired frequency level, and given a set duration to be left on and off. | ||
+ | |||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour Bass Shaker.jpg|center|400px|thumb|Bass Shaker]] | ||
+ | |||
+ | =====Final Slave Unit ===== | ||
+ | |||
+ | This was the final slave unit enclosure. The unit was installed into an ottoman, which was the closest thing to a bed as we could get without actually bringing a bed to the demo. However, the unit has been tested and implemented with a bed and works well. In the picture, you can see the amplifier, the bass shaker, the voltage dividing circuit, as well as the slave SJOne board running with the Mesh Network. | ||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour SlaveUnit.jpg|center|400px|thumb|Slave Unit]] | ||
+ | |||
+ | ==== 8X8 LED Matrix Displays ==== | ||
+ | [[File:Cmpe244_S16_FantasticFour_Matrix_Displays_Mesh.PNG| 500px | thumb | center | Figure 2. LED Matrices]] | ||
+ | |||
+ | The 8x8 matrix displays with backpack drivers (HTK1633) were chosen primarily because of their ultra-bright pixels which shine through the black fabric mesh on the front of the alarm clock. These specific displays are interfaced over I2C, making the wiring less hectic since I2C uses only two wires (SDA and SCL). External pull-up resistors were not needed since the backpack drivers had them built in. Each display requires 5V at 1.5A which is sourced by the breakout board's +5V supply. The SJOneBoard (master) drives the addressable displays with SCL running at the specified frequency of 400 kHz. | ||
+ | |||
+ | ==== Industrial Design ==== | ||
+ | |||
+ | We collaborated with an industrial designer to design a custom mechanical package that houses all of the electrical components. Solidworks was utilized to model the entire assembly. The CAD model was then used to laser cut sheets of acrylic to construct the enclosure. The front bezel assembly was 3D printed to contain the LED displays and speakers. A fabric mesh was then used to cover up the displays and the speakers. | ||
+ | |||
+ | [[File:CMPE244_S16_FantasticFour_EnclosureCADDesign.png|centre|600px|thumb|Solidworks CAD Modeling]] | ||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour EnclosureCADRendering.png|centre|600px|thumb|Designer's Rendering]] | ||
+ | |||
+ | ====Hardware Assembly/Integration==== | ||
+ | [[File:CMPE244 S16 FantasticFour FrontBezelAssembly.JPG|centre|400px|thumb|3D Printed Front bezel assembly]] | ||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour MechanicalIntegration.jpeg|centre|400px|thumb|Electrical/Mechanical integration]] | ||
+ | |||
+ | [[File:CMPE244 S16 FantasticFour FinalAssemblyPicture.jpeg|centre|400px|thumb|Finished Assembly]] | ||
=== Hardware Interface === | === Hardware Interface === | ||
− | + | Refer to the Hardware Architecture diagram above for an overview of the interfaces utilized. | |
=== Software Design === | === Software Design === | ||
− | + | At the heart of the system is a task running the alarm clock state machine. The state machine code is executed whenever the alarm semaphore is given. The state machine is written to escalate the alarm level from one stage to another based on the users's action. | |
+ | |||
+ | [[File:CMPE244 S16 FantasticFour Alarm State Machine.png|centre|800px|thumb|Alarm State Machine]] | ||
=== Implementation === | === Implementation === | ||
− | + | ||
+ | |||
+ | ==== State Machine ==== | ||
+ | <pre> | ||
+ | //alarm semaphore | ||
+ | if (xSemaphoreTake(timeSem, portMAX_DELAY)){ | ||
+ | //only activate alarm if it has been enabled by the user | ||
+ | if(alarm_is_on) | ||
+ | { | ||
+ | switch(state){ | ||
+ | case ALARM1: | ||
+ | if(user_in_bed){ | ||
+ | alarmObj.activateAlarmLevel1; | ||
+ | state = ALARM2; | ||
+ | } | ||
+ | else{ | ||
+ | state = ALARM1; | ||
+ | } | ||
+ | break; | ||
+ | case ALARM2: | ||
+ | if(user_in_bed){ | ||
+ | alarmObj.activateAlarmLevel2; | ||
+ | state = ALARM3; | ||
+ | } | ||
+ | else{ | ||
+ | state = ALARM1; | ||
+ | } | ||
+ | break; | ||
+ | case ALARM3: | ||
+ | if(user_in_bed){ | ||
+ | alarmObj.activateAlarmLevel3; | ||
+ | state = ALARM4; | ||
+ | } | ||
+ | else{ | ||
+ | state = ALARM1; | ||
+ | } | ||
+ | break; | ||
+ | case ALARM4: | ||
+ | if(user_in_bed){ | ||
+ | alarmObj.activateAlarmLevel4; | ||
+ | state = ALARM5; | ||
+ | } | ||
+ | else{ | ||
+ | state = ALARM1; | ||
+ | } | ||
+ | break; | ||
+ | case ALARM5: | ||
+ | if(user_out_of_bed){ | ||
+ | alarmObj.activateAlarmLevel5; | ||
+ | state = ALARM1; //user is out of bed, reset to alarm1 for the next time | ||
+ | } | ||
+ | else{ | ||
+ | state = ALARM5; //repeat alarm until user gets out of bed | ||
+ | } | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | </pre> | ||
+ | |||
+ | ==== Matrix Display Class ==== | ||
+ | The matrix class was created using the singleton template so that only one instance of the class could be used throughout the code structure. The class consisted of various helper functions that initialized, cleared, and wrote to the displays as seen below. The helper functions would fetch the instance of I2C1 and write to the display registers. Since the breakout board was connected to the SJOneBoard header pins, I2C1 had to be used versus I2C2 which is located under the two 7-segment displays. In order to do this, a separate class, which inherited I2C_base class, had to be created for I2C1. | ||
+ | |||
+ | <pre> | ||
+ | /** | ||
+ | * Get instance of I2C1 class and initialize I2C1 to 400 kHz | ||
+ | */ | ||
+ | I2C1& i2c = I2C1::getInstance(); | ||
+ | i2c.init(400); | ||
+ | |||
+ | /** | ||
+ | * Get instance of matrix class | ||
+ | */ | ||
+ | matrix& matrix = matrix::getInstance(); | ||
+ | |||
+ | /** | ||
+ | * Initialize displays: | ||
+ | * | ||
+ | * matrix.init(display address, brightness, blink frequency) | ||
+ | */ | ||
+ | matrix.init(0xe2,0xEF,0x81); //Display 1 | ||
+ | matrix.init(0xe0,0xEF,0x81); //Display 2 | ||
+ | matrix.init(0xe8,0xEF,0x81); //Display 3 | ||
+ | matrix.init(0xe4,0xEF,0x81); //Display 4 | ||
+ | |||
+ | /** | ||
+ | * Clears the displays | ||
+ | */ | ||
+ | matrix.clearDisplay(void); | ||
+ | |||
+ | /** | ||
+ | * Writes time to the displays and accounts for colon | ||
+ | * | ||
+ | * @param string time to be written to display | ||
+ | */ | ||
+ | matrix.setTime(char string[]); | ||
+ | |||
+ | /** | ||
+ | * Writes any four letter word/number to the display | ||
+ | * | ||
+ | * @param string string to be written to display | ||
+ | */ | ||
+ | matrix.writeDisplays(char string[]); | ||
+ | |||
+ | |||
+ | </pre> | ||
+ | |||
+ | ==== Audio Interface Class ==== | ||
+ | The audio interface class provides the capability of initializing the UART communications interface with the Teensy module and playing an audio clip identified by an index value. | ||
+ | <pre> | ||
+ | class audio : public SingletonTemplate<audio> | ||
+ | { | ||
+ | public: | ||
+ | void initAudio(); | ||
+ | void playAudio(unsigned char command); | ||
+ | |||
+ | protected: | ||
+ | friend class SingletonTemplate<audio>; | ||
+ | |||
+ | private: | ||
+ | Uart2& u2 = Uart2::getInstance(); | ||
+ | }; | ||
+ | </pre> | ||
== Testing & Technical Challenges == | == Testing & Technical Challenges == | ||
− | + | We learned how challenging integrating hardware and software can be. There were many instances were we weren't sure whether an issue is being caused by hardware or software. At times we had pull out an oscilloscope to debug at the signal level to try to get to the root cause of an issue. Here are some of the challenges we ran into: | |
− | |||
− | + | === Difficulties interfacing with VS1053 audio module === | |
+ | Implemented driver as per manufacturer's recommendation. However we were unable to get it to work. Communications protocol was too complicated to fix/troubleshoot within planned time period. Resorted to using a Teensy board along with an audio module. A UART interface was implemented on the Teensy to read audio file selection sent from the SJ One board. | ||
− | === | + | === Clock frequency for RGB LEDs too high for MOSFET based level shifting circuit === |
− | + | The RGB LEDs initially selected for the project (WS2812) required a signal of 800kHz. The WS2812 requires 5V digital input, therefore requiring us to level shift the 3.3V output of the LPC microcontroller to 5V. The level shifting was implemented using a MOSFET based circuit with 3 pull-up resistors. The combination of the pullup resistors along with the internal capacitance of the MOSFET and the board capacitance resulted in the 800kHz signal being significantly attenuated. We ultimately resorted to switching to a different RGB LED strip which has less strict of a timing requirement as there's a separate clock signal in addition to the data signal. This allowed us to adjust the data rate by just setting the clock speed. | |
+ | |||
+ | === Software Integration === | ||
+ | On projects such as this one with multiple developers working on multiple aspects of the system, we learned it's critical to integrate and test everything as early on as possible. And after integration, it's very important that everyone incrementally works on the same trunk of source code and reintegrating and testing frequently. We learned that we could've started integration sooner rather than later, as a lot of known issues crept up as we started merging everything together into a single application. Usage of source control tools such as Github are extremely valuable for continuous integration (which we did). | ||
== Conclusion == | == Conclusion == | ||
− | + | This project offered valuable experience in working on a complex product comprising of various subsystems with multiple developers working together simultaneously. We had to constantly communicate with one another to discuss interfaces and how each one of our subsystems will talk to each other. | |
+ | |||
+ | It also allowed us to gain further appreciation for FreeRTOS, by allowing us to split up our project into logical subsystems instead of having to put everything into one huge while loop as would've been done otherwise if it weren't for the RTOS. We got an opportunity to leverage most of the things we learned in class such as semaphores, queues and interrupts. By working on this project we also got an opportunity to utilize all the hardware interfaces (I2C, UART, SPI, Analog in, etc.) available on a typical microcontroller. | ||
=== Project Video === | === Project Video === | ||
− | + | * [https://vimeo.com/168248987 Sunrise Lighting Demo Video Link] | |
=== Project Source Code === | === Project Source Code === |
Latest revision as of 04:20, 29 May 2016
Contents
Smart Alarm Clock for the Stubborn Sleeper
Abstract
This smart alarm clock encapsulates a variety of features that are intended to wake up a stubborn sleeper who cannot get up in the morning. As opposed to your average alarm clock, this alarm clock has the ability to wake up the user using dynamic lighting combined with customizable sounds. An external unit, which is placed beneath the mattress, has a bass shaker built in to vibrate the mattress to aid in helping the user get out of bed. The external mattress unit also has a flex sensor that can detect whether the user is in bed or not, and is used to turn off the alarm once the user gets out of bed.
Objectives & Introduction
The alarm is made up of two modules, one being the alarm clock unit and an external mattress unit which is placed underneath the user's mattress. The heart of the main alarm unit starts with the SJOneBoard (LPC1758) microcontroller. From there, we branch out to the following peripherals:
- Nordic wireless communication with the external mattress unit
- Four 8X8 blue LED matrix displays (HT16K33) with RAM mapping controller drivers interfaced over I2C
- Audio module (VS1053 Codec) with two 2W 8 OHM speakers interfaced using a Teensy Development Board which is communicating with the SJOneBoard over UART.
- RGB LED strips (144 LEDs/m) interfaced over SPI
- A capacitive snooze button interfaced over GPIO
The external mattress unit is driven by another SJOneBoard (LPC1758) microcontroller which drives the following peripherals:
- Nordic wireless communication with the main alarm unit
- Bass Shaker with a 50W amplifier interfaced over PWM
- Flex sensor interfaced using ADC
Show list of your objectives. This section includes the high level details of your project. You can write about the various sensors or peripherals you used to get your project completed.
Team Members & Responsibilities
- Sara Sepasian
- RGB LEDs
- Michael Jaradah
- Breakout board schematic capture and layout, RGB LEDs, Wireless Mesh Network, Shaker, Flex Sensor
- Rabeel Elahi
- 8X8 LED Matrix Displays, Alarm API integration with RTOS, Wireless Mesh Network, Flex Sensor
- Farhan Naeem
- Hardware architecture, board layout, software architecture, mechanical design and integration, audio module
Schedule
Week# | Date | Task | Status | Notes | |
---|---|---|---|---|---|
1 | 3/22 | Hardware architecture
|
Completed |
|
|
1 | 3/27 | Software architecture
|
Completed | ||
2 | 3/29 | Schematic capture, BOM & design review
|
Completed | ||
2 | 3/30 | Order components | Completed | ||
3 | 4/5 | Board layout & design review
|
Completed | ||
3 | 4/7 | Order PCB | Completed | ||
6 | 5/1 | Receive, assemble and test board | Completed | ||
6 | 5/1 | Software module development
|
Completed | ||
7 | 5/7 | Software integration
|
Completed | ||
8 | 5/15 | Debug and test | Completed |
Parts List & Cost
VS1053 Codec + MicroSD Breakout x1 (~$25)
8x8 matrix displays x4 (~$13)
Stereo 2.8W Class D Audio Amplifier x1 (~$10)
2W 8OHM OVL SHP SPKR x2 (~$6)
50W Amplifier x1 (~$15)
Bass shaker x1 (~$21)
Flex Sensor x1 (~$8)
PCB x1 ($40)
Custom Made Enclosure
Design & Implementation
Hardware Design
Hardware Architecture
Breakout Board Schematic
Breakout Board PCB
Our alarm clock contained many different components that needed to be wired together. In order to keep things packaged and wired efficiently, we decided to create a custom PCB that would fit directly on top of the SJOne board, and act as a breakout board.
To design our custom PCB board, we used Eagle version 7.5.0, which is a free tool available for download online. The application allows users to create their own PCB's for free up to a certain dimension, so we made sure to keep our board within the free space allowed. Before starting the PCB work, we made sure to download all additional libraries from outside sources such as Sparkfun and Adafruit, to avoid using hard-to-find components. Their libraries have been tested and used by many PCB's before, so we went ahead with theirs and avoided others.
The bulk of our breakout board was filled with headers, which allowed different devices such as: an amplifier, audio decoder, LED matrix displays, SPI LED strips, a Teensy Header, and the SJOne board. In addition to housing these components, the board contained a level shifter for the LED's. an RC filter designed for a transducer shaker, a power jack, a power supply for the SJOne board, a header for a capacitive switch, as well as a BLE pad and BLE Programmer header. In order to minimize noise, a power copper layer as well as a ground copper layer were added to the top and back of the board. This cleaned up the wiring a lot, since every component contained these wires.
After the schematic and board files were completed, we went with a US-based PCB fab company called OshPark. This company is known for their purple PCB's, being very reliable, and having quick turn around time. In addition to this, their website is very user friendly and designed to be for hobbyist. They do not require any gerber files, and generate every file they need by uploading the .sch and .brd files. From there, they automatically generate the files and go through the design checking process. In total, the PCB took 11 days from submission of payment to receiving the board.
Flex Sensor
The flex resistor was used in the project to detect whether a user was in the bed or not. Two flex resistors were tested and used, with one resistor being more accurate than the other, giving better values. The flex sensor was 4.5" in length. As the sensor is flexed, the resistance across the sensor increases. Using the ADC pins on the board, we were able to view the data of the resistor flex when somebody was in bed, and call a sender function to the alarm clock.
Transducer Mini Bass Shaker
The transducer bass shaker was used in the project to vibrate the user who was staying in bed even after their alarm had gone off. This puck was extremely powerful depending the vibration level that was desired. For our use case, we started making patterns such as SOS, Long Vibration, Short Vibration, Pulse, Heartbeat, and even a custom pattern function for the user to define their own. The patterns became more and more rigorous depending on the users snooze count.
The puck was interfaced through a slave SJOne board, which was separate from the alarm clock master device. In addition, we used a Pulse Width Modulation (PWM) to control the vibrations, as well as a voltage dividing circuit. For the wiring schematic, the bass shaker puck was wired to a 50W amplifier, which required a 12V source. A voltage dividing circuit was then added to the amplifier in order to step down the SJOne board's output voltage from 3.3V (actually around 2.6V, due to the PWM) to 500mV. The bass shaker was then brought down to a desired frequency level, and given a set duration to be left on and off.
Final Slave Unit
This was the final slave unit enclosure. The unit was installed into an ottoman, which was the closest thing to a bed as we could get without actually bringing a bed to the demo. However, the unit has been tested and implemented with a bed and works well. In the picture, you can see the amplifier, the bass shaker, the voltage dividing circuit, as well as the slave SJOne board running with the Mesh Network.
8X8 LED Matrix Displays
The 8x8 matrix displays with backpack drivers (HTK1633) were chosen primarily because of their ultra-bright pixels which shine through the black fabric mesh on the front of the alarm clock. These specific displays are interfaced over I2C, making the wiring less hectic since I2C uses only two wires (SDA and SCL). External pull-up resistors were not needed since the backpack drivers had them built in. Each display requires 5V at 1.5A which is sourced by the breakout board's +5V supply. The SJOneBoard (master) drives the addressable displays with SCL running at the specified frequency of 400 kHz.
Industrial Design
We collaborated with an industrial designer to design a custom mechanical package that houses all of the electrical components. Solidworks was utilized to model the entire assembly. The CAD model was then used to laser cut sheets of acrylic to construct the enclosure. The front bezel assembly was 3D printed to contain the LED displays and speakers. A fabric mesh was then used to cover up the displays and the speakers.
Hardware Assembly/Integration
Hardware Interface
Refer to the Hardware Architecture diagram above for an overview of the interfaces utilized.
Software Design
At the heart of the system is a task running the alarm clock state machine. The state machine code is executed whenever the alarm semaphore is given. The state machine is written to escalate the alarm level from one stage to another based on the users's action.
Implementation
State Machine
//alarm semaphore if (xSemaphoreTake(timeSem, portMAX_DELAY)){ //only activate alarm if it has been enabled by the user if(alarm_is_on) { switch(state){ case ALARM1: if(user_in_bed){ alarmObj.activateAlarmLevel1; state = ALARM2; } else{ state = ALARM1; } break; case ALARM2: if(user_in_bed){ alarmObj.activateAlarmLevel2; state = ALARM3; } else{ state = ALARM1; } break; case ALARM3: if(user_in_bed){ alarmObj.activateAlarmLevel3; state = ALARM4; } else{ state = ALARM1; } break; case ALARM4: if(user_in_bed){ alarmObj.activateAlarmLevel4; state = ALARM5; } else{ state = ALARM1; } break; case ALARM5: if(user_out_of_bed){ alarmObj.activateAlarmLevel5; state = ALARM1; //user is out of bed, reset to alarm1 for the next time } else{ state = ALARM5; //repeat alarm until user gets out of bed } break; } }
Matrix Display Class
The matrix class was created using the singleton template so that only one instance of the class could be used throughout the code structure. The class consisted of various helper functions that initialized, cleared, and wrote to the displays as seen below. The helper functions would fetch the instance of I2C1 and write to the display registers. Since the breakout board was connected to the SJOneBoard header pins, I2C1 had to be used versus I2C2 which is located under the two 7-segment displays. In order to do this, a separate class, which inherited I2C_base class, had to be created for I2C1.
/** * Get instance of I2C1 class and initialize I2C1 to 400 kHz */ I2C1& i2c = I2C1::getInstance(); i2c.init(400); /** * Get instance of matrix class */ matrix& matrix = matrix::getInstance(); /** * Initialize displays: * * matrix.init(display address, brightness, blink frequency) */ matrix.init(0xe2,0xEF,0x81); //Display 1 matrix.init(0xe0,0xEF,0x81); //Display 2 matrix.init(0xe8,0xEF,0x81); //Display 3 matrix.init(0xe4,0xEF,0x81); //Display 4 /** * Clears the displays */ matrix.clearDisplay(void); /** * Writes time to the displays and accounts for colon * * @param string time to be written to display */ matrix.setTime(char string[]); /** * Writes any four letter word/number to the display * * @param string string to be written to display */ matrix.writeDisplays(char string[]);
Audio Interface Class
The audio interface class provides the capability of initializing the UART communications interface with the Teensy module and playing an audio clip identified by an index value.
class audio : public SingletonTemplate<audio> { public: void initAudio(); void playAudio(unsigned char command); protected: friend class SingletonTemplate<audio>; private: Uart2& u2 = Uart2::getInstance(); };
Testing & Technical Challenges
We learned how challenging integrating hardware and software can be. There were many instances were we weren't sure whether an issue is being caused by hardware or software. At times we had pull out an oscilloscope to debug at the signal level to try to get to the root cause of an issue. Here are some of the challenges we ran into:
Difficulties interfacing with VS1053 audio module
Implemented driver as per manufacturer's recommendation. However we were unable to get it to work. Communications protocol was too complicated to fix/troubleshoot within planned time period. Resorted to using a Teensy board along with an audio module. A UART interface was implemented on the Teensy to read audio file selection sent from the SJ One board.
Clock frequency for RGB LEDs too high for MOSFET based level shifting circuit
The RGB LEDs initially selected for the project (WS2812) required a signal of 800kHz. The WS2812 requires 5V digital input, therefore requiring us to level shift the 3.3V output of the LPC microcontroller to 5V. The level shifting was implemented using a MOSFET based circuit with 3 pull-up resistors. The combination of the pullup resistors along with the internal capacitance of the MOSFET and the board capacitance resulted in the 800kHz signal being significantly attenuated. We ultimately resorted to switching to a different RGB LED strip which has less strict of a timing requirement as there's a separate clock signal in addition to the data signal. This allowed us to adjust the data rate by just setting the clock speed.
Software Integration
On projects such as this one with multiple developers working on multiple aspects of the system, we learned it's critical to integrate and test everything as early on as possible. And after integration, it's very important that everyone incrementally works on the same trunk of source code and reintegrating and testing frequently. We learned that we could've started integration sooner rather than later, as a lot of known issues crept up as we started merging everything together into a single application. Usage of source control tools such as Github are extremely valuable for continuous integration (which we did).
Conclusion
This project offered valuable experience in working on a complex product comprising of various subsystems with multiple developers working together simultaneously. We had to constantly communicate with one another to discuss interfaces and how each one of our subsystems will talk to each other.
It also allowed us to gain further appreciation for FreeRTOS, by allowing us to split up our project into logical subsystems instead of having to put everything into one huge while loop as would've been done otherwise if it weren't for the RTOS. We got an opportunity to leverage most of the things we learned in class such as semaphores, queues and interrupts. By working on this project we also got an opportunity to utilize all the hardware interfaces (I2C, UART, SPI, Analog in, etc.) available on a typical microcontroller.
Project Video
Project Source Code
References
Acknowledgement
Any acknowledgement that you may wish to provide can be included here.
References Used
List any references used in project.
Appendix
You can list the references you used.