Sunday, April 29, 2018

Making a Smart Speaker - Part 5

Calvin is coming together. The software is moving along slowly, but I think it's time to assemble Calvin so there's only a single cable coming from him. The power cable. Everything else is optional, the way smart speakers should be. We'll add neato features like lights and working in its own microphone. Let's get to it!

First, let's get the Neopixel Jewel working on the Orange PI. The Orange PI has an SPI out pin, which is how we'll signal the data to the pixels. The two things I've found to help me figure this out are the comments on this video and this forum post, The power can be gotten from the USB header and the data comes from pin 19. Once I modprobed spidev and installed the packages from the forum post, the following program worked:

import spidev
import ws2812
spi = spidev.SpiDev()
spi.open(1,0)
ws2812.write2812(spi, [[25,0,0], [0,25,0], [0,0,25], [25,25,0], [25,0,25], [0,25,25], [25,25,25]])


They're different colors, I swear.
So, how do we control this from Node? I'm not too fond of python, but I honestly think writing an LED controller in Python will be much easier than trying to port the library from Python to JavaScript. So now we need a Python process running in the background. Good thing this processor is quad-core.

We'll use a Unix Socket to send messages to the Python process from the Node main process specifying which animations we want to run (if any) or what state the lights should be in. Thanks to multiprocessing, nothing will freeze the thread of something else and, thanks to hardware SPI support, SPI kinda just happens magically. So I glued it into the air hole allowing air to move around it. This speaker gets loud so we need to allow air to move as the sound is compressing it. This "Unix Domain Socket to Python Process" is also how we'll do the Google Play Music integration (which is also mostly done - asking for Genre stations is not working quite right yet).

The subwoofer internals transform 120VAC to 9VAC to 12VDC for use by the amplification chips. The question then becomes do I take the AC line and transform it to 5V, or should I take the 12V and step it down? After considering my options and the hardware I had on hand, I decided to transform AC power. This way there's no potential overdraw of the amplifier's power supply and we can reduce the noise on the DC line (because there's already a lot). That last bit about noise is just speculation, however. I'm not an electrician or an audio electronic designer. It just makes sense intuitively. 

So I got my hands on a simple 1 amp Micro USB Charger. The OrangePi Zero doesn't consume much energy, but I still checked to make sure it ran correctly using it. After making sure everything was correctly tested, I turned it on and hoped that the software would work. I had been developing the software without testing it on real hardware for a while and wasn't sure if it would still run with the new features.

After a bunch of dependency management and hope, I was able to get Calvin to respond to typed messages. A big issue was with the Google Default Credentials, but I finally got it to accept a service account JSON file. It took longer than it should have, to be honest. The light animations needed a little tweaking too, but it finally ran pretty well without taking up too much processor time.

At the end of the first day of part 5, the following steps remained:
  • I need to find another/better microphone. The USB microphone I was going to use could be better, and I think I want to avoid using USB altogether. I'm going to see if I have a microphone element in my box of stuff and see if it works using the microphone input pins on the OrangePI Zero Board. Bonus points for long range sensitivity and auto gain control.
  • Put it all in the box. With the exception of the microphone, everything is connected. I just need to jam it into the box. This should be easy, but we need to wait for the microphone to do that.
  • Program the firmware. Right now, the Linux firmware layer is just Armbian. I start CalvinAI over some kind of terminal. That shouldn't happen. It needs to start the lights process on boot to show that it's loading, load the Google Credentials, and then load CalvinAI. That way when I plug Calvin in, it just boots and is ready.
  • Make backing processes more resilient. I wrote the Google Play Music backing in Python using the GMusicAPI project. It takes a long time for it to start with the networking overhead, and CalvinAI needs to wait for it to start before it tries to connect to it over a Unix Socket.
  • Make a setup sequence for Calvin. Right now the WiFi stuff is hard coded into Calvin. That should probably change. I'm feeling some sort of WebUI. This isn't as pressing as the other steps because this sounds like a challenge firmware-wise.
  • Make Calvin updatable. Wouldn't it be cool if I didn't have to SSH into Calvin every time I wanted to update his software? Maybe the GitHub could have two branches - test and release - such that everytime I merge into test, any Calvin that's on the Beta channel would pull, build, and reboot (likewise for the stable release channel). This is also pretty low on my list.
I pulled off a microphone from the Canon a560 I tore down last year and wired it according to the following circuit:


When I built the microphone circuit, I had issues with noise and gain, but we'll see what I have to do to get that to work. I don't quite understand the circuit, so I'll ask one of my EE friends to help.

This is where I'll stop for this post. Calvin's hardware is looking really good (or, at least it will after some wire management). The commit at the time of writing has a lot of the kinks worked out, so be sure to take a look at that. I was planning to complete Calvin on this post, but I ran into too many microphone troubles. I'll try to stoke the dying embers of my free time soon so I can get it finished. So, until next time, Calvin still remains in parts on my desk.

No comments:

Post a Comment