Freesteel Blog » A tale of three bricks

A tale of three bricks

Wednesday, October 28th, 2015 at 11:08 am Written by:

The first BeagleBoneBlack in the picture was already bust when I gave it to Tom. He broke his own one when wiring it to the triangle milling machine during replacement of its desk-top PC LinuxCNC controller system. Then, with nothing better to do, we got to work on those Leadshine DB810A servo drives and broke the Z-axis one when we wired an oscilliscope across the plus and minus motor power poles. These are temperamental devices that spend a lot of time flipping back to the error state with the red LED so we weren’t 100% sure it was broken until we did the same job to the ‘Y’-axis driver.

bricks1

And that’s how we reduced three hand-held oblong items of electronic gadgetry to three lifeless plastic bricks in one day.

We took all three drivers out of the box and put them on the bench with a 24 volt power supply to verify that the remaining ‘X’-axis one was working differently on account of the fact that we hadn’t broken it yet.

I was still pretty keen on finding out exactly what the driver did at a technical level, having read in detail someone’s account of building their own servo controller, and wondered if it was something we should think about doing ourselves for the purpose of enabling some feedback from the milling machine to the CAM system.

The servo driver has Motor + and Motor – terminals. These are mislabelled given that power is applied in either directions depending on which way you want to spin the motor. It would therefore be better to call them Left and Right terminals.

And while it’s okay to attach a portable multimeter across these two terminals to measure a voltage differential, it is not okay to do this with an oscilloscope because one of the scope’s terminals is an Earth and one is the probe, and it will result in a short-circuit to ground which will blow up some unknown component in the device. We opened the case to see if there was anything obvious and found that the dipsticks who manufactured it had filed off the labels on all the chips, except for the large optocouplers.

This time we attached the scope’s probe to only one Motor terminal, and keep the ground only on the ground before we turned it on.

To overcome one of the error modes (not having a motor attached), we shoved about half a dozen old 200Ohm resistors between the contacts. They could stand about 30 seconds of power before becoming hot and smelly.

pwmpower

To overcome a second error mode (rotary encoder not attached), we placed a mechanical encoder capable of delivering a quadrature signal to the EA+ and EB+ terminals and spun it rapidly back and forth after hitting the reset button on the driver. This simulated the effect of the motor jogging back and forth following the voltage from the driver that was attempting to keep it stationary and stable to a single absolute position. This was like trying to balance a walking stick on the tip of your finger by moving your hand back and forth with your eyes closed in the dark with an anaesthetised arm. It didn’t work for very long before the encoder was applying full power in one direction and tripping itself out into another error mode equivalent to the stick falling to the ground.

Eventually I rigged up an arduino to deliver a rapid back-and-forth quadrature encoder sequence to the working DB810A servo driver with the following program:

int pinA = 12;
int pinB = 13; 

void setup() {
  pinMode(pinA, OUTPUT); 
  pinMode(pinB, OUTPUT); 
}

long pos = 1000000; 
void encoderout(int d, int microsteps) 
{
    pos += d; 
    digitalWrite(pinA, ((pos/2) % 2) == 0 ? HIGH : LOW); 
    digitalWrite(pinB, (((pos+1)/2) % 2) == 0 ? HIGH : LOW); 
    delayMicroseconds(microsteps); 
}

void loop() 
{
    int stepleng = 10; 
    int microsteps = 1000; // or 1600
    for (int i = 0; i < stepleng; i++) 
        encoderout(1, microsteps); 
    for (int i = 0; i < stepleng; i++) 
        encoderout(-1, microsteps); 
}

The effect of this was to simulate the spinning of the motor encoder 10 notches forwards over 10miliseconds, and then back the same amount for 10miliseconds repeatedly. The idea was to give the driver some work to do trying to follow these simulated position errors.

Why was I doing this?

Well, the motor controller design I read about operated on an update loop of 0.51miliseconds. That is, after every 2000th of a second the device adds up all the encoder steps and control pulses (the ones generated by the LinuxCNC PC setting the desired position) which have arrived during that time window, subtracts the two, does the PID calculation, and sets the voltage to the motor to a new level.

The observable on such a device would be that the voltage going into the motor only changes every 0.51miliseconds, and my argument was that we shouldn’t have to bother generating these expensive real-time pulses when we could simply communicate the desired positional changes with a sequence of small integers of less than a byte long every 2000 times a second down a simple serial line. And then we could use the other side of the serial line to return the positional error back to the controller so it would have some idea of what was going on in terms of how well the 3-axis trajectory was being followed.

But that’s only for a home-built device. Could we observe the same time-window stepped effect in a professional item?

Well, the first thing we noticed when we got the scope working was that it didn’t deliver a constant voltage to the motor as we’d imagined. Instead there was a full voltage pulse-width modulation (PWM) alternating both ways into the motor every 46microseconds. That is, if the motor was stationary it was in fact receiving 24Volts into the left terminal for 23microseconds, followed by 24Volts into the right termal for the next 23microseconds, and so on. When it was spinning slowly it would have 24microseconds of power one way followed by 22microseconds the other way.

Who knew motors could take this kind of crap? In fact after well and truly roasting our half-dozen resistors on circuit which required them to absorb 24Volts of full-on square-wave A/C power, we plugged one of the servo motors in its place and it became pretty peaceful. Turns out that there are so much back induction from the coils inside the motor that a very fast PWM-generated 50% square wave alternating voltage drives very little current and therefore energy into it.

The use of a PWM implies that there is an update loop on some level because the effective voltage to the motor cannot be changed faster than the PWM cycle. A cycle of 46microseconds is very fast. The Arduino Uno has a cycle of 2milliseconds.

We captured some waveforms on the Rigol oscilloscope and then fought hard with it to get the data disclosed into a 100Mb CSV file at a sample rate of 10nanoseconds. It takes forever to save, and we still don’t know how to do it reliably without getting a “Function limited!” error most of the time.

wavetrough

Here is an image of a single trough of one PWM waveform approximately 800 sample points wide representing 8microseconds in duration. (I owe JD lots of beers for letting me use his amazing oscilloscope while he’s swanning around in Berlin.)

The time between the ends of each trough is consistently 46microseconds.

The width of the troughs, however, exhibit a bizarre pattern. (Red dots placed at the peaks.)

pwmsequence

For reference, the code which plots the widths of these troughs from the CSV file is as follows:

cs = list(csv.reader(open("NewFile5.csv")))
print(cs[:2])  # header
fs = list(map(float, (c[0]  for c in cs[2:])))
tvolts = 14  # trigger
k = [i  for i in range(1, len(sfs))  if (sfs[i-1]<tvolts)!=(sfs[i]<tvolts)]
ks = [k1-k0  for k0, k1 in zip(k, k[1:])]
d = 1 if fs[0]<tvolts else 0  # phase
kk = list(zip(ks[d::2], ks[1+d::2]))
pts = [(i*0.1, (k1)*0.0001)  for i, (k0, k1) in enumerate(kk)]
sendactivity(contours=[pts]);  sendactivity(points=pts)

# to smooth the signal when there are false triggers
f, sfs, l0, l1 = 0, [ ], 0.8, 0.2
for s in fs:
    f = f*l0 + s*l1
    sfs.append(f)

I can’t find a real pattern here. The peaks of this are roughly every 16.2cycles (plotted in red lines), or about 729miliseconds, though sometimes they are on the half cycle. They don’t correspond to the encoder pulse times, which I was generating at 1000milliseconds (or 1600milliseconds in a second example).

pwmsequence2

The peaks themselves seem to be aligned in their magnitudes at steps of 2microseconds, with some kind of exponential decay to an average value occurring before another peak is stimulated.

It’s not clear if this pattern is genius or if it’s a mistake.

It’s probably a mistake.

The device contains a component capable of generating a continuous variability in the pulse width in every short cycle, but the input to it may be botched in magnitude, and somebody had to program in a dampener to the signal to make it work. There’s a lot of leeway in what the motor is going to take, so nobody notices, but obviously, we suppose, the engineers intended for signal that was going to come out looking cool and smooth with practically invisible prods pushing the pulse width up and down, and it all went to cack on the way out the door. Who knows? Maybe it’s only bad because of our bogus encoder input.

I need to look at what some other similar drivers do regarding this signal before this idea is conclusive.

In the meantime Tom is supposed to check whether these servo motors actually mind getting a slower PWM wavelength than 45microseconds without causing undue vibration in case this whole deal is just over-engineered. That should take up our time until the replacement drivers make their way over from China over the next month or so.

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <blockquote cite=""> <code> <em> <strong>