Author Archives: Pete Lewis

Enginursday: Innovative Testbed Design (Part 2 of 2)

via SparkFun: Commerce Blog

This is part two of our series about the history of quality control and testbed design at SparkFun (click here to read part one). There was actually much discussion in the comments about hardware design - thank you so much to all that chimed in! You had very valuable feedback, and I look forward to hearing more after we dive a little deeper into the hardware on this design.

You are welcome to download the Eagle design files from the project GitHub repository here:

Flying Jalapeno GitHub Repository

For more info on getting started with Eagle, please check out this tutorial: How to Install and Setup Eagle.

For anyone that might prefer to follow along with a PDF, you may also click on the following image:

alt text

Flying Jalapeno Schematic (PDF LINK)

Power control switching

One of the earliest advancements in testbed design was the ability to control when power is applied to the product. Before this feature, we usually left the pogopin to the product’s VCC “HOT” - meaning that it was permanently wired to a power source. This should work fine, in theory, for most of the time, but what we found was that if you didn’t place the product down perfectly, sometimes you would momentarily short VCC to GND. Note, this would only happen on products where the two header pins VCC and GND were located next to each other, but that was actually pretty common. So during this burst of current on VCC, our testbed power supplied didn’t really like this, and they would drop voltage causing the entire testbed to reset. Ugh!

Some of the first testbeds to incorporate power control actually just routed an IO pin directly from the testbed ATMega328 to the VCC on the product. In this case, we could supply power to the product, but were limited to the 40mA (or so) that the IO could provide. Definitely not the best solution, and we saw a few testbeds die, and so the progress continued.

Power switch schematic close up Power Switch highlight on board

The next approach was to try a high-side switch using a mosfet. Looking back, we could have just as easily done it with a relay, but didn’t have an ideal relay in our inventory. Now that we have some nice mini relays like the SparkX Qwiic Relay, that may be the preferred way. But at the time (2009-ish), we only had the Beefcake Relay Control Kit, which seemed like overkill for 99 percent of our products. You’ll notice we also added a transistor on the front end to ensure the mosfet opens fully and takes the load off of the IO pin on the micro, and it’s really quite nice that writing the control pin HIGH actually engages power. We are always trying to think about usability, even with in-house tools.

Testing for shorts to ground

Using a simple voltage divider style circuit, a digital control pin and an analog read pin, we can safely and easily test a product’s power line (aka VCC) for a short to GND. It is particularly nice to know this before powering up a product - especially when it is a high-current product. We actually test for shorts to GND on all products now, regardless of power consumption. Odds are the testbed and product would survive a few hundred surges, but after a few too many, you are on the quick path to destruction. When designing for production, we need to think about testbeds living on (and working well) for many years to come.

I should also note that we commonly refer to this test for shorts to GND as the “pre-test.” This is because the “main” test is usually referred to as just the “test.”

The pre-test circuit is actually a pretty good exercise in learning about voltage dividers. If you’d like to learn more check out this tutorial here.

Pre-test for shorts to ground schematic close up Pre-test highlight on board

We use the circuit shown above to see whether or not there is a GND connection (or something that pulls as much current as GND would) on the product’s VCC. When there is a short, then the two 10K resistors basically split the VCC and the ADC reads the magic dreaded “486.” When there is no short, it will essentially form another voltage divider between a 100K and a 10K, and the ADC reading will be much higher. For a more info on this circuit, please check out a previous blog about quality control here.

Capacitive Touch “Buttons”

We moved away from mechanical momentary switches to engage testing years ago. A capsense pad (most importantly, non-mechanical) is much more reliable over thousands and thousands of “presses.”

Capacitive Sense schematic close up Capacitive Sense Resistors highlight on board

We use the Arduino capacitive touch library and two IO pins with a large resistor. Because we often need two buttons on a test fixture, we opted to dedicate four IO pins and include the resistors into the Flying Jalapeno design. With this setup, we simply need to route a trace to a pad on the daughter testbed. Note: we do usually take extra care on these traces and route them with 20-millimeter width. By avoiding vias and other data lines, we have seen great results with this form of capsense. Mad-house-routed thin traces or bad ground pour flow can make for some really wonky readings.

Dedicated LED IO with Built-in Resistors

We pretty much always need four LEDs on the testbeds these days – PASS/FAIL for the pre-test for shorts to GND, and PASS/FAIL for the main test. Because we have plenty of extra IOs on the ATMega2560, we decided to include the current limiting resistors on the FJ. These pins are now fairly committed for LED use, but we’ve got plenty of IOs to spare. This way, the daughter boards simply need a trace to an LED on each of these lines. The less complex the daughter boards can be, the better!

I2C Isolation “Switch”

A lot of early testbeds that involved I2C were troublesome for us. It was pretty common for I2C testbeds to “lock up” during testing. This was usually due to the testbed trying to talk to a product that was broken, had cold solder joints or had jumpers on SDA or SCL. I seem to remember a glorious day when wire.end() actually started working… Until then, we used to (and still do) disconnect the lines with a mux built into the test fixture.

I2C "isolation" switch schematic close up I2C "isolation" switch highlight on board

Again, at the time, we didn’t really have an ideal switch, and the Beefcake seemed like overkill for data lines, so we opted to use the PCA3906 I2C converter IC we had on hand. It had an enable pin that proved to be useful in disconnecting. We found that if we disconnected the I2C lines with something like this (in between testing boards), then it was much less likely to lock up. And best of all, the techs were much less likely to wear out the old fashioned momentary reset button the test fixture.

ATMega2560

ATMega2560 schematic close up ATMega2560 highlight on board

We simply went with this because it was very similar to our RedBoard, but with many more IOs. Sometimes a testbed will require a few more IO than the ATMega328 has to offer, so we found ourselves either using a mux or shift registers – better safe than sorry when it comes to having enough IOs. Also, having an Arduino-compatible testbed brain meant that we could more often than not utilize some of the product example codes for the test fixture.

The test developer also serves as a good beta tester for the products they work on. Usually the engineer on the product design has some sort of working code ready before we launch (which is super handy for test development). But sometimes even more importantly, getting it to work on the test fixture can help discover some bugs or documentation confusion before we officially go live with it on SparkFun.com.

Logic Level Select Jumper

Taking a tip from our breadboard power supply, we opted to add in a logic level select jumper.

Logic Level Select schematic close up Logic Level Select highlight on board

There was some discussion as to whether we wanted a slide switch or jumper. We ultimately wanted to keep it a jumper, so that it couldn’t be accidentally switched during handling and cause issues for testing. Plus, there is always gonna be some soldering assembly work for the daughter boards, so what’s the trouble in setting a quick jumper as well? Also, you may note that we are doing a “no-no” here by running the ATMega2560 at 3.3V - it is slightly out of spec for a 16MHz crystal, but we have seen minimal issues (if any at all) caused by this, so we’re gonna keep running with it.

Software-Definable VReg Control on Two Power Sources

Taking the selectable VReg idea one step further, we decided to make the two power sources have adjustable outputs that were software defined. By connecting various resistors to IO on the micro, we can choose which resistor we’d like to “send to GND” by writing that corresponding IO LOW. This effectively sets the output of our VRegs.

Software Definable Voltage schematic close up Software Definable Voltage highlight on board

You’ll notice that V1 can do 3.3V or 5V, and V2 can do 3.3, 3.7, 4.2 or 5V. This is nice when emulating a charged or empty single cell LiPo battery. By bouncing V2 between 3.7 and 4.2, we can get charge circuits to engage or disengage. This has proven very handy when it comes to getting a charge LED to blink.

2x30 RA Header

There was much discussion about what type of connector would do the job. It was tough to find the balance between strength, current capabilities, size and design-ability. We opted to go with a PCB-to-PCB right-angled style connector, and the 2mm pitched RA 2x30 header we found had a 2A rating, so it fit the bill. We also opted to have some connections with redundant pins (GND, V1, V2). Not only was this a good thing for reliability, it gave us way more current capability than we’d ever need (famous last words). More connection means less resistance too, so I was glad to know we’d see very minimal voltage drop from source to pogopin.

Mounting Brackets

With our choice of connector, this required a little creativity on how to mechanically connect the FJ to the daughter boards. We did not want to rely solely on the headers themselves, and so came up with some mounting brackets on either side.

alt text

They go on either side of the connector, on the top and the bottom, and are held into place with a 4-40 screw with a nylon thread locking nut. The spacing of the drill bits also ensures that the FJ and the daughter board will be assembled at the exact spacing for every future testbed. This is nice, because we want to make sure that the 2x30 is inserted fully. Yet another benefit that I didn’t anticipate (and was pleasantly surprised while building up the first prototype), is that these brackets worked as a nice “jig” to hold them together while soldering in the 2x30 male connector on the daughter board.

Custom Eagle Part

Eagle Symbol Eagle Package

To make daughter board design faster, we opted to create a custom part in Eagle. This way, we could quickly drop in an FJ into any daughter board design, and have all of the connections easily accessible. Note: we created the female and male versions of the connector in the same device. This makes it easier when referencing the FJ design during any troubleshooting. Also, we opted to include quite a bit of “used pins” in the symbol, which help highlight what they are doing upstream and can help with developing code for this hardware. Although, using the code library in conjunction with this hardware makes life even easier.

Logic Level Conversion for Serial Debug

Serial Logic Level Conversion schematic close up Serial Logic Level Conversion highlight on board

Do you suffer from serial bridge logic level conversion problems? We do too. Around production and at most engineers' desks here at SparkFun, it is always impossible to find the right logic level version of the serial bridge. Also, it is probably one of the most common mistakes made around here - “whoops, I plugged in a 3.3V logic thing into a 5V thing,” or vice versa. Well, with the FJ, we had a chance to avoid this problem, so we did. A tech can plug in any variety of serial bridge tools into the FJ, and it has the logic level conversion to handle it. Whew!

A Future Hardware Revision

As with all projects, this will never truly be done. The Flying Jalapeno has some quirks that could be improved (thank you for all your feedback on our previous post). But after two rounds of prototypes, we are fortunate that nothing supercritical is a road blocker right now, and for the most part the Flying Jalapeno is doing its job quite well. Nevertheless, here are some of the things we are considering on the next revision:

  • Upgrade mux switch for I2C isolation. The original IC choice for the I2C isolation was not really the best IC for the job. When we need to switch a connection on most newer testbed designs, we opt to use the 74LVC4066 MUX 1:1 (x4). This has worked great for switching all of our RX/TX, USB D+/D-, and programming lines. We also used this on a recent programming tool for production: the Pi AVR Programmer HAT (https://www.sparkfun.com/products/14747), and it has been holding up well for all our 2MHz + programming speeds.

  • Additional GND connections on the right side of the header package. Sometimes it can be a challenge to get a good ground flow all the way around the daughter board, so if I were to do this again, I’d sacrifice a couple IOs to be GND connection points on the right side of the connecter.

  • Additional dedicated LED IO with resistors built in. We are finding that with most daughter boards, we usually need one or two more LEDs. In addition to the standard pass or fail LEDs, it’s nice to indicate the tech other statuses or instruct them that it is time to do a certain action. You can’t have too many LEDs!

  • A strange issue with power control. Maybe someone reading can help us with this, but strangely enough, the power control circuits seem to be interacting. When V1 is powered up, and V2 is powered down, there still is some voltage present on V2. We even tried removing the source of power on V2, and it shows the same condition. I’m guessing it has something to do with the two long traces perfectly parallel to each other. Most of the time, this is not a problem (because we have them both powered up during testing), so we’ve been able to get by with the current version of the hardware. But it sure would be great to get to the root of what’s causing this, so any thoughts would be very welcome. Thanks!

comments | comment feed

Enginursday: Innovative Testbed Design (Part 1 of 2)

via SparkFun: Commerce Blog

It’s fun to be on the quality control side of things. Not only do we get to play with all the new widgets ahead of release, we are constantly faced with new challenges and pushed to innovate testbed design. Sometimes new products require new features on a testbed, and that pushes us to innovate. Sometimes we discover a reliability issue in production, and that pushes us to revise hardware to make something more robust. We’ve progressed a lot over the years. Let’s look back and highlight some of the innovations that allow us to design, build and code new testbeds really quickly.

Back in the day

We used to have some fairly finicky test fixtures back in the day. As a production tech in 2007, I remember very careful handling the fixtures to make sure I didn’t break any of the many, many green wires (and I was lucky if it worked 50 percent of the time).

A very old testbed from 2008 showing a product being tested using male headers held at an angle as a connection

Test fixture from 2008 using bare male headers to connect to the product…eeek!

As you can see above, this early testbed uses male headers facing up to make a temporary connection to the product. The technician would have to slide the headers into the products PTH headers on the side of the product, and then apply pressure to either side to attempt to make a connection during testing. It took a very steady hand to get this sucker to work every time. If you’d like to check out more info about our older test fixtures and general quality control progress, check out these tutorials:

Custom layouts

Testbed design with all of the components designed into one single PCB layout

Testbed made with custom PCB layout using mostly SMD commponents

In 2009 (ish), we started laying out custom PCBs for every new testbed. This was nice because it kept the designs small and self contained. Another advancement here was using pogopins to make a nice temporary connection to the product. This style of testbed design actually proved to be the “norm” for quite a while. At the time, and still to this day, we build all of our test fixtures by hand with an iron (even all the SMD parts). We just couldn’t justify ordering a stencil when we could get by with an iron and a steady hand. Even if it did have some more difficult parts that require hot air to place, we wanted to keep our rework chops up to snuff!

Modular Designs

Testbed with pro mini as controller and more modular design approach

Testbed designed around an Arduino Pro Mini and a custom base layer PCB

Here we have a stepper motor driver testbed. This is a good example of how we were able to use an Arduino Pro Mini as the main “brain” of the testbed, and then add the additional components needed to a custom PCB layout. This approach to testbed design became known as the “modular” approach, and cut down on the SMD work needed to assemble a testbed. It was also nice to know that production had tested the Pro Mini on your testbed, cutting down on any troubleshooting when you first power up.

Very large testbed using a arduino mega pro as the brain

Testbed using a Arduino Mega Pro and a custom base layer PCB

Here is a second example of a “modular” designed testbed, except this time we needed more GPIOs. This required using a Arduino Mega Pro instead of the Pro Mini. This again helps cut down on assembly time, although soldering up all of the PTH headers on the Mega Pro Board, and its mating female headers on the testbed, still does take some time. You may notice that this has quite a mix of color in the PCBs. I seem to remember having to rush order this from OSH Park in order to keep up with the Free SoC2 product launch schedule. Thanks OSH Park!!

Stand-alone programming

It had always been a dream of ours to move testing and programming away from using the production techs' Windows computers. This is because each time Windows would auto-update, we would be bombarded with driver issues. We ended up going with a Raspberry Pi-based solution and designing our own custom HAT, the SparkFun Pi AVR Programmer HAT. Read all about it in the following tutorial:

Pi AVR Programmer HAT Hookup Guide

July 26, 2018

In this tutorial, we will use a Raspberry Pi 3 and the Pi AVR Programmer HAT to program an ATMega328P target. We are going to first program the Arduino bootloader over SPI, and then upload an Arduino sketch over a USB serial COM port.

Custom Generic Hardware

As we designed more and more testbeds, we found that they needed similar things. This is why it made sense to make a single design that included most of the features we needed, and then make custom “daughter” boards that are specific to each product.

Custom designed production testing tool also showing bare headers and mounting brackets

The Flying Jalapeno testing tool in all its glory!

Above, is our in-house designed Flying Jalapeno. We use this on most new test fixtures, and it dramatically decreases testbed design and assembly time. Stay tuned for a more in-depth look at the hardware design of this tool, and the accompanying Arduino code library.

Testbed based off of the flying jalapeno the bottom portion daughter board is quite small

Testbed for an IR Array sensor using the Flying Jalapeno

As you can see above, this testbed is made up of two parts. The top section (the red PCB) is the Flying Jalapeno, and the bottom section (the green PCB) is the custom daughter board for the product. This particular testbed is designed to test the SparkFun IR Array Breakout. Because we receive the Flying Jalapeno assembled (and tested) from production, the assembly time for this test fixture is reduced to simply building up the smaller bottom section. That’s just a 2x30 header, five LEDs and four pogopins. Piece of cake!

Laser-cut Acrylic parts

Lumenati Testbed based off of the flying jalapeno design with lots of lazer cut acrylic

Testbed using the Flying Jalapeno and lazer-cut acrylic parts

Here is a fairly recent testbed design for testing the Lumenati 3x3. Occasionally, we will cut certain layers on our laser cutter using clear acrylic. Not only does this look slick, but it saves us money, because previously we would have been ordering those layers from a PCB fab house and that can get pretty costly for large testbeds. Also, this allows us to fine tune the laser-cut layers in house. We can tweak the design as necessary and have a new part cut in just minutes!

A few more beauties

example testbed using flying jalapeno and acrylic waffle top design

GatorBit testbed

testbed for openlog with unique waffle top that includes precise pusher higher to mate with product and light sensor

OpenLog testbed with unique “waffle top”

very large testbed with mostly acrylic and smallish amount of PCB layout for redboard edge product

RedBoard Edge testbed

Stay tuned for Part 2

Join us next week as we give a more in-depth look at all of the hardware choices inside the Flying Jalapeno, and dive into the accompanying Arduino code library. For a sneak peak, take a close look at the following picture, and see if you can spot any design flaws. There are actually a few things that we plan to change on a future revision to this design, but I challenge you to find as many as you can. The first commenter to spot the flaw I am thinking of will get extreme street cred and I will personally mail you a Flying Jalapeno!

top down image of the flying jalapeno design with no daughter board attached

Detailed pic of the Flying Jalapeno

Also, if you have any testbed design stories to share (I’m looking at you, #773), or any questions about SparkFun testbeds, please feel free to post a comment below. Thanks for reading and we’ll see ya next week!

comments | comment feed

Enginursday: Creating Random Sequences with Rules

via SparkFun: Commerce Blog

When you put a bunch of electronics around trampolines in a room, and ask thousands of kids to jump on them, it’s only a matter of time before something fails. About three weeks after Boulder Bounces opened, we got an email telling us that it was failing on occasion.

alt text

Background of the project

We recently designed and installed an exhibit at the Museum of Boulder called Boulder Bounces. It’s a memory game much like the Simon Says Soldering Kit, but with trampolines. You can read more about it at this blog post, or watch the following video:

The original Simon Says uses the built-in random() Arduino function. While this works fine for the original game, Boulder Bounces needed some extra rules in the sequence generation to avoid “boring” bounce patterns. It’s not that fun to have many repetitions of the same trampoline, and any repetitions in the beginning of the sequence are not only difficult, but can lead to some serious confusion for the first-time player. Plus, when you’re playing with a group of jumpers (each standing on their own trampoline), it is loads more fun to ensure everyone gets to jump.

Let the investigation begin!

I have a lot of serial debug messages sending out from my Arduino Pro Mini on this project, so I was eager to plug in a FTDI basic and hear what was going on. My original email from the museum said that if they simply cycled power, it would start working again. Because of this, my first thought was that it was most likely failing in software, and not a hardware issue.

When I opened up the panel on the wall, it looked like the LEDs had been mistaken for buttons and pushed completely back into the panel. Those darn kids! I guess I can’t blame them; the gumdrop LEDs are big enough to be a button, but I needed to stay focused on the problem at hand.

Jumping right in

I played through an entire game once. It worked just fine. I played another round. No issue. Again, and again. Nothing. Then on the sixth game, right before I should have heard the winning sounds, it seemed to stall out.

I went to look at my serial debug, but it seemed to stop spitting out any serial debug at all. Hmmmm. When I am troubleshooting a code bug that involves a “stall out” like this, my first approach is to verify the point of failure and then work backward to find out the potential issue.

During my last game (right before the failure), I remember my serial debug was working properly. It was outputting each new sequence after each successful play correctly. But at my “win,” the serial debug stopped, so the failure must be occurring somewhere immediately after the last add_to_moves() was called.

A high-level look at the original code

Before we jump into any of the original code, I think it would be beneficial to share the high-level plan for gameplay, and my higher-level approach to creating the random sequence with rules.

The original gameplay code worked like this:

When you are playing a game, the Arduino will “play” back the sequence to you. At first, it only shows one trampoline light up, and you jump on it. Then the Arduino “randomly” chooses the next trampoline to add to the sequence. It plays back the entire sequence (which at this point is only two jumps long), and you must jump the sequence in order. Then it adds another, and so on. Once the sequence reaches eight and you successfully jump in the correct order, you win!

The specific part of the code that I’m talking about today is a function called “add_to_moves()”. This is a simple enough function in theory. Let’s take a look at the original function from the original Simon Says to start. Note, this code is from the button game, and was not used on the trampolines installation, but it’s a good place to start.

void add_to_moves(void)
{
  byte newButton = random(0, 4); //min (included), max (exluded)

  // We have to convert this number, 0 to 3, to CHOICEs
  if(newButton == 0) newButton = CHOICE_RED;
  else if(newButton == 1) newButton = CHOICE_GREEN;
  else if(newButton == 2) newButton = CHOICE_BLUE;
  else if(newButton == 3) newButton = CHOICE_YELLOW;

  gameBoard[gameRound++] = newButton; // Add this new button to the game array
}

First, you notice that the “random(0,4);” is generating the next “newButton” in the sequence. The following five lines of code are not really important in this discussion, but to quickly explain, we need to change them to the defined variables associated with each button choice available. For today, let’s just focus on the creation of newButton and then how it is added to the array, gameBoard[].

Looking at the original function add_to_moves(), it simply uses random() to add a new button to the sequence. This worked fine for the original Simon Says, but for Boulder Bounces, we needed to add in some rules to make it more interesting.

Add a while loop and some rules

My first approach to adding rules was to put it in a while loop. Inside this while loop, it would first grab a random newButton value from random(), then compare it against some rules. If it passes all the rules, then it would use it, and break out of the while loop. If it doesn’t pass a rule, then it would do nothing, stay in the while loop and try again.

alt text

The problem with this approach is that it is living on a prayer that random will eventually return something that will pass the rules. I knew this wasn’t perfect, but in all my development work on this project I never saw it get stuck. It usually tried a couple times at most, but eventually returned something that would work. It turns out that it can get stuck there, and something was causing it to stop trying.

For reference, the original code (with the actual rules - aka “if” statements) is as follows. You can see all of it here on my github commit. Specifically, here is my original add_to_moves():

void add_to_moves(void)
{
  while (1)
  {
    newButton = random(0, 3);
    if (!((newButton == gameBoard[gameRound - 1]))) // avoid repeats
    {
      // check to see if that button is already "maxed out"
      if ((newButton == 0) && (RED_seq_count == 2)); // do nothing
      else if ((newButton == 1) && (GREEN_seq_count == 3)); // do nothing
      else if ((newButton == 2) && (BLUE_seq_count == 3)); // do nothing
      //else if((newButton == 3) && (YELLOW_seq_count == 2)); // do nothing
      else break; // get out of this while loop and continue playing.
    }
  }

  // We have to convert this number, 0 to 3, to CHOICEs
  if (newButton == 0)
  {
    newButton = CHOICE_RED;
    RED_seq_count++;
  }
  else if (newButton == 1)
  {
    newButton = CHOICE_GREEN;
    GREEN_seq_count++;
  }
  else if (newButton == 2)
  {
    newButton = CHOICE_BLUE;
    BLUE_seq_count++;
  }
  else if (newButton == 3)
  {
    newButton = CHOICE_YELLOW;
    YELLOW_seq_count++;
  }

  gameBoard[gameRound++] = newButton; // Add this new button to the game array
}

You may also notice that my rules rely heavily on some new variables: RED_seq_count, BLUE_seq_count, etc. These are helping me keep track of how many times I’ve already included a specific color button in the sequence, so I can avoid favoring any button and ensure everyone gets to jump.

In an attempt to hone in on the problem, I added a little line of debug at the end of my add_to_moves() function.

if(debug) Serial.println("add_to_moves attempting...");

Now I would know whether it was trying at all, getting stuck in this while loop or stalling out elsewhere.

After much jumping and winning, I got another failure in the middle of a round. It stalled out, and my serial monitor looked like this:

alt text

Remember, my first failure was just before a “win.” Because this second failure was in the middle of a game, this was a new clue! This means that the failure is caused somewhere else in the code, and probably has nothing to do with the code just before a win.

Right before it stalled out, the entire serial monitor was filled with the message “add_to_moves attemping…” It was sending this message again and again as fast as my little Pro Mini could go. Something strange was going on. Why would it get stuck repeating this message, and then eventually give up?

The speed of the repetition of the debug message was also strange. When it seemed to be trying normally, the message would spit out to the terminal at a moderate pace. But when the failure would occur, the messages would speed up dramatically and eventually cause a stall out. After much finagling and many attempts to cause failures, I eventually gave up trying to find the root cause. I knew there was a better way, and so decided to start a different approach the the random generator with rules.

A better approach

alt text

To elliminate the possibility of any stall-outs, I introduced a new array called “on_deck_buttons[].” I would have my rules adjust this array, and then my random function can just choose from the good options. That way, random() will only be called once, and this removes the need to loop back around and try again and again.

I also beefed up my debug to get a better view into what was actually going on with all my variables and arrays.

Here is my new add_to_moves() function:

// Adds a new random button to the game sequence
void add_to_moves(void)
{
  byte newButton = random(0, 3); //min (included), max (exluded)
  int add_to_moves_counter = 0; // keep track of our while loop below for finding good new buttons, and see if this is jamming the game.
  if(gameRound == 0); // do nothing - newButton is randomly set above.
  else if((gameRound == 1) || (gameRound == 2)) // jumps 2 and 3 are important. for the first 3 jumps we want these to always hit each tramp once
  {
    while(1)
    {
      add_to_moves_counter++; // keep track of how many times we are trying to find a good new button to use (random might be stalling out here)
      int on_deck_buttons[2] = {0,0}; // these are used to help reandomize below
      newButton = random(0, 3); // pull in a first attempt at a nice new random button
      if((newButton == 0) && (RED_seq_count > 0))
      {
        on_deck_buttons[0] = 1;
        on_deck_buttons[1] = 2;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;
      }
      else if((newButton == 1) && (GREEN_seq_count > 0))
      {
        on_deck_buttons[0] = 0;
        on_deck_buttons[1] = 2;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;
      }
      else if((newButton == 2) && (BLUE_seq_count > 0))
      {
        on_deck_buttons[0] = 0;
        on_deck_buttons[1] = 1;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;        
      }
      //else if((newButton == 3) && (YELLOW_seq_count == 2)); // do nothing
      //else break; // get out of this while loop and continue playing. This means that the new button is good to go. 
      else
      {
        Serial.println("error");
        break;
      }
      if(debug) Serial.println("add_to_moves attempting...");
      if(debug) Serial.print("gameBoard[gameRound-1]:");
      if(debug) Serial.println(gameBoard[gameRound-1]);
      if(debug) Serial.print("gameBoard[gameRound-2]:");
      if(debug) Serial.println(gameBoard[gameRound-2]);      
    }
    if(debug)
    {
      Serial.print("add_to_moves_counter: ");
      Serial.println(add_to_moves_counter);
      Serial.print("RED_seq_count: ");
      Serial.println(RED_seq_count);
      Serial.print("GREEN_seq_count: ");
      Serial.println(GREEN_seq_count);
      Serial.print("BLUE_seq_count: ");
      Serial.println(BLUE_seq_count);
    }
  }  
  else // only after you make it to step 3.
  {
      // attempt 1, works.
      // while((newButton == gameBoard[gameRound-1]) && (newButton == gameBoard[gameRound-2])) newButton = random(0, 4); // keep pulling in more variables until this isn't true.
      // basically, if it's the same as the previous 2 buttons, then it will keep finding a random number until it's "fresh".

      // attempt 2, attempting to add in limit per button to avoid leaving one jumper out.
    while(1)
    {
      add_to_moves_counter++; // keep track of how many times we are trying to find a good new button to use (random might be stalling out here)
      int on_deck_buttons[2] = {0,0}; // these are used to help reandomize below
      newButton = random(0, 3); // pull in a first attempt at a nice new random button

      // This ensures it's not going to repeat same button 3 times
      //if((convert_to_choice_byte(newButton) == gameBoard[gameRound-1]) && (convert_to_choice_byte(newButton) == gameBoard[gameRound-2])); // do nothing, try again 
      // check to see if that button is already "maxed out" (aka it has been used twice already)

      if((newButton == 0) && (RED_seq_count == 2))
      {
        on_deck_buttons[0] = 1;
        on_deck_buttons[1] = 2;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;
      }
      else if((newButton == 1) && (GREEN_seq_count == 3))
      {
        on_deck_buttons[0] = 0;
        on_deck_buttons[1] = 2;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;
      }
      else if((newButton == 2) && (BLUE_seq_count == 3))
      {
        on_deck_buttons[0] = 0;
        on_deck_buttons[1] = 1;
        newButton = on_deck_buttons[random(0, 2)]; // chooose randomly from on_deck_buttons - aka the only ones we want to choose from
        break;        
      }
      //else if((newButton == 3) && (YELLOW_seq_count == 2)); // do nothing
      //else break; // get out of this while loop and continue playing. This means that the new button is good to go. 
      else
      {
        Serial.println("error");
        break;
      }
      if(debug) Serial.println("add_to_moves attempting...");
      if(debug) Serial.print("gameBoard[gameRound-1]:");
      if(debug) Serial.println(gameBoard[gameRound-1]);
      if(debug) Serial.print("gameBoard[gameRound-2]:");
      if(debug) Serial.println(gameBoard[gameRound-2]);      
    }
    if(debug)
    {
      Serial.print("add_to_moves_counter: ");
      Serial.println(add_to_moves_counter);
      Serial.print("RED_seq_count: ");
      Serial.println(RED_seq_count);
      Serial.print("GREEN_seq_count: ");
      Serial.println(GREEN_seq_count);
      Serial.print("BLUE_seq_count: ");
      Serial.println(BLUE_seq_count);
    }
  }

  // We have to convert this number, 0 to 3, to CHOICEs
  if(newButton == 0) 
  {
    newButton = CHOICE_RED;
    RED_seq_count++;
  }
  else if(newButton == 1) 
  {
    newButton = CHOICE_GREEN;
    GREEN_seq_count++;
  }
  else if(newButton == 2) 
  {
    newButton = CHOICE_BLUE;
    BLUE_seq_count++;
  }
  else if(newButton == 3) 
  {
    newButton = CHOICE_YELLOW;
    YELLOW_seq_count++;
  }

  gameBoard[gameRound++] = newButton; // Add this new button to the game array
}

The trouble with failures that only happen once in a while is that it can require lots of data points and repeated testing to emulate the failure. For most software issues, this can sometimes be automated and done quickly, however, with exhibits like these that involve physical hardware, the true game play must be cycled again and again to create the failure.

The trampolines were failing randomly every 10-20 game plays, so that meant a lot of jumping. Never in my life have I had such a physically demanding code debug session! I did my fair share of jumping during the development of this project, but that paled in comparison to this debugging session.

If you have experienced any strange stall-out with the random() function, or have any other approaches to creating sequences like this, please share in the comments below. Also, please check out the github repo link below, and if you so feel inclined, we always love seeing any issues, forks, pull requests or comments. Thanks for reading and happy coding!

Boulder Bounces Github Repository

comments | comment feed

Enginursday: Boulder Bounces

via SparkFun: Commerce Blog

SparkFun recently teamed up with the Museum of Boulder to create a new exhibit called Boulder Bounces. It’s a re-creation of our Simon Says Soldering Kit, but using trampolines instead of buttons, and spotlights instead of LEDs.

The purpose of Boulder Bounces is to augment another exhibit called Sportsology, which has interactive areas where people can learn about their own agility and test their strength doing various sports activities. The museum wanted to add something geared toward toddlers to this area.

alt text

Digital mock up from the project proposal

Emily Zinn, their curator of education, had been to SparkFun for a collaboration involving their new makerspace, saw the original Simon Says trampolines and thought they would be the perfect addition!

alt text

The original Simon trampolines - currently located at SparkFun

Amazingly, the original trampolines have survived almost five years since their original Dunk Tank Hack Installation – they have even been on tour across the nation a couple times! They require very little maintenance (mostly cracking wires and LEDs), but I was very excited to create them a second time and improve on the original version.

Lots of improvements

alt text

Control panel with new gameplay modes

We’re most excited about the addition of two new gameplay modes: “Free Bounce” and “Whack A Mole.”

Free Bounce simply lets you jump for fun. You hear a sound and the spotlight fires each time you jump. If there is no jumping for 30 seconds, the exhibit will default into this mode.

Whack a mole is a bit more challenging. It plays just like the old carnival game; when you see a trampoline light up, you jump on it.

If you want to really test your memorization and jumping skills, then you can try Simon Says and memorize up to eight jumps to win!

Another major upgrade was the elimination of the center gap in the trampolines. I have always dreamed of welding a single frame for all of them, but with only three weeks to get this project completed, there simply wasn’t enough time. We found some hexagonal trampolines that fit together quite nicely instead.

alt text

Hexagonal trampolines with no center gap

As with any slight change to a design, this added complexity elsewhere. The custom covers became quite a challenge, but they sure came out looking awesome!

alt text

Custom hexagonal covers

The original installation used exercise trampolines that came with a very handy triggering switch.

alt text

Version 1 mechanical switch

These mechanical momentary switches work really well for most jumpers. However, some of the really lightweight jumpers didn’t cause enough movement to close the switch, and so the occasional jump was missed. To solve this, we switched to a more analog sensing approach, and used the Ultrasonic Sensor.

alt text

Version 2 used Ultrasonic Rangefinders

This allowed for a more precise measurement of the trampoline skin and we could sense even the slightest of movements – no toddler’s jump missed!

The original version involved a lot of hand soldering of wires. A lot of the connections were made directly to the ATMega328 pins on the Simon Says PCB:

alt text

Lots of hand wiring - wait, which ADC did I wire up?

For this new version, I designed a custom PCB to keep things organized.

alt text

Custom PCB design

I’ve had a couple requests from educators for assistance re-creating their own Simon trampolines installation, so I approached this next version with that in mind. I tried to keep it easy to re-create with less point-to-point hand soldering, so it was a little more accessible for a classroom with little soldering or coding experience. I also opted to use a Arduino Pro Mini to keep things easy to replace.

alt text

Some parts wired up during initial development

The ethernet cables (and connectors) also helped cut down on hand wiring connections, but with the addition of the control panels, there was still plenty of soldering to do:

alt text

The inside of the main control panel

The second version also included two more trampolines for the toddlers: “Mighty Mini” and “Hop and Hear.” They both include more sophisticated sounds and the Mighty Mini has a counting feature!

alt text alt text

Two additional trampolines

Design Challenges

One of the most challenging parts of this project, by far, was the fact that we only had three weeks to get it up and running. We underestimated the time needed for most of the installation steps, and did not add in enough buffer for any surprise problems. Bringing in new design techniques (hexagon shapes) and using new technologies (ultrasonic sensors, Tsunami sound boards) added some surprise extra development work that compounded the time crunch.

The first surprise came from the ultrasonic range sensors. I did some testing with two sensors on the old Simon Says installation, so I naively assumed this would be easy. I was able to get good readings from two sensors sequentially, but I didn’t do any testing with two trampolines being jumped on at the exact same time. I later found that when you have two rangefinders in close proximity shooting up at angled surfaces, there can be some really strange readings. The “send” signal from one sensor can incorrectly “echo” its way to the next sensor and cause errors. Ultimately, I was able to tweak the timing of the sequential readings and also filter out some of the erroneous data, but this extra troubleshooting added an extra 4-5 hours of work!

The second surprise came from the Tsunami Super Wav Trigger. I was experiencing some strange behavior - the Tsunami’s boards seemed to be missing triggers, making strange buzzing sounds and eventually crashing. After spending a day and a half troubleshooting, I eventually found that one of my uSD card settings was causing the issue - I had my file allocation size set incorrectly to four kilobytes. After I switched it to 32 kilobytes, my Tsunami boards worked flawlessly.

alt text

Formatting settings for Tsunami uSD card

What would I do differently for version 3?

Plan better for control panel access. Power worked out, but it was tight, and messy. Also, I’d like to have put access to programming lines and volume control without having to remove the front panel. It was stressful to think that it all had to be “perfect” before putting the faces on the panels, and that it’d be a pain to “rip” them off (velcro) for any adjustments.

Related to panel access, I would go with the RedBoard Edge for future designs like this. It has all of the necessary stuff ready to panel mount. We currently offer this via SparkX, and unfortunately it was out of stock while I was developing this.

alt text

RedBoard Edge would have been a good option for my control panels

I also should have made larger holes for cords into the control panels. I was only thinking about the cable diameter fitting through the wall of the frame; this lead to some unplanned drilling and wood shavings all over everything!

Ideally, I would have preferred more time to fine-tune the button control approach. Currently, the Pro Mini is listening to a resistor ladder on a single ADC. This required a fair amount of fine tuning the “windows” and de-bouncing. It currently will miss a very slight button press, but this actually isn’t that common because most participant smack the arcade buttons with all their might!

I would have used a different power solution to avoid the clicking of the beefcake relays - maybe the Lumenati 3x3 array for lighting?

I also should have tested the LED brightness on MODE LEDs - those greens are way too bright! I used 330 ohm resistors on everything, and found that this was way too bright for our 10mm gumdrop greens. Also, the Large 7-segments are pretty darn bright, wish I could have toned those down a bit.

I probably should have used interrupt-based buttons for mode changing, maybe by hooking all the buttons up to an interrupt pin and keeping them connected to their own dedicated GPIO. This way, the interrupt would fire, you could read all pins and know which one was pressed. I was running low on GPIO (in order to keep my custom PCB universal for all three control boards), so I opted for the resistor ladder approach.

Adding LED limiting resistors into the custom PCB design would also have been helpful. It was a pain to wire those from LED lead to bare wire, and I’d hate to change them at this point, but if they were in the PCB design this would have been much easier.

What Next?

We’re thinking about a potential revision to the Noisy Cricket to have screw pin terminals. We had trouble using even some small-gauge speaker wires with the standard 0.1" header breakout PTH pads. We ended up actually putting a screw pin terminal into the headers (as they are), and it gave us access to the GND/MONO-OUT that we needed, but this is less than ideal.

Our current in-house Simon trampolines could use an upgrade. I’m thinking about switching out the gumdrop LEDs for some sort of strips. Our Side-lit LED RGB strips would probably do the trick!

I wasn’t totally satisfied with my mounting approach to proto board. Those PTH headers should hold up, but I’d love to have some more solid standoff holding everything together.

The Tsunami allows you to “pitch bend” sound files, and I’d love to have lighter jumpers have high-pitched sounds, and heavier jumpers have larger, low-pitched sounds (could be especially fun with frog sound bits).

We’re also considering expanding the project into “The Hive” – seven hexagonal trampolines all connected and making sounds. Oh yeah!

Finally, I’d like to explore more lighting techniques. The spotlights came out cool, but I’m curious to know what we could do with lighting systems under the trampolines and custom covers made from a clear material.

Even with all of these potential ideas for Version 3.0, we’re still really stoked on the end result of Boulder Bounces. Every project is a learning experience, and this was definitely not an exception.

We’d also like to send a big thank you to the Museum of Boulder for the opportunity to collaborate on this project! For more info on the museum and all of the other exhibits, please visit MuseumofBoulder.org.

alt text

Boulder Bounces will be on display at the museum for the next three months, so if you get a chance, please come check it out!

For design files and code, visit the GitHub repository here:

Boulder Bounces Github Repository

comments | comment feed