Software apps and online servicesAdaCore GNAT CommunityAutodesk FusionAutodesk EAGLEAmazon Alexa Alexa Skills KitAmazon Web Services AWS IoT
Software apps and online servicesAdaCore GNAT CommunityAutodesk FusionAutodesk EAGLEAmazon Alexa Alexa Skills KitAmazon Web Services AWS IoT
My wife suffers from a rare condition that causes her to be nauseous for many hours quite often. Through trial and error, she has learned that one thing that seems to alleviate the symptoms is sitting upright and perfectly still. I noticed that often, early in the morning, she would slip out of bed and move to the couch where she can sit upright while I slept in bed.So, about a year ago, after too many nights of being uncomfortable with our bed, my wife and I decided to finally go bed shopping for a good mattress. In doing so we realized how common it is now that people purchase adjustable bases with their mattresses. It dawned on us that having an adjustable base would be excellent for her condition as she could sit up in bed whenever she needed and she wouldn’t have to go to the couch to do it. After trying one on a showroom floor we were excited to find that we loved it and we went out and bought one with our new mattress.At first, it was amazing; being able to prop yourself up in bed. But then there were problems. When my wife wanted to raise the bed, if I wasn’t there she’d have to fumble around for the remote (which always seemed to be hard to find). Often, if she wasn’t feeling well, she’d give up and acquiesce to laying supine. Another problem we had was that we tended to fall asleep with the bed in the upright position. This gets quite uncomfortable for the entire night and the effort needed to find the remote and adjust the bed would wake us from our sleep, making it hard to get back to sleep.One night, when faced with this problem it dawned on me: we already use our Alexa to control our lights and other devices, why not our bed? A quick Google search revealed that nothing like this had ever been done. To make it worse, adjustable beds are primitive affairs --- they don’t have APIs and they aren’t programmable. They rely on power control circuits to drive them.This seemed like the perfect type of project to take on. At the time, I had recently completed my Ph.D. in Computer Science where I focused on formal methods and new techniques for specification inference. From this experience I was already familiar with Ada and SPARK, which uses a specification language similar to my advisor’s own JML. Although I knew about Ada through this experience (The Building High Integrity Applications with SPARK book was one of the first I stole from my advisor’s office!) I hadn’t made anything “real” in Ada, so I thought I’d do this also as a way of understanding what the state of Ada/SPARK would be for a real product.
Project Goals and Overview The goals of this project were to create an IoT device that was:Able to control the movement of a wired adjustable bed.Able to be easily reconfigured to work with other wired adjustable beds.Able to be controlled by both an Amazon Alexa device as well as the original remote.Able to sense occupancy in the room and able to produce under bed safety lighting when walking around at night.Written in Ada/SPARK 2012.Nicely designed in terms of fit and finish (since I planned on actually using it!). That means that the entire system should use its own custom PCBs and be hosted inside of a custom-designed case that would look great under my bed.To explain the product, I’ve prepared two videos that demonstrate the main features of the SmartBase as well as showcase its physical construction.My wife was more than happy to demo the SmartBase for the purposes of this contest. Example of the startup sequence for bed and having the safety lighting activated.For the interested reader, you can read the remainder of this document to learn all about the different phases of development for this project. Roughly, the phases of development this project followed were:1. Reverse engineering, in which I figure out how to control the bed. 2. Prototyping, in which I made some rough perf-board prototypes. 3. PCB design, because no one wants a rats nest of wires under their bed, I designed a series of PCBs to support the function of the SmartBase. 4. Enclosure Design, in which I designed a case for my project. 5. Software Design, which essentially happened at all phases, but I’ve given it its own section here. 6. Verifying Things, in which I do a little bit of verification. And of course, at this point having the thing fully working (with a case!) I decided it would be fun to run it on bare metal. So then:7. Moving to STM32, in which I describe porting the entire project over to a STM32F429ZIT6 and a ESP32 for the WIFI functionality. 8. Bitbanging a WS2812B on a STM32F4 in Ada. Neopixels are only easy to use if you are using an Arduino. Apparently no one had done this one before, so, armed with an oscilloscope and a ARM manual, I figured out how to make that happen. 9. Wrapup, What did I think about using Ada to build the SmartBase? For the complete code of the SmartBase running on the RPIZeroW, please visit: https://github.com/jsinglet/smartbaseFor the complete code of the STM32 version of the SmartBase please see this repository: https://github.com/jsinglet/smartbase-stm -- This repo is essentially a fork of the above repository which targets the STM32. I've published them separately so it's easy to understand which repository represents which product. However, before we jump into all that, here are some pictures of the finished project in action. I hope you enjoy reading about it as much as I enjoyed making it!1 / 11 • The SmartBase. Phase 1: Reverse Engineering The first problem I had to solve was: how do I control the adjustable base? As I’ve mentioned, I’m a software guy, but I’m dangerous with a multimeter. To figure this out, I simply started by sliding under my bed and looking at how it currently functioned.The configuration of my bed was that of a wired remote, connected with a DIN5-style (big round connector commonly found in MIDI applications). Again, being a software guy, I assumed that perhaps the way the people who built the bed constructed it was to perhaps to implement some sort of protocol over serial. I connected it to my computer, fired up WireShark, but alas, nothing sensible came out of the remote.So of course, my next step was to disassemble the remote. The wired remote, horrifically disassembled, is pictured below.This remote has seen better days. Don't mind the packet of taco seasoning off to the left. After some experimentation with a multimeter I was able to determine that the circuit was quite simple. Here’s a picture of a whiteboard from around the time I was figuring it all out:A whiteboard of me reverse engineering the circuit. The logic for the circuit is actually quite simple. One of the 5 pins functions as the power, which happens to be +30V. The other pins are connected to the power via a switch and fed back into the bed. I tested the idea by taking hookup wire and touching it across the various pins in the configuration I had determined through my schematic analysis and sure enough it worked. With this information, I was ready to construct a rough physical prototype.Phase 2: The Super Rough Prototype So after learning the basics of how the control circuit worked, I wanted to test if this could be controlled via relays so after a few trips to my local electronics hacking store SkyCraft (a really one of a kind place!) and some Amazon purchases I managed to put together a rough perfboard prototype, which sadly I didn’t take a picture of when it was all together – however, I saved the board, which is pictured connected to a off the shelf relay module, below: Perfboard prototype which didn't do much other that validate that the control circuit worked. Phase 3: Moving from Perfboard to PCB One of my goals for this project was to have a tidy little box I could stick under my bed that my wife would tolerate. The early perfboard prototype sat on top of some roughly cut tile with a lot of duct tape. I don't have a picture, but it was a great sight. Horrifying, but a good sight.If I was going to have a permanent fixture, I had to fix the ratsnest problem, starting with the circuit. For this, I decided to start by designing my own custom PCB to control the bed. The topic of how many wrong turns and iterations of the PCB I did could frankly fill many pages. To shorten that, I'll just present my finished schematics, below. Before that, however, let me just say that I used JLCPCB to do all my fabrication, including SMT part placement. I can't say enough good things about this company. They are fast, cost effective, and the boards are flawless. For my PCB layout I used Autodesk Eagle, which was great as well. To gain a better understanding of the hardware required to run the SmartBase, I've prepared the following Block Definition Diagram which details the main systems the SmartBase relies on to provide its functionality.Block Definition Diagram detailing main components of the SmartBase. At the top level we have the Relay and Power Control Module and the LED Mainboard Module. These two components roughly outline the two boards that were created for this project. In the following paragraphs we discuss each board separately.First, let's look at the board on the bottom, which was responsible for power and hosting the relays on the board that control the bed.This schematic shows the daughter board, which is responsible for power and control. Layout for the bottom board. Power is routed in through this board on the bottom through a barrel connector to all of the components within the SmartBase. Other components hosted on this board are:The PIR Motion Sensors, via Amazon5V DC Relays, via Digi-KeyLogic Level MOSFET transistors, via Digi-Key2 DIN 5 Connectors, via Digi-KeyA 40 pin GPIO Header, via Digi-KeyVarious LEDs, diodes, and resistors that I sourced at SkyCraft. In order to control the relays (safely) with GPIO signals I used a series of FQP30N06L "logic level" MOSFET transistors connected as shown in the above schematic. One cool thing I did was make the configuration of the relays jumpered, so if I ever encountered a different bed with a different control configuration they relays can be easily rerouted. The basic idea is that the jumper positions control which pin gets the power signal when the relay is activated.Next, this is the top board, which hosts the WS2812B LED array as well as the CPU, which is a Raspberry Pi Zero W. The schematic and the layout file for the board is pictured, below:The LED array and host connectors for the two boards. I have a hard time believing I got this right on the first shot! This board hosts two 40 connectors which host both the GPIO cable connector from the bottom board and the header for the Raspberry Pi itself. If you can believe it, I got this board right on the first try just by following manufacturer spec sheets.Phase 4: Enclosure Design Printing the top of the SmartBase.To build the enclosure I opted for a very simple design, which features several components:Two DIN-5 ports on the back. One connects to the bed and the other allows you to reconnect the remote control to the bed if you wish to ever manually control the bed. In reality I never used this feature because the voice control was so good.One power connector for 5VDC power.The case actually splits into 3 different bodies. The bottom body, the top body, and the "lens" which I printed out of clear PETG. The rest of the case was printed in black PLA.Eagle CAD model of the bottom of the case. Back of the SmartBase. View of the top part of the case from the bottom view. The LED array is pictured. One challenging aspect of this case design was actually coming up with appropriate screw sizes. I ended up using a combination of M2 and M3 screws. I found a bunch of assorted hex head sizes on amazon and was able to design the case dimensions around those.Phase 5: Software Design In this section we will discuss the design of the Ada software that runs the SmartBase. The software described in this section is the software that drives the version of the SmartBase shown in the demo. Later in the section on STM32 we discuss how these components are handled on a STM32F4-family processor in Ada. However, before we start, a few notes:SmartBase makes use of tasking. It is in fact mainly composed of 5 core tasks that handle relay control, command interfacing, MQTT command processing, and LED status control.Because I wanted to be able to verify things (and the run it on metal later), I enabled the Ravenscar profile.Portions of the application are written in Spark. Notably the components that control the bed are written in Spark with some lightweight specifications around the control sequences.Concept of OperationThe SmartBase gets inputs from PIR sensors which will trigger fade on / fade off events. These events are able to be processed along with MQTT events which arrive via a AWS Lambda function connected to the Alexa voice service. These MQTT events then turn into motion of the bed via the relay control subsystem. The following diagram provides a high level summary of how the Smartbase performs its main operations.SmartBase HLA detailing the main high level software components developed. TaskingThe typical way one builds microcontroller applications is via a state machine pattern encoded into the main loop of the program running on the microcontroller.For simple applications this is generally fine but for more complex applications it is common to use the multi-tasking capabilities found in an RTOS such as FreeRTOS. That said, one of the excellent aspects of programming a system like the SmartBase in Ada is Ada's excellent (and I mean excellent) tasking facilities that are built right into the language. Because of this, I opted to use Ada's tasking features to structure my application. If you'd like to learn more about this capability, I suggest you take a look at Fabien's article over on the AdaCore blog, here: There's a mini-RTOS in my language.The SmartBase uses 5 tasks for performing its core operations:1. The Bed Task, which is responsible for controlling access to the relay control system. 2. The CLI Task, which provides a debugging command-line based interface to the SmartBase. 3. The MQTT Task, which listens for protocol events from Amazon IoT (from spoken voice commands) and talks to the bed task to execute protocol events. 4. The LED Task, which is responsible for providing a structured interface to controlling the LED ring. The LED ring defines states for connecting, connected, fading on, and fading off. 5. The Motion Detector Task, which is really comprised of several tasks and is easily the most complex of the 5. I describe the Motion Detector tasks more detail later in this section. The following diagram details the relationship of these five tasks in more detail. Note that in the diagram I use the method loop to indicate the main loop of the task. One stipulation of Ravenscar is that tasks do not exit and notation calls that restriction out.Overview of the main tasking components used in SmartBase. The design of the system is that all interaction with the LED and Bed components happens strictly through the Commands interface with the exception of the Motion Detector tasks. This interface itself in turn only acts with protected objects. For example, if a command arrives via the command line and the MQTT task at the same time (assuming we have more than one CPU) they will both attempt to process the command through the Commands interface which in turn will ensure the access to the resources is serialized.One interesting task is the LED_Status_Task, which is responsible for processing changes to the LED status ring. There are two problems solved in this component: 1) How to provided serialized access to the underling LED hardware and 2) How to ensure that transitions to different LED states are valid? The first problem is solved through protected objects. The second part of the program is covered in more detail in the next section on verification. Lastly, the most complicated use of tasking is easily in the way the SmartBase does motion detection. As can be seen in the above figure, the MotionDetector package is composed of two Tasks and two protected objects. They function in the following fashion: Interrupts arrive on the protected object Detector, which very quickly sets an interrupt flag. The Motion_Detector_Trigger_Task monitors this flag by waiting on the entry to Triggered_Entry. Once the barrier releases, the Motion_Detector_Trigger_Task engages the Timer_Task via the MotionDetector_Control object's Start method. The Timer_Task is then responsible for changing the status of the LED ring to OFF once the detection is finished. Retriggering is handled at the level of the Motion_Detector_Trigger_Task. If the LED hasn't already faded off, more time is simply added to the timeout. That way, if people keep moving the lights remain on. Other Software DetailsSome other items worth mentioning pertaining to the Pi Zero version of this implementation are the following:For MQTT I wrote C bindings to the Eclipse Paho library. On the STM32 platform, I use the MQTT AT interface directly built into the ESP32 and program it over UART. For LED Control on the Pi I used a neopixel library and bound to it in C. On STM32 there is no such type of library for Ada (or anything else, really) so I wrote my own hand-coded bit-banged version of a WS2812B control library. What is nice about my implementation is that it is optimized for my particular use case and uses constant RAM (whereas other implementations use RAM on the order of the number of pixels in the array). You can read about it in the section on STM32. I did all my work in GPS, but I would really like to get my hands on the Eclipse version of the GNAT tool set and would happily accept any complimentary licenses!Phase 6: Verifying Things One of my goals was to check out the specification-related features of Ada with this project. To that end, I came up with two small verification tasks for my project.1. First, rather than use a timer, part of the way that the bed is controlled is through the use of tasks and protected bodies. These tasks use a barrier to control when a task should start waiting to see if it should stop moving the bed. One aspect of this protocol is that since other commands may be received while the bed is moving (thus, nullifying the current action), the tasks controlling the timeout have to know that they have been cancelled without having race conditions around the starting and stopping of the bed. I will show a little bit of what I did in the protocol with relation to specification.2. Second, a critical element of this application is the LED status ring. In this application the LED status ring is used for indicating when the SmartBase is connecting to the internet, disconnected, and when motion is detected. Designing a system that can process all of these states at any time is trickier than it sounds and I discuss the model I used for managing the LED status ring.Specifications on the Bed ControllerThe first thing I wanted to write some specifications for were the behaviors surrounding the behavior of the stopping and starting of the bed. As I described earlier. To do this I wrote the following specifications, which I will explain after the listing.procedure Do_Stop_At(Relay Control Daughter BoardThis is the bottom board of the SmartBase that accepts power and provides access to relays and the connection bus to the top motherboard and LED array.