-
7/15 | boards from pcbway, improved sound effects!
07/15/2023 at 17:51 • 0 commentsMoving the circuit to PCB
I decided that this project is worth keeping around on a PCB, so I designed two boards in KiCad. I tried out PCBWay’s KiCad plugin for the first time, and it worked like a charm. It takes literally one click to generate all the fabrication files and upload them to PCBWay. Pretty cool!
I had made a few careless mistakes during layout (a handful of vias were tented, even though I wanted all of them to be open), which PCBWay thankfully caught and fixed for me. The boards still arrived within less than a week, and they are flawless:
For the main board, I went with what I would call an “educational” layout :). I imagined a circuit board you might see in electronics class at school. It’s easy to identify the subcircuits and there are lots of labeled test points to hook up your scope and look at waveforms. All components are through-hole because I already had all the parts that way. It is also era-appropriate for this circuit :) The accelerometer is an SMT part, but I’m using the SparkFun module which breaks out the pins to more convenient through-hole pads.
Here is the fully assembled main board:
And here is the fully assembled accelerometer board, mounted to the display:
The full system on PCB:
Improved sound effects
I couldn’t resist making a few tweaks to the circuit before hardening it on a PCB. The most significant one is better audio. The original approach of playing a 1kHz tone for the duration of the bounce was effective for how simple it was, but I somehow couldn’t dial it in to where lighter bounces really sounded lighter.
So I added a voltage controlled amplifier that varies the volume with the depth of the bounce. You can see the VCA in the bottom right of the main PCB. It’s a basic long tail pair with 3 NPN transistors, the schematic is shown below. The full updated schematics are uploaded here on hackaday.
I also decided to move the speaker from the main board to the display, so that the bounce sound effect comes from the right direction. This is shown in the picture below. I had to play with the positioning of the speaker a bit, since the strong permanent magnet can easily distort the CRT picture.
Fixed display flicker
I noticed a slight flickering in the display so I took a second look at the brightness signal coming at G1 of the CRT. It turns out the brightness voltage was not actually constant as I had hoped, but was periodically pulled down to completely black/off during what looks like horizontal and vertical blank (retrace) periods.
In retrospect, it makes sense, looking at the rest of the viewfinder schematic. I’m not quite sure why the ~60Hz vertical flicker didn’t show up more clearly in the videos I made earlier? Either way, to fix the issue I disconnected G1 from the video circuit and connected it to 12V DC (display power rail) through a 1M resistor.
Miscellaneous tuning
- Double checked the resistors that are parallel to the deflection coil to dampen ringing and decided to lower their value from 120 Ohms to 68 Ohms.
- Repurposed unused op amps in as additional virtual GND buffers
Updated demo video
Finally, I recorded another short video that shows the PCBified system. Enjoy!
-
6/5 | Finished system demo, analysis
06/06/2023 at 05:14 • 0 commentsIt is done! In today's update I will discuss the finished product (finished meaning for the hackaday op amp challenge, ideas for future work are listed below). I have a demo video of the system working and some deeper insights into how component values were picked and how the bounce logic works. I also finally wrote the high-level “Why this works” part in this project’s Details section.
Attaching the accelerometer to the display
As the final build step, I have replicated the accelerometer circuit on a protoboard and mounted it to the handheld CRT display. I 3D printed a rectangular frame to hold the protoboard and stuck it to the side of the display housing with double-sided tape.
The accelerometer is deliberately positioned close to the front of the display, where the screen is. That way, we always measure linear acceleration on the side of the housing where the simulated “box” is. The placement of the accelerometer wouldn’t matter if we only allowed translational movements or very slow rotational movements of the display. But it is unavoidable in practice, and quite fun actually, to “wiggle” the display (e.g. quickly tilt it up and down) to move the ball around. During these fast rotational movements, measuring linear acceleration at the back of the case would yield the opposite of what we expect to see on the front side where the ball is displayed.
The finished system
Random side note: I’m kind of proud of this technique I came up with for making a scrappy cable assembly with .1” header connectors and strain relief in a hurry: just cut a paddle-shaped support plate out of 2mm ABS and superglue the header and outer cable jacket to it. Works great :)
Demo video
Without further ado, here’s a video of the system in action. Make sure you have sound on, I find that the sound effect nicely adds to the illusion. I’m super happy how well this circuit performs!
Double-checking our simulation parameters
The motion equations for the ball are independent for each dimension (x and y) in our 2D simulation. Each dimension is modeled with two op amp integrators and four passive components, as shown in the schematic snippet below. The circuits for x and y are identical.
Note that this is for ball motion without wall collisions. We look at the bounce logic in the next section below.
I chose the values for R1, R2, C1, C2 by trial and error, such that the simulation “looked right”. The shown values R1=100k, C1=C2=.22u worked well, and I found it useful to leave R1 variable, to control how strongly the ball is affected by inputs from the accelerometer. Around 120k felt pretty good for R1.
But since we are measuring actual earth gravity and acceleration of the box, there should be a “correct” choice of parameters. Let’s do the math and see if the above values make physical sense.
Let’s use a(t), x(t) to describe acceleration and position in the real world, in meters, and v_a(t), v_x(t) to describe the corresponding voltages in our simulator. Here is the equation that relates acceleration to position in the real world
How do v_x (t) and v_a(t) relate to x(t) and a(t)?
- v_x to x: the display is 2x5.1V “wide” in our simulator and 28mm wide in the real world, so x / v_x = 1m / 364V, or x = (v_x / 364V) * m
- v_a to a: our accelerometer + signal conditioning produces about 1V per g, so we have a / v_a = (9.81m / s^2) / 1V, or a = (v_a / 1V) * 9.81m / s^2
Substituting these relationships into the real world formula we get
Dividing by the 1/V and m units, and combining constants, we get
Now we can compare coefficients to the integral equation of our simulator circuit, and find that 1/R1C1R2C3 must be 3574/s^2. The s^2 units checks out, because RC is in seconds, so RCRC is in s^2.
In our case, with C1=C2=.22u and R2=100k, what value does R1 need to be? It's 3574 * (.22e-6 *.220e-6 * 100e3) = 58kOhm!
Again, the value I picked experimentally to make the simulation look "right" was 120k. It about twice the theoretical value. But that's not too far off, considering part and measurement tolerances, and how closely you can expect to even judge physical correctness on this crude display.
One more interesting thing to note is that when the value of R1 is off, both earth gravity and accelerations caused by box movements are equally off. So if we wanted to simulate low gravity, we can't just make R1 large. I found the most convincing way to play with low gravity is to simply hold the display vertically (screen parallel to the floor). Then, earth gravity has no effect, but box acceleration affects the ball as before.
Deep dive into the bounce circuit
The bounce logic is shown in the inside blue box below. The op amp to the right is the first integrator of the motion equations we just discussed above. It takes the sum of the accelerations from the accelerometer (through R25) and from the wall bounce (through R26), and integrates them into the (negative) ball X velocity.
There are four bounce circuits like this, one for each wall of the box (or side of the display). The one shown here is the left wall and it works like this.
- While the ball is to the right of the left wall, XPos > VRef- (-5.1V), and the op amp output is at -100 x (-5.1V - XPos), which is likely at the negative supply rail, -7.5V. In that state D8 is reverse biased, so no current flows through R26, no bounce acceleration.
- When the ball crosses the left wall, the op amp output goes positive, 100 x the penetration depth. Now, D8 is forward biased and a bounce acceleration is applied to the velocity integrator through R26.
Effectively, the wall is like a mechanical spring (F = -kx) with spring constant k = 100 (R16/R12) that accelerates a ball mass proportional to R26.
I picked the resistor values as follows: I wanted a large R16/R12 ratio, so I made R12 small (10k), but not too small where it would present a significant load to the preceding circuits, and R16 large to get a strong bounce (1M), but not too large where the op amp output would saturate too often, as shown in the scope traces below.
While picking R26, I ran into some practical limitations of the circuit that are worth discussing.
In theory, if the wall acted like a perfect spring, the ball’s velocity would be exactly reversed during a bounce. The only thing that R26 should change is how “squishy” the bounce is. Larger R26 means larger ball weight, so the ball penetrates deeper into the wall and takes longer to reverse its velocity. So I expected that changing R26 would be a matter of just picking what looks best.
Instead, here is what I found
- Regardless of the bounce resistor values, there is always a substantial amount of damping present in my circuit, i.e. the ball always loses some energy with every bounce. Of course, some amount of damping is desirable for our simulation, since that’s what happens with a real ball as well. But it’s not obvious where damping happens in the circuit.
- Changing R26 did not only change the “squishiness” of the bounces, but also significantly affected the amount of damping: the least amount of damping was for R26 around 100k. Both decreasing and increasing R26 from there, resulted in more damping.
Here are scope traces for different values of R26 and an attempt to explain R26’s effect on damping. The traces were produced by holding the display with the bottom right corner pointing towards earth, then quickly rotating the box counter-clockwise so that the bottom left corner points down. This makes the ball fall along the full screen width down to the left wall. Here is the first experiment with R26 = 1k:
You can see the damping in the ball height (magenta) reducing with each bounce. The bounce acceleration (cyan) comes in very short spikes that reverse the ball velocity (yellow), until an equilibrium is reached where the bounce acceleration exactly cancels out the gravity pushing the ball into the wall.
Here is what happens as we increase R26:
A few observations:
- The minimum damping (highest bounces, magenta curve) occurs with R26=100k.
- As expected, larger R26 values make the bounces squishier, so
- bounce events take longer (wider pulses on the cyan trace),
- the ball pushes further into the wall (lowest point of magenta curve is at -5.1V for R26=1k and goes all the way down to the negative op amp rail for R26=1M)
- As the ball pushes deeper into the wall, the bounce op amp output saturates a lot (cyan curve goes to top rail).
Here is how I would explain the damping depending on R26 values. I’m not super confident about this, so I’d love to hear your thoughts:
- For large R26, both the position and bounce op amps outputs go to the rails, so our physics model is no longer valid. For example, during the first bounce with R26=1M, the ball hangs out at an artificially shallow depth, with an artificially low spring force. By the time it leaves the wall, it has barely picked up any of its initial motion energy.
- For small R26, the bounces are simply too short and we are limited by the bandwidth of our simulator. My guess is that in R26=1k example, the velocity has to change so quickl that the circuit simply can’t keep up, due to parasitic capacitances, slew rates, etc.
The value I ended up picking for R26 is 33k. It felt like a good compromise between squishiness and damping.
When you look at other ball-in-box implementations, you will sometimes see a “bleeder” resistor across C6, which is a way to implement damping more similar to air drag. I did experiment with this approach, but probably due to the bounce-related damping effect we just discussed, I didn’t find the bleeder resistor effective. Of course, it would be nice to be able to model damping during bounces more explicitly, rather than taking advantage of limitations and parasitics in the circuit. But that’s for a future project :)
Future work
I wanted to build this project for a while when the hackaday op amp challenge finally prompted me to actually build it. I’m happy that I got it working just in time! I’m going to take a break, but there are some things I’d like to get back to in a bit.
One thing that I didn’t get to do was really characterize and understand the CRT coil drive circuit. The resistors R43/R44 removed the ringing I saw initially, but also did occasionally see what looked like further stability issues (oscillations?). There is some good information on making compensation networks for deflection coils in this application note: https://www.apexanalog.com/resources/appnotes/an05u.pdf
Originally my plan was to build this on a PCB, but I ran out of time. I’ll probably still do that, since it’s a cool demo I’d like to keep ready to go after I clear my breadboard for other projects.
Thanks so much for reading!
-
6/2 | Schematics, full system test
06/03/2023 at 05:20 • 0 commentsIt’s alive! In today’s update I’ll be describing the complete circuit and post a short video of everything working together for the first time.
First things first, to make the CRT display easier to work with (see last update), I created this wire harness for it. It has 6 conductors, 2 for power and 2 each for horizontal and vertical deflection.
The circuit
The circuit is built on two separate breadboards, as shown in the photo below. The large main board has everything on it except for the accelerometer, which is on the small board. The small board will eventually be mounted on the display so it can measure the acceleration of the display (i.e. the “box”) as it is moved around in space. I’ll probably rebuild / solder the small board on a perfboard for that.
I have uploaded the full schematics to the schematics section of this hackaday project. I’ll briefly go over the different components now one by one, referencing the colored boxes in the breadboard photo. Each box has a corresponding section in the schematics, which has all the details.
Split supply and reference voltages (top left, red box)
The circuit uses a split supply with +7.5V, -7.5V, and a 0V ground reference. I don’t have a bench split supply so I’m feeding in 15V from my bench supply and splitting with a resistor divider to create GND halfway between the rails. This ground reference is buffered by an op amp and is only used for small loads, like deriving the VRef+ and VRef- reference voltages with 5.1V Zener diodes.
Accelerometer board (small board, blue box)
Nothing too much going on here, I use a Zener diode to set up the 3.3V power for the ADXL335 chip. The chip outputs 3 analog voltages proportional to the chip’s acceleration in 3 dimensions. Sensitivity is around 300mV/g, with 0g about halfway between the chip’s positive and negative rail. I use two op amps to first buffer the output of two dimensions, then amplify it x3 and add an offset so that 0g is at GND.
A few more details on the accelerometer board. I played with the lowpass filter capacitors but ended up using the default values from the breakout (100nF), which amounts to 50Hz bandwidth. I also tried another accelerometer chip, the ADXL326. It is the same as the ADXL335, but less sensitive. It detects up to +/-16g, instead of +/-3g. I first thought that shaking the display might create more than 3g acceleration, but that wasn’t really the case. So I stuck with the 335 and its +/-3g range.
X and Y physics logic (2 orange boxes)
The entire physics simulation happens in the two orange boxes. The physics behind the ball’s motion in X and Y direction are independent in this simulation, so there are two separate circuits/orange boxes, one for X and one for Y.
In each box, the bottom 8DIP chip makes up two op amp integrators: a first one that integrates the ball’s acceleration over time to produce velocity, and a second one that integrates that velocity over time to get the ball’s position.
At the top of each orange box is the “bounce circuit” (2 op amps each). This circuit detects collisions with the top/bottom or left/right edges of the screen and provides the force that accelerates the ball back in the opposite direction, much like a spring. For example, when the ball’s X position goes over the right side of the screen by a few mV (full screen width is set by VRef- and VRef+, or -5.1V to 5.1V), the bounce circuit will produce a large negative voltage, 100x the penetration depth (set by R11 and R15 in the schematics), which is fed to the acceleration input for X and makes the ball bounce back to the left.
I hope this short description makes some sense. I want to quickly cover the overall circuit today and plan to dive deeper into the choice and physical interpretation of components and values in the next update.
Bounce sound trigger logic (2 green boxes)
Yes, there is a bouncing sound effect :) I’ve seen this in other ball-in-box implementations and IMO it adds a ton to the realism of the simulation. Definitely worth the few additional parts.
The bounce sound effect gets triggered when the bounce force (see physics logic) exceeds a threshold, set by a trim pot. The bounce sound is simply the 1.3kHz oscillator signal that is also used to draw the ball on the screen.
Loudspeaker and driver (white box)
When a bounce sound is triggered, the 1.3kHz tone from the oscillator gets amplified and played through this speaker.
Sine wave oscillator (yellow box)
The main purpose of this circuit is to create a time-varying X and Y position signal to draw a round ball on the screen. It is a 1.3kHz sine wave and a corresponding cosine, or 90 degree shifted version, generated by a standard phase-shift oscillator plus a tunable phase-shift circuit. The sine and cosine output of this oscillator circuit are added to the ball's X and Y position from the physics circuit, which results in the CRT drawing a circle at the position of the ball. The oscillator is also used to create the bounce sound effect (see above).
CRT deflection driver (cyan box)
The X and Y position from the physics logic (with the ball sine/cosine signal added) directly drive the horizontal (X) and vertical (Y) deflection coils of the CRT. I’ve shown in the last update how to drive the coils in principle, more details are in the schematics. There are three push-pull stages: one to drive the X coil, one to drive the Y coil, and one as a current return path (GND) for both X and Y coils.
It takes a lot of current to drive these deflection coils. To hold the ball at the left or right edge of the screen, the horizontal coil must carry 180mA DC. The coil’s DC resistance is only 4 Ohms, that means most of the 15V supply voltage drops at the top and bottom side drive transistors, about 1.2W per transistor! That’s why these transistors have heatsinks. They still get quite hot during operation.
A few more details: I noticed some ringing in the coil current that stopped when I added a damper resistor in parallel. Fun fact, in the photo you can see these ½ W resistors. They are 1/2 W because I thought they were getting hot, but it was just the proximity to the transistors. They dissipate tiny amounts of power, a ¼ W resistor is totally fine here.
Display power supply (magenta box)
This is just a 7812 voltage regulator to bring the 15V supply voltage down to 12V, to power the Sony viewfinder.
The video
Here’s a video of the complete system working for the first time. Apologies for the portrait video, but that was the easiest way to get both the moving accelerometer board and display into the shot. I’m super stoked it all works as intended!
Next steps
- Attach the accelerator board to the display. I will probably rebuild the circuit on a perfboard and add the accelerometer-to-mainboard cables to the display’s wire harness.
- Record a fun video of the final system
- Write up more details on how the physics circuit works, maybe show some scope traces
- Write up the math / theory behind the physics
- Write up what didn't get done in time, possible future work
-
5/29 | Initial log entry, CRT bring-up
05/29/2023 at 22:26 • 0 commentsThis is my first log entry. At this point I’ve spent a couple evenings testing the feasibility of the idea with a 1D version of the circuit on a breadboard. It doesn’t perform too well yet, but it does render a ball on my tiny CRT, and the ball can bounce off the floor and ceiling. Over the next few days I plan to optimize and clean up the circuit, so I can draw the schematics and share them here.
For this update I’ll focus on the part that is more “done” already, which is the display. The display is a modified Sony DXF-801 viewfinder. You can find them for $20 on eBay. To fit our purposes, I cut most of eyepiece off with a hacksaw. I also cut off the clamp in the back.
Using a service manual I found online, I looked up the power pins on the 20-pin connector (it needs 12V, 2.1W). From the schematic it appears fine to leave all other pins disconnected. Indeed, it powered up fine, and showed static on the screen. Yay!
To connect the CRT to our simulator circuit, we need to drive the horizontal and vertical deflection coils. The picture below shows the coils disconnected from the main board, highlighted in green. We’ll leave the other CRT connections alone (highlighted orange and red), those are for biasing the tube with high voltage:
The orange connector also carries the heater and grid 1 (H1 and G1) voltages, which determine the brightness of the dot on the screen. I will leave that part of the circuit unmodified for now, and just use the external “bright” control knob, since it lets me turn down the brightness to basically darkness. Brightness control is important, because in normal viewfinder operation, the energy in the electron beam lights up the entire picture. If we instead make the CRT draw just one dot, the brightness of a full image is now concentrated to one point. We need to set the brightness very low, or we could damage the CRT.
Let's look at the deflection coils next. Our analog computer produces X and Y voltages that normally connect to an oscilloscope in x-y mode. For example, 0 Volts for X means horizontal center of the screen, more positive is more right, more negative is more left, etc.
With magnetic deflection coils, the beam angle is proportional to the current, not voltage. And since deflection coils are inductors, the current through them is i(t) = 1/L * \int v(t) dt. So we can’t just apply our X and Y voltages to the coil and expect the current to be proportional, like in a resistor. Instead, we need to produce a drive voltage that causes the coil current to follow the path we want. This is the perfect job for an op amp in the configuration below:
The scope traces here show the desired deflection waveform Vin (yellow), the resulting drive current waveform Vsense (cyan), and the drive voltage Vdrive (magenta) produced by the op amp. The yellow and cyan waveforms are identical because the negative feedback loop ensures that Vsense = Vin, and therefore, Idrive is proportional to Vin.
NOTE: the circuit above is simplified to illustrate the feedback mechanism. The real circuit doesn’t drive the coil directly from the op amp; there is a push-pull transistor stage in between. A fair amount of current is needed to deflect the beam all the way to the edges: about 50mA vertically and about 200mA horizontally. I’ll post the full schematics once I have finalized them.
Finally, we have a ball on the screen! To waveform used to draw the ball in the picture below is a 1.3 kHz sine wave, with 90 degrees phase shift between X and Y.
Ok that’s it for today's update. Here’s what I’m planning to do next.
- During testing I destroyed a 2N3904 transistor driving the CRT deflection coils. I ordered beefier transistors, they came today.
- The ball on the display is not perfectly round near the corners of the screen. It’s not the most important thing to fix right now, but it bugs me, so I will try.
- Finish the rest of the circuit, e.g. add missing bounce logic in 2nd dimension.
- Dial in the simulation parameters, like mass, gravity, spring constants for the wall bounces.
- Draw up schematics
- Rebuild the circuit with better / tighter / cleaner layout
- Document operation and record video