Skip to content

Automated Spice Rack with Vue.js, Arduino, and a Stepper Motor

I have been working way too long on an automated spice rack. The idea came to me when I was playing with learning how to manipulate a stepper motor. I thought, “Wouldn’t it be cool if we could place a little pusher on a shuttle and have the computer push out the spices you need?

I started about a year ago, and, for one reason or another got sidetracked. I always mean to get back to it. Last week, I found time again to finish this magnificent contraption. Here it is!

I want to go through the parts, share the code, and talk about the biggest challenges I had to overcome to get it working.

The Parts

Here are the parts I needed to piece together to get this thing working:

  • Stepper motor (Nema 17)
  • Stepper motor driver (Easy Driver)
  • Bread boards and jumper wires to connect everything
  • A NodeMCU ESP8266 Wifi controller (cheaper Arduino-like chip)
  • Relay switch (something like this)
  • Solenoid to push out the spices from the rack
  • 3d printed parts from an Ender 3 (I designed them using Fusion360)

To get this thing working I plugged it into a DC power supply. The NodeMCU chip had a simple http server running on it that communicates using websockets. I then built an interface where the chip would instruct the stepper motor to rotate. This may sound particularly hard, but there are many helpful libraries in arduino-land that made this a breeze.

Stepper motors are really nice because you can tell them to turn very precisely. I basically sent instructions to the NodeMCU to rotate x amount of stepper motor steps, and I was able to move with nearly millimeter precision once I hooked it up to the shuttle belt.

I then created a front end using Vue.js and sent commands to the chip. When the chip finished its instructions it would send a message back to my javascript app.

Challenge 1: Getting precise motor movement

At first I was working with a Raspberry Pi through it’s GPIO pins. I used Node to write instructions to flip the GPIO pins on or off. This would have been okay, but I found rather quickly that Javascript is slow.

Maybe it’s more accurate to say that scripting languages like Python and Javascript were inconsistent. Stepper motors, after you hook them up to a stepper motor driver, are controlled by basically flipping a switch. The faster or slower you flip that switch, the faster the motor will rotate.

I first started by just setting timeouts with javascript and switching pins on and off that way. But, if you know anything about javascript, you’ll know that timeouts are not guaranteed time pauses. Because there’s a lot going on on the system while your code is running, I found that I couldn’t get the pins to switch fast enough or consistently enough to get smooth movement. It would sometimes miss a bunch of switches and the total rotation would be off. For my automated spice rack I needed the distances to be exact.

Then I switched over to using arduino-like devices. I found these devices are low level enough that I could count on microsecond precision. In other words, there weren’t any jumps because there was not operating system per se interrupting or slowing down my code.

Challenge 2: Figuring out wiring

I’m not going to lie- my wiring is probably a mess. I’m powering everything through a DC power supply, and I just added connections where I feel like I needed it. When I got my shuttle moving well enough, I needed a way to switch my solenoid on and off so I could physically push out my spices once the shuttle got behind the wanted spice container.

Luckily relay modules are really easy to learn. They allow you to connect a circuit when you turn a pin on on the module. So, when the shuttle gets behind the right spice, the NodeMCU turns on a specific wire, and that tells the relay module to connect the circuit and fires the solenoid.

I learned quite a bit about check voltages, capacitors (I probably should be using them), resistors, and spec sheets.

Challenge 3: Sequencing asynchronous code in javascript

The last difficulty that I had to overcome was that Javascript had to wait for the spice rack to finish a command before it could send more. It was a little tricky to coordinate.

The solution? I used reduce() to sequentially resolve promises.

I had an array of instructions that basically amounted to:

const spiceArray = [
    // Go to 14cm,
    // push out spice,
    // Go to 34cm,
    // push out spice,
    ...
]

The problem in javascript is that if you just map over that array and run all of them, javascript won’t wait for the first instruction set to finish and then move to the next. It will all be fired off at once.

So we have to get creative.

The gist is that we wrapped each instruction in a promise and attached a listener to listen for a ‘done’ message to come back. When we get the ‘done’ message back we resolve the promise, and then javascript knows to move to the next promise.

Here’s my code… it works, but it’s a bit tricky to dig through.

  startFetching(spiceArray) {
    this.spiceArray = spiceArray

    const spiceLocationArray = this.spiceArray.map(spice => spice.position)

    const returnLocationPromise = (position, last = false) => {
      return new Promise(resolve => {
        const handleMoveEnd = event => {
          console.log(event, ' **FINISHED**')
          this.ws.socket.removeEventListener('message', handleMoveEnd)

          // fire the solenoid to push the spice out
          this.push()

          setTimeout(() => {
            if (last) {
              console.log('last...')
              this.to(0)
            }
            resolve()
          }, 2000)
        }

        this.ws.socket.addEventListener('message', handleMoveEnd)

        // pusher is 3cm above shuttle position
        this.to(position - 3)
      })
    }

    spiceLocationArray.reduce((previousPromise, nextPosition, currentIndex) => {
      return previousPromise.then(() => {
        return returnLocationPromise(nextPosition, currentIndex === spiceLocationArray.length - 1)
      })
    }, Promise.resolve())
  }

There are some prettier ways to do this that involve async await, but I didn’t bother trying to install the babel plugins. I just wanted to get this working 🙂

Conclusion

An “automated” spice rack wasgreat project that taught me way more than I though I would learn. I learned about electronics, C, micro-controllers, websockets, and learned some new stuff in javascript.

I think what struck me most is how accessible the parts are for creating your own things. If you feel you might be interested in making, try it out!

Leave a Reply

Your email address will not be published. Required fields are marked *