Tuesday, December 26, 2023

Edit-as-you-go Sound Recorder

My friend, Mason, is an actor in film, stage, and voice projects. One of his enjoyed past times is to record audio books. Y'know, long ones, the ones in the public domain (his still sound great though). All from the kindness of his heart. The problem is that his typical workflow included recording long takes often with restarts or variations. Then, when he went to edit the hours and hours of audio, it would take him a really long time to narrow things down to the ones he really wanted. All this and he still had the other audio processing he likes to do before he publishes. 

As we were hanging out, I had the idea that one could substantially cut down on time if you make the decision about selections as you record them. More often than not, he has a good ideas what recording segments he thinks will work well. This is when I got to thinking about the Edit-as-you-go Sound Recorder (I'll call it EAYG). The idea was simple, write a program that would record your microphone and then when you knew you had something you liked, you would hit a keyboard shortcut and it would automatically be stored for you. Another benefit is that each clip already has a natural cutting point by virtue of being a self-contained clip or segment. Using ChatGPT a bit (haven't done much with sound in Python), and after putting things together for a couple hours, I had a working version of the program with managed memory buffers, recording flow, and even restoring your last recording if the program crashes mid-take. 

The program records audio at 96kHz 32-bit. This could be easily changed in the code, and maybe from a preference menu or something. 

Another note, Mason is always inside his recording booth, and not next to his computer. Using a simple wireless keypad, and the program shortcuts, he can trigger whatever action he wants to have happen to the clip and get audible confirmation through his headphones. 

You can checkout Mason's stuff here:

Mason Willard - Stage, Film, and Voice Actor
Youtube: https://www.youtube.com/@_roscius
Email: [email protected]


Before recording, choose session directory. This directory will be the location of one or two more directories after you finish recording your session (based on good/bad takes).

Next, choose your recording device or interface.

To begin recording, start the session (F10). Once the recording has started it is now recording audio. When you are happy with the take, click Finish Good Take (F11).
If you don't like the take, click Finish Bad Take (F12).
If you are not sure about the take, click Replay Last Take and you can listen to the take on repeat, then choose Finish Good Take or Finish Bad Take.

Choosing Finish Good Take or Finish Bad Take, saves the audio segment in a respective folder, and then begins recording again automatically. 

When you are done with the session, click End Session (F10). The last segment of recording prior to the session ending will be discarded.

Your good takes will all be in a folder called /recorder-keep and the rejected audio files are in a folder called /recorder-discard. All files have been named using timestamps so they are sortable. The location of these folders can be selected prior to starting a session.

Keyboard Shortcuts

These can be changed in the code easily enough. The reason behind these was specific to the original use case of using a mini wireless keyboard to trigger recordings from inside the recording booth.

Assembly in Audacity

For quick assembly in Audacity, you can select all your good takes and drag them into a new session. Next, select them all and choose Tracks from the top menu. Then choose Align Tracks -> Align End to End.

Also, it may be helpful to turn on ripple edit so as you modify each take, the other audio files don't fall behind. You can enable this by going to Edit -> Preferences and the go to Track Behaviors and check the box "Editing a clip can move other clips"

More Help or Desired Changes

The code is available as is. If you find bugs, please submit them on GitHub and I will address them as I am able and time permits. In the event you would like bugs fixed sooner, customizations, or personal help setting up and using the program, I can be available to help at my hourly rate. 


Wednesday, December 13, 2023

Lolin32 Lite Notes

These are on-going notes I have for the Lolin32 Lite board.

Specs and graphic: https://mischianti.org/esp32-wemos-lolin32-lite-high-resolution-pinout-and-specs/

Flashing the Board

  • Plug in device
  • Start flash, wait for the Arduino ide to report 'Connecting'...
  • Connect the EN pin to GND briefly using a wire or something
  • The thing starts to flash!
Source: https://github.com/espressif/arduino-esp32/issues/2516#issuecomment-648088588

Wednesday, November 8, 2023

Connecting to and Controlling an Optidrive E3 VFD using Arduino and Modbus RTU

Note: For those interested in virtual production, I have published a version of this on this website as part of a collection of virtual production resources.

While working on building some automations for a large rotating platform, I determined I would need to communicate with a the VFD (variable frequency drive) which drives the large turntable motors. From my research, it seems that many modern VFDs generally support the Modbus Protocol, generally over RS485. The Invertek Optidrive E3 that we are using, specifically supports Modbus RTU (Modbus over serial) by way of an RJ45 port. The connection for RS485 (or two wire signal configuration where one wire carries the inverse signal) can be implemented in various ways, this one is through the RJ45 port, but sometimes you will find connections for this on the terminal strip on the VFD. 

Invertek Optidrive E3

To complete our objective, we need several things: 

  • Setup Arduino to communicate using the same means (RS485) and with an understanding of the Modbus RTU protocol
  • Setup the VFD correctly to handle accepting and responding to the Modbus RTU protocol
  • Debugging capabilities (in my case, a USB TTL to RS485 cable), tools, and software

Admittedly, this is my first time working with Modbus RTU and VFDs. I previously did a little work with building some DMX adapters which also uses the RS485 wiring configuration, but this was going to be quite a bit more involved.

RS485 and MAX485

Starting with RS485, we first learn that this unique configuration allows for data signals to travel fairly long distances without much risk of data loss or noise. These long runs are perfect for large entertainment venues (DMX) or factories and warehouses (PLCs, VFDs, etc.).

For a great and fairly comprehensive guide on RS485, take a look here. For our setup, we will only be implementing 2-wire (half-duplex) communication. With our two wires, one wire carries the normal signal and the second wire to carry the inverted signal. These two signals can then be compared to one another to determine what is intended signal and what may have been inadvertently introduced or lost, like noise. Most common Arduino boards do not have accessible RS485 capability which  means we need to add another chip. The MAX485 is a common chip that has been around for sometime and can take a single signal, and create our two versions of it for transmission. For me, I decided to work with the MAX485 module boards instead of the chips directly as that tends to make prototyping much quicker. 

MAX485 Module

Connecting the MAX485 module to and Arduino is fairly simple and many guides exist out on the internet which are more or less the same (see image below). The big take-aways are that you use two GPIO pins on the Arduino to send and receive data, the same way serial works. The second is that you connect a third GPIO to signal the MAX485 to listen or speak (Note: this is actually two connections on the MAX485 module, but most people jumper these together with the send/receive signaling pin). This signaling GPIO pin tells the module if it should receive data or send data. 

You might be wondering why, if serial already sends and received data, why do we need an entirely separate module? This is important for a couple reasons, but primarily because the MAX485 module is half-duplex (although you could add a second MAX485 module for full-duplex configuration - also known as 4-wire). That means it can only send data OR receive data, but it can't do both at the same time. You can think of it like this: half-duplex means only one device can speak at a time. So, with regard to the module, in order for us to make sure it works as we expect, we need to tell it when to do what. So the module is kind of down-grading (in a sense) our communication, but remember, because we are using 2 wires to send the signal and the invert signal, we get much more reliability much further distances in exchange. 

The basics of wiring the Arduino Uno to the MAX485 look like this.

Basic Wiring for MAX485 and Arduino Uno

I would recommend using an Arduino with multiple UART serial ports. This allows you to continue debugging the Arduino program while it is also communicating with the MAX485 module. I have had success using SoftwareSerial, a coded implementation of the serial interface. It is slower, but it seems to work fine for this. Turns out the communication was more flaky using SoftwareSerial, and I had to switch to using an Arduino with a second dedicated Serial (I went with the Arduino Mega2560 for now -- wiring is very similar to the above image just connect the RE to RX1 and DI to TX1). Also, if you decide to connect up a different board, make sure the operating voltage of the MAX485 match the GPIO operating voltage (i.e. 5 volts).

You may have noticed that DE and RE on the module are connected together. This is because one of those is set HIGH when we want to send data and the other is set LOW when we want to receive data. This combination means that while we have the flexibility to customize our interactions further, for our usage, we don't want the board to receive data at the same time we are sending data. Connecting both pins from the MAX485 allows us to use a single GPIO on the Arduino, and just toggle it's state when we send or receive. 

You may have also seen MAX485 modules (or similar modules) that have flow control. To my understanding, flow control essentially tries to automate the toggle for you based on when data is being sent or not. This sounds great in theory and has been reported to work well with DMX, but some users have reported issues when trying to use flow control modules specifically with Modbus RTU.

Modbus RTU

Modbus is a fairly well-established protocol and has been around for sometime. By protocol, I mean it dictates what the data on a line looks like, how to read it and write it. Modbus does not actually care how it is transmitted, which is why you will see similar things like ModbusTCP, etc. With regard to Arduino, we usually don't have transport layer capabilities without adding a shield or ethernet module. In our case, this E3 VFD does not support ethernet (there are warnings in the manual about treating the RJ45 port as an ethernet port and the damage this would likely cause your other devices - DO NOT DO THIS).

As Modbus has been around for some time, there are already some great libraries that exist that abstract much of the heavy lifting of implementing Modbus properly. This include format, encoding, decoding, and CRC (error checking). I chose to use the library ModbusMaster. This library is simple to install and is supported by many Arduino boards right out of the gate.

Essentially, the program lets us communicate with a Modbus device using a Serial interface. It also allows us to easily setup callbacks to call before sending data and after we have sent it. This comes in really handy when we want to signal to the MAX485 transceiver module that it is time to send, otherwise it defaults to be receiving data.

I've posted some test code here.

You should be able to upload this code to your Arduino.

Testing Arduino Modbus RTU and MAX485 

Now with our wiring of the Arduino to the MAX485 module in place, and our Arduino Uno programmed, we can now run a test. To make testing simpler, it is helpful to have another MAX485 board connected to another Arduino, or you can also buy a TTL/RS485 cable online. The prices on these cables can vary greatly, and some include more capabilities than others to support other hardware protocols. 

A TTL/RS485 Cable

For FTDI chip cables, you may need to also install the FTDI driver like I do with DMX. With that in place, you now can connect your adapter to your computer and connect the MAX485 A to RS485A/RS485+ of the adapter and the MAX485 B to RS485B/RS485- connector. This can trip people up -- with Serial, you connect RX to TX both ways, but with RS485, you connect A to A and B to B. This is because in half-duplex communication A will always be the regular signal, and B will be the inverted signal. (If you wired them backwards on accident, it should be fine, just switch them around.) One more important thing to keep in mind is that we need to establish a common reference between the Arduino and the adapter. Connect a ground (GND) wire between them. 

It all looks good, but how do we know it is working?

A great program for Windows is called Serial Debug Assistant which you can get for free from the Microsoft Store (and with awesome upgrade options). This is a serial interface program that provides many great basic options when interacting with serial communication devices. For our tests, select the COM port of the TTL/RS485 USB adapter, set the baud rate (i.e. 115200), set the data bits (for this setup it is 8), no parity bit, and 1 stop bit. Now click Open Serial Port. If the software was able to connect successfully, you should see the button change to say Close Serial Port. I also like to set the Receive settings in Serial Debug Assistant so that the HEX display is on and Auto break frame is set to 20ms. For Send settings, check the HEX send box to send responses (more later).

My Settings in Serial Debug Assistant

A note about communication using Modbus. Often, we setup these configurations with one main controller or master (the devices asking for data from others) with one or more peripheral or slave devices (the devices returning data). The connected slave devices will only respond when asked to update something or return a value, otherwise they are quiet. Also, there is only ever 1 master. In our Arduino setup, the Arduino is the master device. For testing with the PC, the PC is a slave device. That means that the PC should only respond when requested from the Arduino.  

With a connection between Arduino and the PC setup correctly, and Serial Debug Assistant successfully connected to our USB TTL/RS485 adapter via a com port, we should now be able to see the data coming from the Arduino. It may look like this if you left the Arduino code as it was:

01 03 00 06 00 01 64 0B 

Which breaks down like this:

Modbus RTU sent message breakdown using https://npulse.net/en/online-modbus

These are created from https://npulse.net/en/online-modbus which has some great tools to help with this process. If you wish to return a response from Serial Debug Assistant, you can enter this and hit send:

01 03 02 00 34 B9 93

This response just returns some random data (in this case the decimal value 34).

Modbus RTU response message breakdown using https://npulse.net/en/online-modbus

Later, we will add a lot more meaning with how we handle use this. For now, however, we just want to make sure we have data correctly moving into and out of the Arduino. 

Invertek Optidrive E3

As I have mentioned before, the RJ45 port on the front of this particular VFD is NOT an ethernet port. This port, though, gives us access to the A/B lines for RS485. I made part of an ethernet cable and left the wires on the other end exposed. I decided to align the ethernet cable according to T-568B wiring spec, but for this it doesn't really matter, just make sure your using the correct wires positions as they are described in the manual. For this project, I clipped everything that wasn't wire 3 (GND), or wires 7/8 (A/B lines). I have no desire to accidentally connect something with 24v :). 

Page 36 snippet from the Invertek Optidrive E3 Manual

The manual also will tell us how to setup the configuration for our VFD. Specifically, we need to make sure the values are setup correctly for P-36 (parameter 36). You can hold down the top center button on the VFD to enter into a settings mode, then using the arrow buttons, navigate to P-36, how click the same center button as before, it should change to show Adr 1. Clicking the same center button will let you cycle through all the settings for this parameter group. Make sure these settings match the ones from before (i.e. Baud 115200 [shown as 115.2]). The manual describes the other settings needed for this connection. 

Now let's remove the MAX485 and Arduino connection from our USB TTL/RS485 adapter and instead connect our ethernet wires up. Although slightly confusing, when the manual says RS485+, this is the same as A, and RS485- is the same as B. 

With everything connected properly (and double-checked), let's turn on the VFD and plug in the USB TTL/RS385 adapter. Open Serial Debug Assistant and make sure to connect to the adapter again with the same settings as before. 

Now in this configuration, the master device is going to be the PC and the slave device is the VFD. So we need to be first to send data to the VFD to have it respond. Let's send a request to see what the temperature of the VFD is. In the input area, enter:

01 03 00 39 00 01 04 0D

Now hit enter. If everything is working as it should, you should immediately get back a response like the one we sent out before. The data portion of the message should represent the temperature of the VFD.  

Connecting Everything Together

As you probably have guessed by now, we are going to connect the MAX485/Arduino directly to the VFD. The USB TTL/RS485 adapter won't do us much good here (unless you want to man-in-the-middle like I did), but by using the Arduino serial monitor, we can query any of the read registers on the VFD. We can also set new values for write registers. 

You should now have a working connection and communication between Arduino and the VFD. 

Hopefully you found this helpful, but feel free to ask questions. Fair warning, I do not know anything about other VFDs and would do exactly what you would (look in the manual) to try and figure it out. If you want to hire me to read your VFD manual, I suppose you could :). If there is no manual, I'm not aware of any easy shortcuts to figure out the connections. My advise would likely be to start with a multimeter and try to find voltage and ground, then operate the VFD and take measurements, maybe use an oscilloscope, and see what you can deduce. Although, it would probably be cheaper considering time/cost to just buy a VFD that you know has support for Modbus and has a good manual.

Support the Developers

If you find the free software referenced above useful, make sure you try to find ways to support those developers as that will go a long way to making sure these tools stay awesome for everyone.

Getting a TimedOut error in ModbusMaster (226)?

At first, I tried to connect everything with the baud rate 19200, and everything was working fine except that the responses back to Arduino would timeout every time. It turns out that there is a set amount of time to get a response, and if it doesn't happen quick enough, the library will timeout. You can modify the code, or in my case, I just increased the baud rate to 115200 which happens to be the default value for the VFD anyway. This change has been working well.

Flaky data transmissions? Random transmission failures?

My first attempt at this used SoftwareSerial to replicate a hardware serial with hopes that I could use an Arduino that did not have Serial1 or so on. After hooking my USB TTL/RS485 adapter into the communication between Arduino and the VFD, I found that all the values being exchanged were actually correct, but my Arduino program would randomly report bad CRC, TimedOut, or other errors. As I had already had a bit of trouble with the TimedOut error before due to timing, I determined this is likely also an issue with timing, but one I'm not sure I can code to fix. Instead of messing with all that, however, I decided to change my Arduino UNO R3 board for an Arduino Mega2560. The mega is a more capable board and possibly overkill for what I'm doing, but I had it on hand and I knew it has additional dedicated hardware Serial. After a quick update to my code (trading out SoftwareSerial for Serial1), and a switch over on wiring to use RX1/TX1 GPIO on the mega, I was up and running. The flaky communication issues from before have been resolved. 

VFD Doesn't Start / Register Values Don't Return Correctly

One thing to note is that ModbusMaster uses a zero-based addressing system for registers, but the E3 uses a 1-based addressing for registers. This means you need to subtract 1 from the register listed in the documentation to properly.

In the E3 documentation, it states:

NOTE For Master devices which use zero based addressing and therefore treat the first Register address as Register 0, it may be necessary to convert the Register Numbers detailed below by subtracting 1 to obtain the correct Register address.

Example Code:


Resources and Links:

https://npulse.net/en/online-modbus (Modbus protocol tools online)

https://www.circuitstate.com/tutorials/what-is-rs-485-how-to-use-max485-with-arduino-for-reliable-long-distance-serial-communication/ (comprehesive look at RS485 and MAX485)

https://github.com/4-20ma/ModbusMaster (Arduino Library for MAX485)

https://www.microsoft.com/store/productId/9NBLGGH43HDM?ocid=pdpshare (Serial Debug Assistant)

https://inverterdrive.com/file/Invertek-Optidrive-E3-Manual (VFD Manual)

https://www.wolfautomation.com/media/pdf/ac-drives/invertek/ode/invertek-e3-an-ode-3-038-21.pdf (VFD Manual - Additional details, like corrected Modbus register map)

https://github.com/4-20ma/ModbusMaster/issues/127 (ModbusMaster timeout error)

https://www.youtube.com/watch?v=owxWr8vdzSM (An example of sending data to the VFD)

Monday, October 16, 2023

Digispark ATtiny85 AVR USB Connect/Disconnect - Programming the Dev Board

I bought a couple little ATtiny85 development boards a while ago and I've used them in little projects here and there, like creating a 3D printed stoplight with my son. It's a great little AVR board with 5v pins making it ideal to work with. 

ATTiny85 Development Boards

Recently, I decided I would build an Arduino-based useless box for Halloween, and as I only need 3 pins (2 with PWM to control servos and 1 for the switch) and doesn't require a lot of memory or power I thought this might be a good option.

When I went to upload a sketch to the board, I found that the board would connect and quickly disconnect. 

After reviewing several websites and YouTube videos walking through the installation of digistump drivers and adding the board to Arduino IDE, all of which I had already done, I finally found some guys with a video showing the same problem I was having.

In this video, they begin the upload process for the board before connecting the board. Once the compilation has completed, the console will direct you to plug-in the board and then it will continue uploading the program as you would expect.

Note: For PlatformIO, just make sure to define your board correctly, leaving the com ports blank and the port selection set to auto. Everything else should be basically the same as from the Arduino IDE.

platform = atmelavr
board = digispark-tiny
framework = arduino

It seems that the bootloader takes command of the TX/RX lines at the very beginning of the board boot waiting for a packet indicating an intention to program, if this does not appear within a short amount of time, the bootloader seems to start up the ATtiny MCU as it is. Feel free to educate me if you know more or would like correct my thinking here. 

For even simpler projects, you can buy just the ATtiny85 chips and a programmer board. Programmer boards vary greatly in price, but if you want to go cheap, you could even connect an existing ATtiny85 development board with a de-soldered MCU chip, and then wire it up to a breadboard to program more chips. That is essentially what is happening here.


Sunday, October 1, 2023

Clue - The Great Museum Caper - Maps Printables

My wife has had this game since she was a kid. We went to play it today and I found that there are only so many maps available for the thief. I figured I would make some more and make sure they are small sheets so they can be discreetly obscured by the thief's shield. 

First, I found an image that from boardgamegeek.com, and took it into Photoshop to clean it up and make a 6-sheet PDF from it.

Lastly, out of curiosity, I tried an online vectorizing service, vectorizer.io, which did an awesome job with it making an SVG

Wednesday, September 27, 2023

Fixing, Updating, or Removing Sound Libraries in DaVinci Resolve / Fairlight


Sometimes our sound files get moved around or possibly removed, but as of DaVinci Resolve 18.6 managing your sound library is still a bit challenging. In my case, I had files that were removed but they continued to show up in my searches, they just would not playback and were obviously unusable. 


Note: this solution requires modifying a program database in a way which could interrupt the proper functionality of your application. While I take steps to try and prevent any corruption, I admit I do not fully understand everything Resolve is doing with that database and this could have side-effects. If you find your file has been corrupted beyond repair, a clean install may be required. My results have been successful, but you are doing any of these things at your own risk.  

Resolve stores your information relating to your local sound library in a SQLite database. If for some reason your setup is different than mine (like for instance if it is being stored in Postgres), I imagine many things will translate, but it won't be exact and you will need to do the research required to handle that situation. 

The first thing you need to do is find the SQLite database where the sound information is stored. You can do this by opening the Project Manager window, and in Local Database, right-click and choose Open File Location.

The folder that opens will contain a folder called Resolve Projects, open that to find a SQLite file called SoundLib.db. Now close down DaVinci Resolve. Start by making a copy of this file! Name it something like SoundLib_bkup.db. It's good practice to never mess with the working version of something so that you can restore the working copy later if something goes awry. With your back-up file securely in place, the easiest way to edit our working database SoundLib.db is to use a visual database program like SQLiteStudio (which is free and open source) and then connecting the SQLite database. Once connected, you should see a list of tables like these on the left-hand side.

A database is a way to organize data. With SQL type databases, it is often best to think of it like spreadsheets, where one spreadsheet is a table. The tables we are looking for start with FLAsset which I assume stands for Fairlight Asset. 

If we double-click on FLAssetBaseClip table and click the Data tab at the top, we see a table (or spreadsheet) or information associated with these assets. 

Now double-click on the FLAssetBaseContainer table, then click the Data tab again to see what is in the table. You should see one or more rows. One column is called path and seems to contain all the paths Resolve is using to search for media.  Note the FLAssetBaseContainer id. This is the ID associated with individual media assets so that they can have a relationship (or association) with each other. 

For me, the path no longer valid is D:\CorrLabs Drive Backup\Video Resource\Fairlight Sound Library

Fortunately, the tables are set up with cascading actions, which means if we remove one record, it can trickle some effects down into other tables helping us clean things up. We are going to leverage this to make our job simpler. With a SQLite file backup in place, click the row you wish to delete and then click the red icon with a line through it (on hover it will say: Delete selected row). 

Once you click this, the row will blank out. This is a preview of the action that is about to take place. If you selected the incorrect row, you can click the red icon with a white X (rollback) on it to undo that. If you have the right row selected that you wish to continue to remove it, click the green icon with a white checkbox. This will make your change to delete this row. 

Now the FLAssetBaseFile table will have lost the container_cookie reference (which is actually the ID we noted earlier), so let's go clean those records up. Right-click on the FLAssetBaseFile table and choose Generate query for table -> SELECT.

Delete the existing query (SELECT...) and paste: 
DELETE FROM FLAssetBaseFile where container_cookie is null;

And now hit the blue play icon at the top of the query window to run it.

The Status window will give us insight into how many records were removed. 

Now you can disconnect from your SQLite database (the plug disconnecting icon near the top left), close your SQLiteStudio and launch Resolve.

The sounds associated with the old library location should no longer appear in Fairlight!

For Errors: If you ran into an error during this process, first close the SQLite editor (SQLiteStudio) and Resolve without saving anything. With those programs closed, rename the SoundLib.db file to something like SoundLib_bad.db, and rename SoundLib_bkup.db (created from before) to SoundLib.db and restart Resolve. You should now (hopefully) have a sound library state that was the same as before any of this process took place. 


Saturday, September 16, 2023

Driving a Max98357 with an ESP32C3 single processor arduino


For part of a hobby project, I wanted to replace a piezo buzzer with a speaker. I have heard Arduino can drive speakers directly with PWM (never done it myself), but instead I decided to add a max98357 amp and leverage the ESP32 I2S capabilities to drive it using the Arduino Audio Tools library. 

After first connecting things up, as most people do (all GPIOs should work the same for ESP32), I went to play an audio file from littlefs. The noise produced sounded nothing like the MP3 I was trying to play. To remove some complexity, I changed my code to instead produce a sine wave using the libraries generator functions. The result of this was kind of a really crackly sine tone. One thing I noticed early on was that there was a periodic clicking/popping sound that seemed pretty consistent. I went through and switched out the amp, the Arduino, and the speaker in an attempt to figure out what was causing the problem. A larger speaker helped add some clarity to the tone, but didn't get rid of the clicking noise. I also reduced the sine wave amplitude effectively reducing its volume to make sure it wasn't something to do with peaking. My code looked kind of like this at the time:

AudioInfo info(44100, 2, 16); // sample_rate, channels, bits_per_sample
SineWaveGenerator<int16_t> sineWave(32000);                // subclass of SoundGenerator with max amplitude of 32000
GeneratedSoundStream<int16_t> sound(sineWave);             // Stream generated from sine wave
// CsvOutput<int32_t> out(Serial);
I2SStream out;  // Output via I2S
VolumeStream volume(out);
StreamCopy copier(out, sound);

The VolumeStream did not work at the moment, not sure why. Changing the 32000 value reduced the volume of the tone just fine. 

The speakers I ultimately wanted to use for this project were tiny 10mm or 15mm loud speakers, which seem to get hot after running for some time. I guessed that the crackling sound could be straining the speaker and contributing to this issue. 

Finally, after playing around with DMA buffer counts and sizes, I tried reducing the sample rate (as referenced by the author of Arduino Audio Tools blog). That seemed to help solve the crackling/popping issue.

After running the tiny speakers for a little bit with the sine wave tone, they still seem to get hot, but if I only use the speaker periodically and for short form things, I think that will work ok. 

Next I needed to get audio files playing back from littlefs, and possibly using the MP3 decoder or Orvis decoder to keep my file sizes small. We'll see how this little chip can handle loading and playing back files with decoding on top of the other processes. 

Saturday, September 2, 2023

PIO Adding a New Board for Lolin ESP32-C3 Pico

There is a sense that things are right in the world when things are just like they should be. One such instance is declaring an Arduino board that has not been done so yet. 

Fortunately, the board is fairly similar to another board, so my work was minimal. But here is what I had to do:

Add a new JSON file for the board:


In this file I had to update some values like name and variant. Also, I double-checked the board hardware IDs, CPU, flash, and upload settings.

The variant name is used to find the additional files used by these boards. In my case, it is just one file, pins_arduino.h, which I added here:


Note the folder name matches the variant name from the JSON file before. The data for that file had to be verified by looking at the published specifications for the board.






https://www.espressif.com/sites/default/files/documentation/esp32-c3_datasheet_en.pdf (ESP32-C3FH4)

https://www.wemos.cc/en/latest/c3/c3_pico.html (pins)


The Lobster Pickleball Machine Power Chargers and Batteries

These are my personal notes. Apply at your own risk. 

Note: Although the found label on the wall wart says 13V, at least one motor and the battery are all 12V which but one motor might be 12.5VDC. To be safe, I imagine it is probably better to under-voltage a device than overvoltage.

We went to sell the Lobster Pickleball Machine and could not find the power supply.

Standard Chargers

The information is a bit tough to find online. Even the machine itself does not list the power specifications which is unusual. After a lot of searching, I finally found a video showing the specs of the standard charger. As you can see, it says it is 13VDC or 13 volts DC and 1 Amp (1000 mA).


13VDC and 1A w/ Barrel Connector (source: YouTube video

Standard Charger w/ XLR Connector

Input: 120 VAC 60Hz 16W
Output: 13VDC 1A
Model: DV-1280-5
Connector: Male 3-pin XLR or Male Barrel 5.5mm x 2.5mm (or possibly 5.5mm x 2.1mm; but 2.5mm felt snug)

Similar power supplies from many Chinese suppliers are about $15-$20 on Amazon but the reviews can range widely as to their effectiveness. At the time of writing, Lobster Sports sells the Lobster Standard XLR Charger for about $35. The website says this comes standard on all Lobster Pickleball Machines, like The Pickle, The Pickle Two, and The Pickle Champion and will work on any machine purchased since January 2009. The Lobster seems to come with both a barrel jack charging port and an XLR style connector port.  
5.5mm OD and 2.5mm Male Barrel Connector

Premium Chargers

Premium charger from Lobster Sports currently sells for about $150. 

Lobster 3-Amp Premium Charger w/ XLR Connector

Premium Charger w/ XLR Connector

As far as I can guess, the premium charger is likely 13VDC 3A, allowing the device to charge quite a bit faster. Also, the premium charger has trickle charge capabilities, which tend to be better for the health of battery and can stay plugged in all the time. The connector on these chargers seems to often feature an XLR-style male connector. One reviewer on Amazon said he had luck with a $30 similar option, the "SONEIL CHARGER 1206SX2 100-240VAC IN 12V 3A OUT 3 PIN XLR CONNECTOR POWER SUPPLY." Not sure if trickle-charge logic would make exact voltage more important. 

Input: 100-240 VAC ~1.5A (MAX) 50/60Hz
Output: 13VDC(?) 3A (not sure on voltage but I assume it would be the same)
Model: ?
XLR Socket Replacement Part Model #E886


The battery inside the Lobster machines is a fairly standard rechargeable battery. Lobster Sports sells it for $85 and lists it as compatible with Elite One, Elite Two, Elite Three, Elite Four, Elite Five, Elite Five LE, The Pickle Two, and The Pickle Champion. These look similar to Power Sonic batteries which end up being a bit cheaper with similar specs. 

Inside our machine, The Pickle, I found this battery, a Zeus 12v 9Ah. Lobster Sports sells this style battery for: Elite Freedom, Elite Liberty and The Pickle.

Zeus 12v 9Ah Battery from The Pickle

Manufacturer: Zeus (confirmed) / Power Sonic (?)
Type: Lead Acid
Amp-hour: 9Ah (maybe some are 18?)
Voltage: 12V

12V Feeder Motor

This server motor almost looks like it's 12.5VDC but is hard to read.

Troubleshooting (See video)

Red/Green Blinking Light on Power Supply - Faulty charger

Charger light stays green on plugging in - Battery may no longer hold a charge, and should be replaced

Double check battery terminals under the plate to ensure proper connections


https://www.lobstersports.com/products/standard-charger (product page)

https://www.lobstersports.com/products/premium-charger (product page)

https://pickleballcentral.com/3-amp-premium-charger-for-pickle-ball-machine/ (product page)

https://www.youtube.com/watch?v=WHEmS4imDBs&t=158s (machine overview)

https://www.doittennis.com/lobster/ball/tennis-machine-xlr-charger-socket-replacement-part (product page)

https://www.amazon.com/Lobster-Sports-3-Amp-Premium-Charger/dp/B000XCOF0G (product page)

https://www.youtube.com/watch?app=desktop&v=g-MubGr--Qw (troubleshooting the lobster)

https://www.lobstersports.com/products/battery-large-12-volts-elite-one-elite-two-elite-three-elite-four-elite-five-elite-five-le-and-the-pickle-two (battery)

https://www.amazon.com/Power-Sonic-Genuine-PS-12180NB-Rechargeable-Battery/dp/B00BMUEN9Q (suspected battery for some machine?)

https://www.newark.com/zeus-battery-products/pc9-12sf2/rechargeable-battery-12v-9ah/dp/13AJ3015 (the battery mine had)

https://www.lobstersports.com/products/battery-small-elite-freedom-elite-liberty-the-pickle (battery for The Pickle)

https://europe1.discourse-cdn.com/arduino/original/4X/a/4/9/a4959e12c4f50653e7ec45ce0e252f422fdf1c93.jpeg (maybe the same motor as the 12.5VDC possible?)

Wednesday, August 30, 2023

Lolin esp32-c3 pico Notes (PIO, Qwiic Stemma QT)

I don't work on this often, so when I do, I feel like I'm having to go back and figure things out. These notes will hopefully save me some time.

The chip on these dev boards may require the installation of a driver for proper connection to your computer.


PIO platform.ini (first 4 lines)

platform = espressif32
board = esp32-c3-devkitm-1 ; or could use lolin_c3_pico if setup
framework = arduino
upload_port = com4
upload_speed = 921600
monitor_port = com4
monitor_speed = 115200

Digital Pins: just the digit (0, 1, 2,... -- number matches IO)

Analog Pin: A0, A1, A2, A3, A4, A5 (number matches IO)

I2C Pins:

static const uint8_t SDA = 8; //IO8

static const uint8_t SCL = 10; // IO10

Lolin I2C Port and Qwiic / StemmaQT (Not Compatible!) - both use 4 Pin SH1.0 connectors

Lolin:  VCC     SCL     SDA     GND

Qwiic:  Black   Red     Blue    Yellow

Lolin ESP32-C3 Pico I2C Connector

Qwiic / StemmaQT I2C Connector

Possibly could build a custom converter adapter - but probably easily just to use the board pin for IO8 & IO10 as they are the same pins unless you are connecting multiple Qwiic compatible I2C connections.

Upload Code

Make C3 boards into Device Firmware Upgrade (DFU) mode.

  • Hold on Button 9
  • Press Button Reset
  • Release Button 9 when you hear the prompt tone on USB reconnection


Make sure to check polarity of the battery before plugging it in! For my battery the JST polarity connections were backwards.





https://github.com/espressif/arduino-esp32/blob/master/variants/lolin_c3_mini/pins_arduino.h (similar?)

https://learn.adafruit.com/assets/113383 (stemmaQT/qwiic connector)



Monday, June 5, 2023

Nanlite USB-C DMX Cable Instead of Aputure USB-C/ DMX Cable?

Out of curiosity, and because they are nearly half the price of the Aputure USB-C/DMX cable, I really wanted to know if the Nanlite USB-C/DMX cable would work as a suitable replacement for the Aputure USB-C/DMX cable. After getting zero information from both Nanlite and US retailers (uh-hem... B&H), I decided to purchase one to see if the similar looking Nanlite cable would work instead. Here is what I found.

Unfortunately, the Nanlite USB-C/DMX cable uses D+/D- and GND to transmit DMX data, so it sadly is not compatible with the Aputure USB-C/DMX cable which uses A10/A11 (and B10/B11) and GND. 

Wednesday, May 10, 2023

PyInstaller - Include sv-ttk Sun Valley TTK Theme in build


Trying to build a python application using tkinter and ttk Sun Valley theme using pyinstaller, the finished build would throw errors unable to find the tcl file and related theme data. Pyinstaller does a pretty good job finding and including related python files and modules, but it doesn't do so well with other assets and this theme uses other assets.


The brute force method is just to include the tcl file and theme resources manually when building the program.

pyinstaller --onefile --noconsole --add-data "<path to python modules>\Lib\site-packages\sv_ttk\sv.tcl;sv_ttk\" --add-data "<path to python modules>\Lib\site-packages\sv_ttk\theme\*;sv_ttk\theme" .\main.py

This should produce the bundled application with the resource files all embedded where the scripts expect to find them. 

Thursday, March 23, 2023

Notes on Getting Python to Talk to FTDI FT232 chipset for USB Serial Communication

NOTE: This is incomplete and is nothing more than just notes for myself. It is not yet part of a complete solution and I don't fully understand all the consequences that may be involved. Follow at your own risk.

To get python to talk to FTDI FT232 chip for USB Serial Communication (Windows)

Replace the existing FTDI Driver with libusb-win32 using Zadig (Reference

Now the device shows up when searched for using VID and PID:

import usb
import usb.util
print(usb.core.find(idVendor=0x0403, idProduct=0x6001))

It WILL NO LONGER list under:

import serial.tools.list_ports

# List all available COM ports
ports = list(serial.tools.list_ports.comports())

# Print information for each port that is currently in use
for port in ports:
    if port.pid is not None and port.vid is not None:
        print(f"Port: {port.device} - VID: {hex(port.vid)} - PID: {hex(port.pid)} - Description: {port.description}")

but now pyftdi can now connect using VID and PID:

import time
from pyftdi.ftdi import Ftdi, FtdiError

    ftdi = Ftdi()
    ftdi.open(vendor=0x403, product=0x6001)

    while ftdi.is_connected:
            status = ftdi.modem_status()
        except FtdiError: