Freesteel Blog » 2017 » April

Monday, April 24th, 2017 at 8:15 pm - - Flightlogger

I had a very agreeable flight on Saturday in Wales, marred by a crappy going down performance on Bradwell on Sunday, just to put me in my place as not having any talent.

Here’s the good place to be, about a mile up from the ground:
wavellan

It was a confused forecast, which meant a lot of people stayed away. Turns out it was because there was wave everywhere. I flew Tim’s U2 (mid-performance glider), but was put off by the fact of everyone pointing out that I was too high on the bar, and so wouldn’t be able to steer it so well. Hang-loops, unlike climbing harness loops, do not come with a buckle, so you can’t do anything about it.

There was a lot of lift straight off the hill, and then Carl said over the radio, “I think I’ve contacted wave, just to the right of the mound in front of the hill.”

There were lenticular (French for “slow”) wave clouds everywhere and no cumulus. I was wearing a skinny pair of gloves and had no base bar mitts (which I do have on my own glider).
(more…)

Wednesday, April 19th, 2017 at 11:41 pm - - Flightlogger

I’m not going to learn too much from myself, so I’ve got the raw data from Tim’s flight as measured by his Kobo/bluefly IGC logger.

timgps

As you can see, he ranged a good deal further than I did from Mam Tor, reaching an altitude of 1500m, and he reported scoring glide angles of 10 to 1 on his glider much-fancier-than-mine-of-which-I-am-now-jealous.

Let’s see if we can corroborate this from his data with the power of pandas and matplotlib.

pIGCtim = fd.LoadIGC("Tim-1492470000.igc")
pQ = pIGCtim.resample("1S").interpolate(method="time")  # fill uneven records

dstep = 30 # rolling windowed measurements in seconds
vario = (pQ.alt.diff(dstep)/dstep)  # m/s averaged over 30seconds
groundvelocity = numpy.sqrt(pQ.x.diff(dstep)**2 + pQ.y.diff(dstep)**2)/dstep

Here is vario:
timsvario

Here is ground velocity:
timsgroundvel

The glide slope (normally called the glide-angle, even though we don’t quote it as an angle) is the groundvelocity divided by the descent rate. When the descent rate is close to zero, you get stupid numbers, so we need to throw those out and only quote for the parts where there is reasonably direct gliding flight.

(more…)

Friday, April 14th, 2017 at 4:32 pm - - Machining

Building on the weighted servo motor (having spent the first 20 minutes of the day trying to find where I left my code) I’ve tried to code it to run on a sine wave as an oscillation.

It’s not easy, of course.
voltssinwave

How did I get this?

From the fixed voltage experiments I computed the function from the voltage and velocity to the acceleration for motor1 as follows:

cv0, cm0, cv1, cm1, cvm, cvc = 53.202, -1036.634, 56.027, -974.375, -7.497, -1521.571
acceleration1 = (velocity1 - (min(volts1-cv0, 0)*cm0 + max(volts1-cv1, 0)*cm1))*cvm + cvc

Therefore, given the velocity, if you want a particular acceleration, you need the following voltage:

tq = velocity1 - (acceleration1 - cvc)/cvm
if tq < 0:
    volts1 = tq/cm1 + cv1
else:
    volts1 = +tq/cm0 + cv0

The above was the result of trying to make the motor oscillate like a pendulum by setting the acceleration to a negative number times the displacement:

acceleration1 = -acc1fac*(position1 - position1c)

Of course, one source of the problem is knowing the velocity. I've bodged this by recording a couple of positions up to 0.2seconds in the past and measuring to them.

if currenttime - prevtime > 0.1:
    position1prev2 = position1prev
    position1prev = position1
    prev2time = prevtime
    prevtime = currenttime
velocity1 = (position1 - position1prev2)/(currenttime - prev2time)

Unfortunately, this produces lots of bumps, so I think I'll have to do this properly by applying, say, an exponential filter to the position value which delays the position, and use the difference between that and the current position as a measure of velocity.

Like all such runtime velocity measurements (unlike the ones done in pandas that have been calculated by picking a position on either side of the current time, like so:

(df.shift(-10).position1 - df.shift(10).position1)/(df.time.shift(-10) - df.time.shift(10))

...it's also going to be delayed by a certain amount and be invalid under accelerations.

(more…)

Thursday, April 6th, 2017 at 11:22 am - - Flightlogger

On my last sorry flight I was carrying a total of four GPS units. One of them is a pile of poo. It’s the bluefly one I programmed to read at the frequency of 10 times a second, so greedy was I for precision and data.

gpscompare

Why do they have that option if it’s a complete waste of my time? All that work learning how to remotely step up its baudrate so that it could transmit data at this higher rate.

Here’s how the error comparisons line up, including the minus 3second correction on the 6030 vario’s timestamps. The “u” value is the number of milliseconds from midnight according to the GPS satellite timestamp.

gnames = [ "gps6030", "gpsxcsoar", "gpsTopShelf", "gpsBlueFly" ]
print("samples, gpsA, gpsB, stddev")
for i in range(len(g)):
    for j in range(i+1, len(g)):
        qA, qB = g[i], g[j]
        dt = 3000 if i == 0 else 0 # observed timeslip on 6030 unit
        dx = qA.x - numpy.interp(qA.u-dt, qB.u, qB.x)
        dy = qA.y - numpy.interp(qA.u-dt, qB.u, qB.y)
        k = (dx**2 + dy**2)[tf0:tf1]
        print(len(k), gnames[i], gnames[j], math.sqrt(k.mean()))
samples gpsA gpsB stddev
400 gps6030 gpsxcsoar 6.086
400 gps6030 gpsTopShelf 7.914
400 gps6030 gpsBlueFly 17.040
550 gpsxcsoar gpsTopShelf 7.845
550 gpsxcsoar gpsBlueFly 19.095
4120 gpsTopShelf gpsBlueFly 17.451

Now I have to program the BlueFly to sample at 200ms like the spare top-shelf GPS does, and see if that fixes it.

Meantime, has is that the accelerometer doing with this not-crap GPS?
(more…)

Tuesday, April 4th, 2017 at 1:29 pm - - Machining

Suppose we apply a random series of fixed duty cycles to a servo motor, like so:

volts1

A 50% duty cycle means that the volts are applied half one way and half the other at about a frequency of 100kHz, so it’s equivalent to zero volts.

I can plot the position from the encoder at the same time, like so:

volts1pos

There’s about 1000 ticks per revolution of the wheel and it’s wired backwards so a positive voltage makes it spin backwards.

Amazingly, with the control loop written in Python on a beaglebone controlling the H-bridges, it makes 4500 samples per second, which is perfectly adequate and I have not had to resort to any fancy tricks with C++ or the PRUs.

With a pandas timeseries Series object pos, we can calculate the velocity over a window of +-100 samples (about 1/20th of a second) like so:

# I'd like a better way to shift and difference a timeseries index.
vel = (pos.shift(-100) - pos.shift(100)) / \
      (pos.index.to_series().shift(-100) - pos.index.to_series().shift(100))

And then there is the acceleration:

acc = (vel.shift(-100) - vel.shift(100)) / \
      (vel.index.to_series().shift(-100) - vel.index.to_series().shift(100))

We can plot them all up like so:

volts1velacc

Here’s what the first two seconds look like.
(more…)