Simulated live radio station method:
Each simulated radio station is made up of a dequeue list of audio files, along with the length of each song.
Each day at midnight the code will randomize the stations. (Or sync them with local time if ordered)
As you tune across the dial, the code figures out which song should be playing, and what time in the song we should be, based on the amount of time that has past since midnight.
For example, if 15 minutes have elapsed since the start time, then the code will subtract the length of each song in the list from the elapsed time, and at the same time move that song to the end of the list.
Once the amount of remaining time is less than the length of the song at the top of the list, then the code drops into that song, at the point in time remaining in the calculation.
The radio stations loop automatically. They can also be dynamically randomized, skipped/rewound or otherwise altered in time without losing the live playback effects.
Time synchronized playback:
If two radios have the same time set, then they will end up with the same randomized list of song, meaning two radios can play the same list of songs.
Also, an ordered station can be set with a time offset, such that any playback of that station will be synchronized to local time. So hourly callouts or other time dependent playback will work properly.
Radio Station Tuning Method:
To allow for flexible tuning regardless of the number of stations, or the size of the radio dial, a feedback loop is used to determine what radio station to play, or whether to play static, or no station at all.
On the Pi Pico the tuning potentiometer controls the angle of the motor, linearly from the minimum angle to the maximum angle. This gives a perfect 1:1 feel for the movement of the needle and turning knob.
The code on the Pi Zero then monitors the motor/needle angle, and determines the nearest radio station to that angle. If the needle starts to move near the position of a radio station, it starts playback of that station, at a low volume level, while still playing static. As the user tunes closer to the station position, the volume raises, until the needle falls close enough to the station that it is considered "locked on", in which case the station plays at full volume with no static.
The area of "lock-on", partial playback, and static only is automatically setup depending on the number of radio stations present on the dial, as well as the range of the dial.
Using PyGame for the music playback allows for very fast tuning as it can stream the file from disk without caching the whole file, as well as drop into a particular timecode. The tuning occurs so fast that sweeping across the dial and hearing small blips of audio works just like a analog AM/FM radio.
Air core motor control method:
At first I tried using a typical low cost stepper motor, but even with half-stepping the movement looked like the second hand on a cheap watch, with very visible discrete steps for each movement.
I am now using a tiny Simco Air Core Motor. An air core motor is just a magnet attached to a shaft, with two coils would around it at perpendicular angles.
Setting the angle of the motor is a matter of controlling the SIN and COS coil voltages. This results in very smooth analog movement of the motor The challenge came when trying to find a dual H-Bridge motor controller to use. A normal dual PWM controller has issues when the coil is near any of the angle quadrants (0, 90, 180, 270 degrees). As the voltage on one of the two coils will drop to nearly zero.
The solution was to use a TB6612 dual H-bridge controller. This controller has separate digital inputs that control the direction of the motor, and a separate PWM input for each motor. This allows the voltage to remain near constant across the coils, and the duty cycle changes with the PWM input.