{"id":108,"date":"2013-02-17T19:54:47","date_gmt":"2013-02-18T02:54:47","guid":{"rendered":"http:\/\/www.mjblythe.com\/hacks\/?p=108"},"modified":"2021-12-22T00:01:01","modified_gmt":"2021-12-22T07:01:01","slug":"valentines-day-puzzle-box","status":"publish","type":"post","link":"http:\/\/www.mjblythe.com\/hacks\/2013\/02\/valentines-day-puzzle-box\/","title":{"rendered":"Valentine&#8217;s day puzzle box"},"content":{"rendered":"<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170864.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft  wp-image-164\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170864-1024x768.jpg\" width=\"570\" height=\"427\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170864-1024x768.jpg 1024w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170864-300x225.jpg 300w\" sizes=\"auto, (max-width: 570px) 100vw, 570px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-large wp-image-165\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-768x1024.jpg\" width=\"570\" height=\"760\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-768x1024.jpg 768w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-225x300.jpg 225w\" sizes=\"auto, (max-width: 570px) 100vw, 570px\" \/><\/a><\/p>\n<p><strong>***UPDATE***<\/strong> I&#8217;m going to make some updates to the code, so I&#8217;ve modified all the github links below to point to a tagged version.  For the latest-and-greatest code, look <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/tree\/puzzle_box\">here<\/a>.<\/p>\n<p>After I saw <a href=\"http:\/\/hackaday.com\/2012\/11\/29\/hackaday-links-november-29th-2012\/\">this post on hackaday.com<\/a> about ST Microelectronics giving away STM32F3 Discovery boards for free, I knew I had to have one, but I didn&#8217;t really have a specific project in mind for a while.\u00a0 Then, one day I remembered a <a href=\"http:\/\/arduiniana.org\/projects\/the-reverse-geo-cache-puzzle\/\">reverse geocache box<\/a> that was also <a href=\"http:\/\/hackaday.com\/2009\/10\/19\/reverse-geocache-puzzle\/\">featured on hackaday<\/a>, and realized that I could do something similar.\u00a0 The F3 Discover board includes a 3-axis accelerometer &amp; 3-axis gyroscope, so instead of using GPS, I would only have the box open when it was rotated through the correct sequence of orientations.<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/aLWbtpQS66U?rel=0\" height=\"360\" width=\"640\" allowfullscreen=\"\" frameborder=\"0\"><\/iframe><\/p>\n<p>For those who don&#8217;t want to read the whole post below, the code is posted on <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/tree\/puzzle_box_1.0\">my github repository<\/a>.\u00a0 Also, those looking for photos should skip to the last half of the post.<\/p>\n<p>Since I had ordered the free sample in late November, I figured that I&#8217;d have enough time to make this puzzle box as a Christmas gift for my wife.\u00a0 Unfortunately, it didn&#8217;t arrive until the day that we celebrated our early Christmas (before we travelled to see our families). Not quite enough time to throw it together&#8230;\u00a0 Fortunately, that just meant that I had more time to put something together by the next gift-giving opportunity&#8230;St. Valentine&#8217;s day.<\/p>\n<p><!--more--><\/p>\n<h2>Materials<\/h2>\n<ul>\n<li>Pre-assembled box<\/li>\n<li>Servo motor<\/li>\n<li>Piezoelectric speaker<\/li>\n<li><a href=\"http:\/\/www.adafruit.com\/products\/777\">Red, diffused 3mm LEDs<\/a><\/li>\n<li><a href=\"http:\/\/www.adafruit.com\/products\/266\">Female\/Female jumper wires<\/a> (I also got some <a href=\"http:\/\/www.adafruit.com\/products\/400\">male headers<\/a> for versatility)<\/li>\n<li><a href=\"http:\/\/www.adafruit.com\/products\/830\">Battery holder<\/a><\/li>\n<li>On\/Off Switch<\/li>\n<li>Micro-switch<\/li>\n<li>Misc (scrap wood, steel wire, glue, etc.)<\/li>\n<\/ul>\n<p style=\"text-align: left;\">The box I got was from Michael&#8217;s, similar to <a href=\"http:\/\/www.michaels.com\/ArtMinds%E2%84%A2-Medium-Unfinished-Hinged-Box\/gc2162,default,pd.html?cgid=products-generalcrafts-craftingsurfaces&amp;start=13\">this one<\/a>, except that the cover had a rectangular cut-out with a wire mesh in it that I removed.\u00a0 I also bought some unfinished birch plywood to cover the cut-out.\u00a0 In the end, I think having this cut-out made it much easier to get the locking mechanism working, so I&#8217;d recommend it.<\/p>\n<p style=\"text-align: left;\">The servo doesn&#8217;t have to be anything special&#8230;I just went to my local hobby store and asked for the cheapest one they sold.<\/p>\n<p style=\"text-align: left;\">Likewise, the piezo speaker isn&#8217;t anything special either.\u00a0 I happened to have a spare that used to be a &#8220;PC speaker&#8221;, and it worked well because it was already connected to a 0.1-inch female header.<\/p>\n<p style=\"text-align: left;\">The On-Off switch that I used was one that I already had from Radio Shack or something.\u00a0 It was a 2-pole 2-throw switch, which was overkill, but it worked fine.<\/p>\n<p style=\"text-align: left;\">I used a micro-switch from a junked HP printer to sense when the box is open or closed.\u00a0 It also had a 0.1-inch female header, which was convenient.<\/p>\n<h2 style=\"text-align: left;\">Servo<\/h2>\n<p style=\"text-align: left;\">I figured the easiest way to latch the box would be to have a servo motor drive some sort of a sliding mechanism, so my first step was to get the servo working with the Discovery board.\u00a0 I hadn&#8217;t used a servo on a project in a long time, so I had to look up how to control it.\u00a0 Fortunately, wikipedia has an article on <a href=\"http:\/\/en.wikipedia.org\/wiki\/Servo_control\">servo control<\/a>, with this helpful graphic:<\/p>\n<p style=\"text-align: left;\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone\" alt=\"\" src=\"http:\/\/upload.wikimedia.org\/wikipedia\/commons\/7\/7b\/ServoPwm.png\" width=\"345\" height=\"70\" \/><\/p>\n<p style=\"text-align: left;\">In order to achieve this, I decided to use some easy math.\u00a0 I set up a Timer 3 to do <a href=\"http:\/\/en.wikipedia.org\/wiki\/Pulse-width_modulation\">PWM<\/a> and to have a clock divider of 72 (with a 72MHz clock, each timer increment would be 1 \u03bcs), a period of 20,000 counts (20 ms), and then controlled the pulse width by setting a compare register to a value between 1000 (1 ms) and 2000 (2 ms).\u00a0 I found, however, that the rotation difference between a\u00a0 1ms and 2 ms pulse was only about 90 degrees.\u00a0 In order to get about 180 degrees of rotation, I needed 0.55 ms and 2.3 ms pulses.<\/p>\n<p style=\"text-align: left;\">My servo control code is <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/src\/servo.c\">here<\/a>.<\/p>\n<p style=\"text-align: left;\">I had considered trying to get as much accuracy as possible from the servo by finding the lowest clock divider that wouldn&#8217;t overflow the 16-bit timer in 20 ms, but the extra accuracy was unnecessary.\u00a0 Also, when I tried to figure out that math, it was too late at night for me to make sense of it.<\/p>\n<p style=\"text-align: left;\">I thought it might be an issue that the servo was powered by 5V, but the signalling from the STM32F3 was only 3V.\u00a0 This turned out to be fine.\u00a0 I was also worried about powering the servo, but my USB hub provided enough power to the servo during the prototype &amp; debugging phase before I moved over to using a battery pack.<\/p>\n<h2 style=\"text-align: left;\">Buzzer<\/h2>\n<p style=\"text-align: left;\">I figured an audible beep would be a good way to provide feedback to the puzzle-solver about whether they had made a correct move.\u00a0 This feedback would have to indicate both good and bad moves, however, so I decided to use different frequencies.\u00a0 I settled on having a &#8220;bad&#8221; beep be 200 Hz, and a &#8220;good&#8221; beep be 800 Hz.\u00a0 Similar to the servo, I used a timer in <a href=\"http:\/\/en.wikipedia.org\/wiki\/Pulse-width_modulation\">PWM<\/a> mode to generate these tones.\u00a0 For my own sanity, I used the same clock divider of 72, and set the period and compare register to 1250 &amp; 625 for a &#8220;good&#8221; beep, and 5000 and 2500 for a &#8220;bad&#8221; beep.<\/p>\n<p style=\"text-align: left;\">I also wanted the beep to only persist for a short time.\u00a0 In order to do this, I used the <code>SysTick<\/code> timer, set up to generate an interrupt every 10 ms.\u00a0 Whenever I wanted a beep, I enabled the PWM timer, and set a counter to 25.\u00a0 Every 10 ms, the <code>SysTick<\/code> handler would decrement this counter, and when it reached 0, it would disable the timer again.\u00a0 This would result in a beep of about 250 ms (i.e. 1\/4 second).\u00a0 Of course, when I later coded up the puzzle game itself, a &#8220;bad&#8221; beep would be triggered as long as the box was in the wrong position, so a &#8220;bad&#8221; beep could be much longer than 250 ms.<\/p>\n<p style=\"text-align: left;\">The buzzer control code is <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/src\/beep.c\">here<\/a>.<\/p>\n<p style=\"text-align: left;\">When I was developing things, I thought the beeper sounded plenty loud, but I found that the sound was much quieter than I expected once the buzzer was in the box.\u00a0 I haven&#8217;t addressed this yet, but I&#8217;d first try to make the buzzer louder by having it connected to complimentary outputs from the timer.\u00a0 This way, the buzzer would have a 6 V peak-to-peak signal, instead of 3 V peak-to-peak.\u00a0 Failing that, I could drill some holes in one side of the box&#8230;essentially a simple speaker grille.<\/p>\n<h2>LEDs<\/h2>\n<p>I also wanted a way for the puzzle solver to get back to the previous point of failure quickly, and LED indications fit this nicely.\u00a0 For early development, I just used the 8 LEDs on the Discovery board itself.\u00a0 After I had made the box&#8217;s cover with the LEDs arranged in a heart, I modified the code from ST to control those pins instead.<\/p>\n<p>I had originally planned on using 6 different indications:<\/p>\n<ul>\n<li>Blink the top half of the heart (or circle, while developing)<\/li>\n<li>Blink the bottom half<\/li>\n<li>Blink the left side<\/li>\n<li>Blink the right side<\/li>\n<li>Sequence the LEDs in a clockwise rotation<\/li>\n<li>Sequence the LEDs in a counter-clockwise rotation<\/li>\n<\/ul>\n<p>I quickly determined that this would lead to ambiguous indications.\u00a0 Would blinking half mean that side should be up? down? a rotation in that direction?\u00a0 After consulting with a co-worker (thanks, Logan!), I settled on these indications:<\/p>\n<ul>\n<li>Sequence LEDs from top-to-bottom<\/li>\n<li>Sequence LEDs from bottom-to-top<\/li>\n<li>Sequence LEDs from left-to-right<\/li>\n<li>Sequence LEDs from right-to-left<\/li>\n<li>Sequence LEDs clockwise<\/li>\n<li>Sequence LEDs counter-clockwise<\/li>\n<\/ul>\n<p>Here&#8217;s what each of those looks like:<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/LED_indications_sm.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-172\" alt=\"LED_indications_sm\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/LED_indications_sm.gif\" width=\"570\" height=\"428\" \/><\/a><\/p>\n<p>Like the beep length, it didn&#8217;t make sense to handle this LED sequencing in the main program loop, so it is also handled during the <code>SysTick<\/code> interrupt.\u00a0 The code that controls the LEDs is <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/src\/led.c\">here<\/a>.<\/p>\n<h2>Selecting Difficulty &amp; Gyroscope<\/h2>\n<p>I had decided fairly early that I wanted to implement different difficulty levels, mostly by changing what feedback was given to the puzzle-solver.\u00a0 I decided on the following levels:<\/p>\n<ul>\n<li>Easy &#8211; audible feedback &amp; the LEDs would always indicate the direction the box needed to be turned<\/li>\n<li>Medium &#8211; audible feedback, but the LEDs would only indicate directions to get you back to your point of furthest progress<\/li>\n<li>Hard &#8211; audible feedback only, no LEDs at all<\/li>\n<li>Impossible &#8211; no audible or LED feedback.\u00a0 If the puzzle is successfully completed, the box still opens, but when a mistake is made, nothing happens.<\/li>\n<\/ul>\n<p>I considered adding a button to select difficulty, but then it dawned on me that I could just use the on-board gyroscope to have the puzzle-solver literally dial in their difficulty by rotating the box around the vertical axis.\u00a0 If the box is turned 1\/8 turn, the very bottom of the heart lights up, and <em>easy<\/em> is selected.\u00a0 1\/4 turn lights up the bottom half of the heart and <em>medium<\/em> is selected. 3\/8 turn light up more, and <em>hard<\/em> is selected.\u00a0 At 1\/2 turn, the heart is fully illuminated, and <em>impossible<\/em> difficulty is selected.\u00a0 Once the box is rotated back to the original position (that is, back 1\/8, 1\/4, 3\/8, or 1\/2 turn), then the puzzle starts in earnest.\u00a0 Here are the various illumination levels for the difficulties:<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/diff_indications_sm.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-171\" alt=\"diff_indications_sm\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/diff_indications_sm.gif\" width=\"570\" height=\"427\" \/><\/a><\/p>\n<p>Implementing the gyroscope code was fairly straightforward, given the example code from the Discover board firmware download.\u00a0 The one problem that I had to solve was that the gyroscope would output values as a rotational velocity in degrees per second, but I wanted the rotational position.\u00a0 In order to perform the integration necessary to get position from velocity, I just had the <code>SysTick<\/code> interrupt handler estimate the positional difference from the last interrupt call.\u00a0 I assumed that the velocity (returned by <code>GyroReadAngRate()<\/code>) was constant in the interval between <code>SysTick<\/code> calls (10ms), so angular position would increase or decrease by <code>.01 * degPerSec<\/code>.\u00a0 I could have gotten much more sophisticated (and hopefully accurate), but this worked well enough.<\/p>\n<p>The code for reading data &amp; integrating position from the gyroscope is <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/src\/gyro.c\">here<\/a>.<\/p>\n<h2>Puzzle program<\/h2>\n<p>At this point, most of the individual pieces were working, so I started coding up the puzzle implementation itself.<\/p>\n<p>The <code>main()<\/code> function has the program loop, which essentially implements a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\">finite-state machine<\/a>.\u00a0 When we&#8217;re in the <code>STATE_PUZZLE<\/code> state, we call <code>DoPuzzle()<\/code> which reads the accelerometers.\u00a0 If the acceleration is 6 times greater in one direction ( which corresponds to being within <a href=\"https:\/\/www.google.com\/search?q=arctan%281\/6%29+in+degrees\">about 10 degrees<\/a> of vertical), then it calls <code>HandleNewDir(direction)<\/code>, which is where the interesting things actually happen.<\/p>\n<p>In the simplest version of <code>HandleNewDir(direction)<\/code>, we compare the direction passed in with what we know is supposed to be the next direction in the sequence.\u00a0 The sequence is stored in <code>DirList<\/code>, and <code>DirPos<\/code> indexes into this list to keep track of our progress.\u00a0 If the 2 compare correctly, then <code>DirPos<\/code> is incremented, and we trigger a &#8220;good&#8221; beep.\u00a0 If the 2 directions miscompare, then we reset <code>DirPos<\/code> to 0 and trigger a &#8220;bad&#8221; beep.\u00a0 The other case we have to handle is when the puzzle solver holds the box in place after hitting the next direction in the sequence.\u00a0 This is tracked by <code>LastDir<\/code>, and when the new direction is equal to <code>LastDir<\/code>, we do nothing.<\/p>\n<p>As I added features to the puzzle box, <code>HandleNewDir(direction)<\/code> gets more complex with<\/p>\n<ul>\n<li>Tracking the furthest progress<\/li>\n<li>Conditionally emitting beeps based on the difficulty setting<\/li>\n<li>Conditionally setting the LED indication based on progress &amp; difficulty<\/li>\n<\/ul>\n<p>Of course, aside from actually doing the puzzle, we have to determine if the box is already open, and if not, then let the puzzle-solver select their difficulty (handled by the <code>DoGyro()<\/code> function), and we have to know what to do when the puzzle has been won.\u00a0 This is the reason for the rest of the finite-state machine in <code>main()<\/code>.<\/p>\n<p>All of this code can be found <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/src\/main.c\">here<\/a>.<\/p>\n<h2>Physical Construction<\/h2>\n<p>Even though navigating the register maps of the STM32F3 to set up all of the previous functionality was unfamiliar territory, it didn&#8217;t cause me the same anxiety as figuring out how to pack &amp; secure everything inside the box.\u00a0 I&#8217;m an Electrical &amp; Computer Engineer after all, not a Mechanical Engineer.\u00a0 You can see from the photo below how I fit everything in (and left room for some real Valentine&#8217;s day gifts, too!), but I&#8217;ll call attention to a couple of things I struggled with.<a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100836.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-149 alignright\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100836-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100836-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100836-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100854.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-154 alignleft\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100854-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100854-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100854-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100851.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-153 alignright\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100851-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100851-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100851-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<h3><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100831.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-148 alignleft\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100831-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100831-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100831-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/h3>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170868.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft  wp-image-166\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170868-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170868-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170868-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a> <a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-165 alignnone\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-225x300.jpg\" width=\"225\" height=\"300\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-225x300.jpg 225w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2170867-768x1024.jpg 768w\" sizes=\"auto, (max-width: 225px) 100vw, 225px\" \/><\/a><\/p>\n<h3>LED heart<\/h3>\n<p>I didn&#8217;t <em>struggle<\/em> with this so much, but I thought I had a clever solution to making the heart turn out well.\u00a0 First, I found a nice <a href=\"http:\/\/en.wikipedia.org\/wiki\/SVG\">SVG<\/a> image of a heart, then I used <a href=\"http:\/\/inkscape.org\/\">Inkscape<\/a> to place 24 dots evenly around the path of the heart.\u00a0 Next, I put this image into <a href=\"http:\/\/www.scribus.net\/\">Scribus<\/a> &amp; resized it to 3 different heights that were close to the dimension I was looking for.\u00a0 (All of these files appear <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/graphics\/Heart.svg\">here<\/a>, <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/graphics\/Heart_with_dots.svg\">here<\/a>, and <a href=\"https:\/\/github.com\/mblythe86\/stm32f3-discovery-basic-template\/blob\/puzzle_box_1.0\/graphics\/sized%20hearts.sla\">here<\/a>.)\u00a0 After I printed this and determined which height would work best, I transferred the dots to the plywood by hammering each one with a nail a little bit to leave a dent.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090817.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-143 alignnone\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090817-300x225.jpg\" width=\"300\" height=\"225\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090817-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090817-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once all the points for LEDs were marked, I drilled the holes for the LEDs.\u00a0 In order to make a clean cut, I drilled &#8220;good side&#8221; down, and clamped it to another piece of wood, which I also drilled into.\u00a0 I first tried drilling a 7\/64 inch (2.78 mm) hole, expecting that it would be just a little snug on the 3 mm LEDs, but it was too small to get the LED in at all.\u00a0 I had to use a 1\/8 inch (3.18 mm) drill bit instead.\u00a0 the LEDs fit fine, but they weren&#8217;t very snug at all.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090818.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-144 alignnone\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090818-300x225.jpg\" width=\"300\" height=\"225\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090818-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090818-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>I tried using wood glue to hold them in place, but found that wood glue didn&#8217;t adhere to the plastic cap of the LED very well at all.\u00a0 I ended up basically covering the entire back side of each LED with the glue to hold it in place.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090827.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-146 alignright\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090827-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090827-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090827-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a> <a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090823.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft  wp-image-145\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090823-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090823-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090823-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090829.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-147 alignnone\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090829-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090829-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2090829-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<p>Once the glue dried, things were held in place pretty well.\u00a0 Soldering everything together was pretty straightforward from that point.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100861.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-156 alignright\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100861-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100861-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100861-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a> <a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100859.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft  wp-image-155\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100859-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100859-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100859-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<h3>Latching mechanism<\/h3>\n<p>In my first revision, I had simply drilled a hole through a piece of wood for a steel wire to go through.\u00a0 The servo pushed this wire, and it would hook through an eye hook on the lid.\u00a0 In order for the lid to securely latch, this wire had to be near the bottom of the hook.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100843.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-152 alignright\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100843-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100843-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100843-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a> <a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100839.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft  wp-image-150\" alt=\"OLYMPUS DIGITAL CAMERA\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100839-300x225.jpg\" width=\"270\" height=\"203\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100839-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/P2100839-1024x768.jpg 1024w\" sizes=\"auto, (max-width: 270px) 100vw, 270px\" \/><\/a><\/p>\n<p>However, if the wire was too far down, it would hit the hook instead of going through.\u00a0 In this case, the servo would just bend the wire, and it wouldn&#8217;t work until I straightened things again by hand.\u00a0 I tried bending the tip of the wire upwards slightly, but 2 things prevented this from being very effective.\u00a0 First, I couldn&#8217;t bend the wire very much since it still had to slide back into the hole drilled into the wooden block, and there was only about 0.05 inches of leeway.\u00a0 Second, the wire was free to rotate in the block of wood, so if the tip was bent &#8220;up&#8221;, it might flop over to one side or the other on the next movement.\u00a0 This video shows the function and failure of that first design:<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/SLVfsJanlwQ?rel=0\" height=\"360\" width=\"640\" allowfullscreen=\"\" frameborder=\"0\"><\/iframe><\/p>\n<p>I solved this by cutting a slit in the block of wood instead of simply a hole.\u00a0 This way, I could bend the latching wire in such a way that it couldn&#8217;t rotate in the hole, and and &#8220;upwards&#8221; bend would remain upwards.\u00a0 Also, this allowed me to bend the tip upwards much more since I only had to fit back into a slit, and not into a hole.\u00a0 This new design worked much better:<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/new_latch.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-135 alignnone\" alt=\"new_latch\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/new_latch-597x1024.jpg\" width=\"478\" height=\"819\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/new_latch-597x1024.jpg 597w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/new_latch.jpg 2035w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><\/a><\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/iQVOohQqHM4?rel=0\" height=\"360\" width=\"640\" allowfullscreen=\"\" frameborder=\"0\"><\/iframe><\/p>\n<h3>Attaching the cover<\/h3>\n<p>I had originally planned to glue the plywood with the LEDs to the lid of the box, but after the trouble I had with the latching mechanism, I didn&#8217;t want to do anything so permanent.\u00a0 I decided to glue little blocks of wood onto the plywood that fit snugly against the 4 corners of the opening in the lid.\u00a0 Before gluing them, I had drilled holes in each block so that I could insert some retaining clips I bent out of steel wire to hold the plywood cover in place.\u00a0 Now, if something gets messed up, I can remove the retaining clips on the cover again and use the opening in the lid to debug it.<\/p>\n<p><a href=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/DSCN1527sm.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-141 alignnone\" alt=\"DSCN1527sm\" src=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/DSCN1527sm-1024x768.jpg\" width=\"614\" height=\"461\" srcset=\"http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/DSCN1527sm-1024x768.jpg 1024w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/DSCN1527sm-300x225.jpg 300w, http:\/\/www.mjblythe.com\/hacks\/wp-content\/uploads\/2013\/02\/DSCN1527sm.jpg 2048w\" sizes=\"auto, (max-width: 614px) 100vw, 614px\" \/><\/a><\/p>\n<h2>Conclusion<\/h2>\n<p>When I gave it to my wife on Valentine&#8217;s day, she thought it was pretty awesome.\u00a0 Even after she had opened it (on <em>medium<\/em> difficulty), she played with it for long enough that she had memorized the hard-coded sequence of orientations.\u00a0 She also liked the gifts I had stowed inside (a candle, some candies, and some romantic &#8220;coupons&#8221;).<\/p>\n<p>When she was playing with it, though, I did notice a few things that I could have improved.\u00a0 First, when an incorrect move was made to topside-up, the box would emit a high beep.\u00a0 This was because even though it was an incorrect move, it was the first correct move in the re-try.\u00a0 I should tweak the code to emit a longer low beep to signal the failure.<\/p>\n<p>I already mentioned above that once the box was closed, the beeper was too quiet.\u00a0 This shows on the demonstration video, too.<\/p>\n<p>I&#8217;d also improve my wire management.\u00a0 When playing with the box, I had to be very careful not to close the lid on a wire.\u00a0 The lid would still lock in place, but I think it has loosened.<\/p>\n<p>Finally, I want to improve the program to generate a new random sequence every time.\u00a0 The <em>impossible<\/em> difficulty is somewhat defeated now that my wife has memorized the sequence.<\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>***UPDATE*** I&#8217;m going to make some updates to the code, so I&#8217;ve modified all the github links below to point to a tagged version. For the latest-and-greatest code, look here. After I saw this post on hackaday.com about ST Microelectronics giving away STM32F3 Discovery boards for free, I knew I had to have one, but [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[5,6,3],"tags":[],"class_list":["post-108","post","type-post","status-publish","format-standard","hentry","category-gifts","category-puzzles","category-f3-discovery"],"_links":{"self":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/108","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/comments?post=108"}],"version-history":[{"count":51,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/108\/revisions"}],"predecessor-version":[{"id":1088,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/posts\/108\/revisions\/1088"}],"wp:attachment":[{"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/media?parent=108"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/categories?post=108"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.mjblythe.com\/hacks\/wp-json\/wp\/v2\/tags?post=108"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}