Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
The general idea is to cut a USB extension cable (Type A plug on one end, Type A receptacle on the other) in half, splice the two data wires, splice the ground / common wire, but connect the +5 V wires to a dual banana plug that goes into a current meter. The Big Box o’ USB Junk produced a cutoff cable end with a Type A plug and a PC jumper that was supposed to connect an internal USB header to the back panel; the red blob of silicone tape conceals the jumper’s socket strip and a five-pin male header with all the wires soldered to it.
You could use a Type B plug that would go directly into an Arduino UNO (or similar), but I figured this way everybody can bring whatever cable they need for their particular Arduino, not all of which have bulky Type B receptacles these days.
The External Power version:
External Power Current Tap
The coaxial power plug goes into the Arduino and whatever you used for power goes into the socket. The Big Box o’ Coaxial Power Stuff actually had a more-or-less properly sized coaxial jack with two wires on it and silicone tape wrapped around it; I regarded that as a Good Omen and pressed it into service as-is.
These will also replace the horribly rickety collection of alligator clip leads I usually use for such measurements…
Rather than start with the stepper, I wired an LED and resistor between output bit 07 and Field Ground at the power supply:
Mesa 5i26-7i76 with LED
It’s worth noting that the terminals labeled GND on TB2 and TB3 are isolated from the Field GROUND terminal on TB1. When Mesa says “isolated power supply”, that’s exactly what they mean.
The digital output bits connect +24 VDC Field Power to the load, which should then connect to Field GROUND. I picked a good-looking 5 V panel LED from the pile, simply because it had wires soldered to it from a previous life, and put a 1 K resistor in series to drop the other 19 V.
Then you start up HAL, load the Mesa drivers, and twiddle the bit:
The thread runs with a 1 ms period, mostly because it’s convenient. The .read and .write pins transfer data from and to the 5i25 FPGA each time the thread runs; if you forget those, nothing happens.
Setting the output bit true activates the output bit, turns on the MOSFET driver, and connects the terminal to Field Power = 24 VDC. The 7i76 outputs do not sink current, they source it.
A journey of a thousand 3D printed objects starts with a single LED…
The watchdog timer ought to be connected to something more fragile and UI-related than the main thread, but I haven’t figured out how to do that yet.
Unlike most Arduino courses, I assume you’re already OK with the programming, but are getting tired of replacing dead Arduinos and want to know how to keep them alive. The course description says it all:
Learn how to help your Arduino survive its encounter with your project, then live long and prosper. Discover why feeding it the proper voltages, currents, and loads ensures maximum Arduino Love!
Ed will describe some fundamental electronic concepts, guide you at the workbench while you make vital measurements, then show you how to calculate power dissipation, load current, and more. You’ll understand why Arduinos get hot, what kills output bits, and how you can finally stop buying replacements.
Among other lab exercises, we’ll measure the value of the ATmega’s internal pullup resistors, which everybody assumes are 20 kΩ, but probably aren’t. Hint: you can apply Ohm’s Law twice to that simple circuit and come up with the right answer, but only if you’ve measured the actual VCC voltage on the board.
The Mighty Thor will detail how to not prepare Fried Raspberry Pi.
In the unlikely event you’re in Highland NY, stop by: you’re bound to learn something.
I wound up doing an impromptu magnetics (as it applies to transformers) review during a recent SqWr meeting. This summarizes, re-orders, and maybe expands on some quadrille paper scribbling, so that if I ever do it again I’ll have a better starting point. Searching on the obvious terms will produce a surfeit of links; Wikipedia may be helpful for diagrams.
Corrections and further points-to-ponder will be gratefully received…
Magnetizing force H comes from amp-turns (amps I, turns N) around the core, which produces flux phi = Φ = NI.Edit: that’s not quite right. Thanks to Martin Bosch for catching the units mismatch!
Magnetomotive force ℱ comes from ampere-turns (amps I, turns N) around the core: mmf = ℱ = NI.
The magnetizing force H is the mmf per unit length of the solenoid or core: H = ℱ / L.
Flux density B comes from permeability (mu = μ) times H, which is a DC relationship that doesn’t care about frequency in the least: B = μH. For an air-core inductor or transformer, μ is the mu-sub-zero = μ0 of free space, but if there’s a core involved, then you use the permeability of the material near the conductor, which will be the material’s dimensionless relative permeability μR times μ0.
Total flux Φ is the integral of flux density B over all the little areas covering the surface you’re interested in, oriented in a consistent manner using the right-hand rule.
If you have an iron(-like) core inside the coil, then essentially all the flux is in the core, so the integral reduces to B times the area (call it a) of the core at right angles to the flux: Φ = Ba = μaH. In this case, μ is the relative permeability of the core times μ0 of free space.
You can plot BH curves (B for various H values) using a straightforward circuit and an oscilloscope. The X axis voltage is proportional to the winding current I and the Y axis voltage is proportional to Φ. The trick is the integrator on the secondary that converts EMF = dΦ / dt into a voltage directly proportional to Φ. The same trick works on inductors if you add a few turns to act as a secondary.
All that’s true for DC as well as AC, but transformers only work on AC, as summarized by Lenz.
The induced EMF is proportional to flux change through the secondary windings, which number n turns: EMF = – n dΦ / dt. That’s obviously proportional to frequency: higher frequency = higher EMF. Flux is all in the transformer core, so it’s still μaH. Note that these are secondary turns, so it’s n rather than N. Air-core transformers exist, but coupling the flux poses a problem; looking up variometer or variocoupler may be instructive.
The negative sign says the induced EMF creates a current that creates a magnetic field that points the other way, so as to oppose the original field change. In effect, the induced EMF works to cancel out the field you’re creating.
Knowing how much EMF you need in the secondary for the purposes of your circuit, you know the product of five things:
n – secondary turns
μ – (relative) core permeability
a – area
f – frequency
H – from primary
Now you get to pick what’s important, but they all have gotchas:
The ratio n:N seems easy to control, but it tops out at a few hundred. If you care about the voltage ratio, then that fixes the turns ratio.
Choose different core material to increase μ, but then you hit core saturation in B as H increases. Practical core materials may give you permeability over two or three orders of magnitude, but with significant side effects.
Reduce B for a given Φ by using a larger core area a, which obviously requires a bigger core that may not fit the application.
Increase frequency f to get more EMF and thus H, but it may be limited by your application and other losses and effects. Higher frequency = more traverses of that BH curve with hysteresis = more core losses = can’t use lossy metals.
Increase primary H, but again you hit core saturation in B.
The circuit driving the primary must be able to handle the total load, which means it must be able to drive the impedance presented by the transformer + secondary load. That determines the primary inductance (to get the reactance high enough that the transformer presents the secondary load to the primary circuit), which determines the core + turns at the operating frequency.
The core must support the flux required to drive the load without saturation, which constrains the material and the area. For heavy loads (i.e., “power” transformers), output power also constrains the secondary turns and wire size, which constrains the minimum core opening and thus overall size.
Dan Newman’s TC4Server turns the TC4 thermocouple board into a USB HID input device that’s compatible with HAL’s hal_input module:
TC4 on ProtoScrewShield on Leonardo
For simplicity (i.e., to avoid writing a special driver), TC4Server misrepresents itself as a nine-axis joystick-like device suited for RC airplane control:
halrun
halcmd: loadusr -W hal_input +A Leonardo
halcmd: show
... snippage ...
Component Pins:
Owner Type Dir Value Name
5 s32 OUT 2941 input.0.abs-rudder-counts
5 s32 IN 4095 input.0.abs-rudder-flat
5 s32 IN 255 input.0.abs-rudder-fuzz
5 bit OUT TRUE input.0.abs-rudder-is-neg
5 bit OUT FALSE input.0.abs-rudder-is-pos
5 float IN 32767.5 input.0.abs-rudder-offset
5 float OUT -0.9102464 input.0.abs-rudder-position
5 float IN 32767.5 input.0.abs-rudder-scale
5 s32 OUT 2947 input.0.abs-rx-counts
5 s32 IN 4095 input.0.abs-rx-flat
5 s32 IN 255 input.0.abs-rx-fuzz
5 bit OUT TRUE input.0.abs-rx-is-neg
5 bit OUT FALSE input.0.abs-rx-is-pos
5 float IN 32767.5 input.0.abs-rx-offset
5 float OUT -0.9100633 input.0.abs-rx-position
5 float IN 32767.5 input.0.abs-rx-scale
5 s32 OUT 65535 input.0.abs-ry-counts
5 s32 IN 4095 input.0.abs-ry-flat
5 s32 IN 255 input.0.abs-ry-fuzz
5 bit OUT FALSE input.0.abs-ry-is-neg
5 bit OUT TRUE input.0.abs-ry-is-pos
5 float IN 32767.5 input.0.abs-ry-offset
5 float OUT 1 input.0.abs-ry-position
5 float IN 32767.5 input.0.abs-ry-scale
5 s32 OUT 65535 input.0.abs-rz-counts
5 s32 IN 4095 input.0.abs-rz-flat
5 s32 IN 255 input.0.abs-rz-fuzz
5 bit OUT FALSE input.0.abs-rz-is-neg
5 bit OUT TRUE input.0.abs-rz-is-pos
5 float IN 32767.5 input.0.abs-rz-offset
5 float OUT 1 input.0.abs-rz-position
5 float IN 32767.5 input.0.abs-rz-scale
5 s32 OUT 65535 input.0.abs-throttle-counts
5 s32 IN 4095 input.0.abs-throttle-flat
5 s32 IN 255 input.0.abs-throttle-fuzz
5 bit OUT FALSE input.0.abs-throttle-is-neg
5 bit OUT TRUE input.0.abs-throttle-is-pos
5 float IN 32767.5 input.0.abs-throttle-offset
5 float OUT 1 input.0.abs-throttle-position
5 float IN 32767.5 input.0.abs-throttle-scale
5 s32 OUT 2957 input.0.abs-wheel-counts
5 s32 IN 4095 input.0.abs-wheel-flat
5 s32 IN 255 input.0.abs-wheel-fuzz
5 bit OUT TRUE input.0.abs-wheel-is-neg
5 bit OUT FALSE input.0.abs-wheel-is-pos
5 float IN 32767.5 input.0.abs-wheel-offset
5 float OUT -0.9097581 input.0.abs-wheel-position
5 float IN 32767.5 input.0.abs-wheel-scale
5 s32 OUT 2942 input.0.abs-x-counts
5 s32 IN 4095 input.0.abs-x-flat
5 s32 IN 255 input.0.abs-x-fuzz
5 bit OUT TRUE input.0.abs-x-is-neg
5 bit OUT FALSE input.0.abs-x-is-pos
5 float IN 32767.5 input.0.abs-x-offset
5 float OUT -0.9102159 input.0.abs-x-position
5 float IN 32767.5 input.0.abs-x-scale
5 s32 OUT 2942 input.0.abs-y-counts
5 s32 IN 4095 input.0.abs-y-flat
5 s32 IN 255 input.0.abs-y-fuzz
5 bit OUT TRUE input.0.abs-y-is-neg
5 bit OUT FALSE input.0.abs-y-is-pos
5 float IN 32767.5 input.0.abs-y-offset
5 float OUT -0.9102159 input.0.abs-y-position
5 float IN 32767.5 input.0.abs-y-scale
5 s32 OUT 2940 input.0.abs-z-counts
5 s32 IN 4095 input.0.abs-z-flat
5 s32 IN 255 input.0.abs-z-fuzz
5 bit OUT TRUE input.0.abs-z-is-neg
5 bit OUT FALSE input.0.abs-z-is-pos
5 float IN 32767.5 input.0.abs-z-offset
5 float OUT -0.910277 input.0.abs-z-position
5 float IN 32767.5 input.0.abs-z-scale
5 s32 OUT 2941 input.1.abs-rudder-counts
5 s32 IN 4095 input.1.abs-rudder-flat
5 s32 IN 255 input.1.abs-rudder-fuzz
5 bit OUT TRUE input.1.abs-rudder-is-neg
5 bit OUT FALSE input.1.abs-rudder-is-pos
5 float IN 32767.5 input.1.abs-rudder-offset
5 float OUT -0.9102464 input.1.abs-rudder-position
5 float IN 32767.5 input.1.abs-rudder-scale
5 s32 OUT 2947 input.1.abs-rx-counts
5 s32 IN 4095 input.1.abs-rx-flat
5 s32 IN 255 input.1.abs-rx-fuzz
5 bit OUT TRUE input.1.abs-rx-is-neg
5 bit OUT FALSE input.1.abs-rx-is-pos
5 float IN 32767.5 input.1.abs-rx-offset
5 float OUT -0.9100633 input.1.abs-rx-position
5 float IN 32767.5 input.1.abs-rx-scale
5 s32 OUT 65535 input.1.abs-ry-counts
5 s32 IN 4095 input.1.abs-ry-flat
5 s32 IN 255 input.1.abs-ry-fuzz
5 bit OUT FALSE input.1.abs-ry-is-neg
5 bit OUT TRUE input.1.abs-ry-is-pos
5 float IN 32767.5 input.1.abs-ry-offset
5 float OUT 1 input.1.abs-ry-position
5 float IN 32767.5 input.1.abs-ry-scale
5 s32 OUT 65535 input.1.abs-rz-counts
5 s32 IN 4095 input.1.abs-rz-flat
5 s32 IN 255 input.1.abs-rz-fuzz
5 bit OUT FALSE input.1.abs-rz-is-neg
5 bit OUT TRUE input.1.abs-rz-is-pos
5 float IN 32767.5 input.1.abs-rz-offset
5 float OUT 1 input.1.abs-rz-position
5 float IN 32767.5 input.1.abs-rz-scale
5 s32 OUT 65535 input.1.abs-throttle-counts
5 s32 IN 4095 input.1.abs-throttle-flat
5 s32 IN 255 input.1.abs-throttle-fuzz
5 bit OUT FALSE input.1.abs-throttle-is-neg
5 bit OUT TRUE input.1.abs-throttle-is-pos
5 float IN 32767.5 input.1.abs-throttle-offset
5 float OUT 1 input.1.abs-throttle-position
5 float IN 32767.5 input.1.abs-throttle-scale
5 s32 OUT 2957 input.1.abs-wheel-counts
5 s32 IN 4095 input.1.abs-wheel-flat
5 s32 IN 255 input.1.abs-wheel-fuzz
5 bit OUT TRUE input.1.abs-wheel-is-neg
5 bit OUT FALSE input.1.abs-wheel-is-pos
5 float IN 32767.5 input.1.abs-wheel-offset
5 float OUT -0.9097581 input.1.abs-wheel-position
5 float IN 32767.5 input.1.abs-wheel-scale
5 s32 OUT 2942 input.1.abs-x-counts
5 s32 IN 4095 input.1.abs-x-flat
5 s32 IN 255 input.1.abs-x-fuzz
5 bit OUT TRUE input.1.abs-x-is-neg
5 bit OUT FALSE input.1.abs-x-is-pos
5 float IN 32767.5 input.1.abs-x-offset
5 float OUT -0.9102159 input.1.abs-x-position
5 float IN 32767.5 input.1.abs-x-scale
5 s32 OUT 2942 input.1.abs-y-counts
5 s32 IN 4095 input.1.abs-y-flat
5 s32 IN 255 input.1.abs-y-fuzz
5 bit OUT TRUE input.1.abs-y-is-neg
5 bit OUT FALSE input.1.abs-y-is-pos
5 float IN 32767.5 input.1.abs-y-offset
5 float OUT -0.9102159 input.1.abs-y-position
5 float IN 32767.5 input.1.abs-y-scale
5 s32 OUT 2940 input.1.abs-z-counts
5 s32 IN 4095 input.1.abs-z-flat
5 s32 IN 255 input.1.abs-z-fuzz
5 bit OUT TRUE input.1.abs-z-is-neg
5 bit OUT FALSE input.1.abs-z-is-pos
5 float IN 32767.5 input.1.abs-z-offset
5 float OUT -0.910277 input.1.abs-z-position
5 float IN 32767.5 input.1.abs-z-scale
... snippage ...
Parameters:
Owner Type Dir Value Name
5 s32 RO 65535 input.0.abs-rudder-max
5 s32 RO 0 input.0.abs-rudder-min
5 s32 RO 65535 input.0.abs-rx-max
5 s32 RO 0 input.0.abs-rx-min
5 s32 RO 65535 input.0.abs-ry-max
5 s32 RO 0 input.0.abs-ry-min
5 s32 RO 65535 input.0.abs-rz-max
5 s32 RO 0 input.0.abs-rz-min
5 s32 RO 65535 input.0.abs-throttle-max
5 s32 RO 0 input.0.abs-throttle-min
5 s32 RO 65535 input.0.abs-wheel-max
5 s32 RO 0 input.0.abs-wheel-min
5 s32 RO 65535 input.0.abs-x-max
5 s32 RO 0 input.0.abs-x-min
5 s32 RO 65535 input.0.abs-y-max
5 s32 RO 0 input.0.abs-y-min
5 s32 RO 65535 input.0.abs-z-max
5 s32 RO 0 input.0.abs-z-min
5 s32 RO 65535 input.1.abs-rudder-max
5 s32 RO 0 input.1.abs-rudder-min
5 s32 RO 65535 input.1.abs-rx-max
5 s32 RO 0 input.1.abs-rx-min
5 s32 RO 65535 input.1.abs-ry-max
5 s32 RO 0 input.1.abs-ry-min
5 s32 RO 65535 input.1.abs-rz-max
5 s32 RO 0 input.1.abs-rz-min
5 s32 RO 65535 input.1.abs-throttle-max
5 s32 RO 0 input.1.abs-throttle-min
5 s32 RO 65535 input.1.abs-wheel-max
5 s32 RO 0 input.1.abs-wheel-min
5 s32 RO 65535 input.1.abs-x-max
5 s32 RO 0 input.1.abs-x-min
5 s32 RO 65535 input.1.abs-y-max
5 s32 RO 0 input.1.abs-y-min
5 s32 RO 65535 input.1.abs-z-max
5 s32 RO 0 input.1.abs-z-min
... snippage ...
Dan’s program assigns the outputs thusly:
Wheel – ambient temperature as measured on TC4 board
X Y Z Rudder – thermocouples – channels 1 through 4
RX RY RZ Throttle – thermistors – channels 5 through 8
I created a huge Eagle device that encapsulates the whole thing. A simple demo schematic includes the constants that make the temperatures come out in °C:
TC4Server – Eagle Schematic
That picture produces this HAL file:
# HAL config file automatically generated by Eagle-CAD ULP:
# [/mnt/bulkdata/Project Files/eagle/ulp/hal-write-2.5.ulp]
# (C) Martin Schoeneck.de 2008
# Charalampos Alexopoulos 2011
# Mods Ed Nisley KE4ZNU 2010 2013
# Path [/mnt/bulkdata/Project Files/eagle/projects/LinuxCNC for M2/]
# ProjectName [LinuxCNC M2 - TC4Server Test]
# File name [/mnt/bulkdata/Project Files/eagle/projects/LinuxCNC for M2/TC4Server.hal]
# Created [20:03:16 03-Jun-2013]
####################################################
# Load realtime and userspace modules
loadusr -W hal_input -A +Leonardo
loadrt threads name1=servo-thread period1=1000000
loadrt constant count=4
loadrt conv_float_s32 count=2
####################################################
# Hook functions into threads
addf constant.0 servo-thread
addf constant.1 servo-thread
addf constant.2 servo-thread
addf constant.3 servo-thread
addf conv-float-s32.0 servo-thread
addf conv-float-s32.1 servo-thread
####################################################
# Set parameters
####################################################
# Set constants
setp constant.0.value 10
setp constant.1.value 2732
setp constant.2.value 0
setp constant.3.value 0
####################################################
# Connect Modules with nets
net n_2 constant.2.out conv-float-s32.1.in
net n_3 constant.3.out conv-float-s32.0.in
net tc4-ambient input.0.abs-wheel-position
net tc4-flat input.0.abs-wheel-flat input.0.abs-x-flat input.0.abs-y-flat input.0.abs-z-flat input.0.abs-rudder-flat input.0.abs-rx-flat input.0.abs-ry-flat input.0.abs-rz-flat input.0.abs-throttle-flat conv-float-s32.1.out
net tc4-fuzz input.0.abs-throttle-fuzz input.0.abs-rz-fuzz input.0.abs-ry-fuzz input.0.abs-rx-fuzz input.0.abs-rudder-fuzz input.0.abs-z-fuzz input.0.abs-y-fuzz input.0.abs-x-fuzz input.0.abs-wheel-fuzz conv-float-s32.0.out
net tc4-offset input.0.abs-wheel-offset input.0.abs-x-offset input.0.abs-y-offset input.0.abs-z-offset input.0.abs-rudder-offset input.0.abs-rx-offset input.0.abs-ry-offset input.0.abs-rz-offset input.0.abs-throttle-offset constant.1.out
net tc4-scale input.0.abs-wheel-scale input.0.abs-x-scale input.0.abs-y-scale input.0.abs-z-scale input.0.abs-rudder-scale input.0.abs-rx-scale input.0.abs-ry-scale input.0.abs-rz-scale input.0.abs-throttle-scale constant.0.out
net tcouple-1 input.0.abs-x-position
net tcouple-2 input.0.abs-y-position
net tcouple-3 input.0.abs-z-position
net tcouple-4 input.0.abs-rudder-position
net tmistor-5 input.0.abs-rx-position
net tmistor-6 input.0.abs-ry-position
net tmistor-7 input.0.abs-rz-position
net tmistor-8 input.0.abs-throttle-position
Fire it up with halrun to see the temperatures (alphabetically by the pin name):
halrun -I -f TC4Server.hal
halcmd: start
halcmd: show pin *position
Component Pins:
Owner Type Dir Value Name
5 float OUT 20.9 input.0.abs-rudder-position ==> tcouple-4
5 float OUT 21.5 input.0.abs-rx-position ==> tmistor-5
5 float OUT 6280.3 input.0.abs-ry-position ==> tmistor-6
5 float OUT 6280.3 input.0.abs-rz-position ==> tmistor-7
5 float OUT 6280.3 input.0.abs-throttle-position ==> tmistor-8
5 float OUT 22.5 input.0.abs-wheel-position ==> tc4-ambient
5 float OUT 21 input.0.abs-x-position ==> tcouple-1
5 float OUT 21 input.0.abs-y-position ==> tcouple-2
5 float OUT 20.8 input.0.abs-z-position ==> tcouple-3
The sensors do not correspond to the picture at the top: only the first thermocouple and first thermistor are connected ; the ADC returns bogus data for disconnected inputs, which means you must be careful about tightening the wires and checking the result. Dan’s firmware has the ability to disable unused sensors, in which case you get a huge value; when used for heater control, a sensor failing high means the heater will turn off, but, should you use this gadget in a freezer, you might want them to fail low (so modify the code for your own use).
The ambient temperature reported for the board runs 1 or 2 °C higher than the actual ambient air temperature, probably because of all those components doing useful things up close to the sensor chip. That particular ambient temperature serves as the cold junction reference for the thermocouples; the other temperatures don’t change very much as the board warms up, so it’s all good.
Remember to issue the start command in halrun, because otherwise nothing changes.
Also remember that you must configure TC4Server with the thermistor characteristics before you use it as a hal_input device.
Based on the discussion attached to the post on Z axis numbers, I wanted to take a look at the points where Marlin switches from one step per interrupt to two, then to four, just to see what the timing looks like. The RAMBo board has neatly labeled test points, to which I tack-soldered a pin for the scope probe poked through one of the ventilation slots, and an unused power connector on the left edge of the PCB that provided a ground point (admittedly, much too far away for good RF grounding, but it suffices for CMOS logic signals). The Tek Hall-effect current probe leaning in from the top right captures the current in one of the X axis windings:
X axis Step and Current probes
I’ve reset the Marlin constants based on first principles, per the notes on distance, speed, and acceleration, so they’re not representative of the as-shipped M2 firmware. Recapping the XY settings:
Distance: 88.89 step/mm
Speed: 450 mm/s = 27000 mm/min
Acceleration: 5000 mm/s2, with the overall limit at 10 m/s2
The maximum interrupt frequency is about 10 kHz and the handler can issue zero, one, two, or four steps per axis per interrupt as required by the speed along each axis, up to a maximum of step rate of 40 kHz. There are complexities involved which I do not profess to understand.
The maximum 10 kHz step rate for one-step-per-interrupt motion corresponds to a speed of:
112.5 mm/s = (10000 step/s) / (88.89 step/mm)
The maximum 40 kHz step rate produces, naturally enough, four times that speed:
450 mm/s = (40000 step/s) / (88.89 step/mm)
Assuming constant acceleration, the distance required to reach a given speed from a standing start or to decelerate from that speed to a complete stop is: x = v2 / (2 * a)
The time required to reach that speed is: t = v/a
Accelerating at 5000 mm/s2:
112.5 mm/s = 6700 mm/min → 1.27 mm, 22.5 ms
150 mm/s = 9000 mm/min → 2.25 mm, 30 ms
450 mm/s = 27000 mm/min → 20.3 mm and 90 ms
An overview of a complete 6 mm move at 150 mm/s shows the acceleration and deceleration at each end, with a constant-speed section in the middle:
X Axis 150 mm-s 6 mm – overview
The bizarre patterns in the traces come from hp2xx‘s desperate attempts to discern the meaning of the scope’s HPGL graphic data where the trace forms a solid block of color; take it as given that there’s no information in the pattern. I described the trace conversion process there.
The upper trace shows the X axis motor winding current at a scale of 500 mA/div, with far more hash than one would expect. The RAMBo drivers evidently produce much more current noise than the brick drivers I intend to use.
The lower trace is the X axis step signal produced by the Arduino microcontroller. You can barely make out the individual step signals at each end, but there’s not enough horizontal resolution to show them when the motor moves at a reasonable pace.
In round numbers, the acceleration and deceleration should require about 30 ms each. The overall move takes 63 ms, so the constant-speed section in the middle must be about 3 ms long. That’s probably not right…
Here’s a closer look at the step pulses as the motion starts from zero on the way to 150 mm/s:
X Axis 150 mm-s 6 mm – 1 ms-div 0 ms dly
Over on the right, the 5 kHz step rate after 8.5 ms suggests a speed of 56 mm/s and counting 28 pulses says it moved 0.32 mm. Plugging those numbers into the equations:
a = v/t = 6600 mm/s2
a = (2 * x)/t2 = 8900 mm/s2
It’s not clear (to me, anyway) whether:
The firmware accelerates faster than the alleged 5000 mm/s2 limit
It’s accelerating near the overall limit of 10000 mm/s2
The acceleration isn’t constant: starts high, then declines
The measurement accuracy doesn’t support any conclusions
I understand what’s happening
In order to see the double- and quad-step outputs, here’s a 50 mm move at 450 mm/s, with a 19 ms delay to the point where the interrupt handler transitions from single-step to double-step output:
X Axis 450 mm-s 50 mm – 200 us-div 19 ms dly
The interrupt frequency drops from just under 10 kHz to a bit under 5 kHz, with the doubled pulses about 16 μs apart. At the transition, the axis speed is 112.5 mm/s, pretty much as predicted.
If that’s the case, the overall acceleration to the transition works out to:
5800 mm/s2 = (113 mm/s) / (19.5 ms)
Delaying the traces to 41.9 ms after the motion starts shows the double-to-quad step transition:
X Axis 450 mm-s 50 mm – 100 us-div 41.9 ms dly
Once again, the pulse frequency drops from 10 kHz down to 5 kHz. The speed is now 225 mm/s, half the maximum possible speed, which also makes sense: at top speed, the pulses will be essentially continuous at 40 kHz.
The average acceleration from the start of the motion:
5300 mm/s2 = (225 mm/s) / (42.1 ms)
That implies the initial acceleration starts higher than the limit, but it evens out on the way to the commanded speed.
Those scope shots come from moving only the X axis. Moving both the X and Y axes, with Trace 1 now showing the Y axis output, for 50 mm at 450 mm/s, produces similar results; the Y axis output lags the X axis by a few microseconds:
XY 450 mm-s 50 mm – 100 us-div 19.5 ms dly
Once again, that’s at the single- to double-step transition at 19+ ms. The overall timing doesn’t depend on how many axes are moving, as long as they can accelerate at the same pace; otherwise, the firmware must adjust the accelerations to make both axes track the intended path.
None of this is too surprising.
For a motor running at a constant speed just beyond the single-to-double step transition at 112.5 mm/s or the double-to-quad transition at 225 mm/s, the rotor motion should have a 5 kHz perturbation around its nominal position: it coasts for nearly the entire period, then a pair of steps kicks it toward the proper position. At those transitions, the rotor turns at:
The perturbation should look like a 5 kHz oscillation (not exactly sinusoidal, maybe triangular?) superimposed on the nominal position, which is changing more-or-less parabolically as a function of time. I expect that the overall inertia damps it out pretty well, but I’d like to attach a rotary encoder to the motor shaft (or a linear encoder to the axis) to show the actual outcome, but I don’t have the machinery for that.
In any event, LinuxCNC’s step outputs should behave better, which is why I’m doing this whole thing in the first place…