Freesteel Blog » 2016 » August

Wednesday, August 24th, 2016 at 9:16 am - - Hang-glide

I spent the last three days at the washout known as the British Open Series 3 where one day out of five was flyable. This was yesterday from a hill called Camlo which is a “little flown hill, especially for hang gliders, as there is not a suitable bottom landing field”

Numpty here took off first with everyone watching and waiting because there were no clouds, and I got thrown about a bit. Luckily there were no other gliders in the air to dodge.

Then I came in and landed when things got full up like a zoo (orange glider on the 39th second of the vid).

Then I un-redeemed myself by sitting on takeoff for most of the next video until the launch window was about to close.

Most of the big boys got away during that time until I was one of just two gliders left in the air. I went in and landed just as the other one got away to a big cloud. Grumble.

Once you’ve tasted XC flying, nothing is ever good enough again.

Monday, August 15th, 2016 at 9:20 pm - - Cave

This one has been on our minds since we were caving novices in CUCC (back in 1987) when some of the big boys went to dive the sumps in Rowten Pot and had a bit of an epic. Twenty-nine years later Becka and I used the rigging put in for the Eurospeleo conference, took a small pony cylinder and checked it out.

It was lovely with masks, warm hood, bright LED lights, proper wetsuits (much better than what they had in the bad old days). We went back and forth a couple of times without the tank, and then exited through Valley Entrance — with some complaining at the short pitch from the streamway, which I climbed out and she whinged at, in spite of the fact that she goes bouldering most weeks, and I don’t because I hate it.

Saturday, August 13th, 2016 at 12:23 pm - - Machining

I’ve been getting some machining done, found out what worn out tools are like when you try to use them, and bought a whole load more.

We’ve also been doing some important work controlling servos directly from the Beagleboard through an H-bridge which will allow us to bypass the conventional servo motor drive setup that prevents all positional feedback information.

You can see the varying width modulations on the scope here:

prupwm

The code, compiled from C and deployed on the programmable realtime unit, varies the pulse width every cycle thus modulates the amplitude like a class D amplifier.

The music, in the second half of the above video, isn’t well picked up by the phone microphone, although it sounded surprisingly good in reality.

This is almost all the PRU code responsible for reading the channels (pairs of numbers that are wavelength and amplitude) and setting the PWM width per cycle.

#define NOTECHANNELS 12
struct Commondata {  unsigned int notes[NOTECHANNELS*2];  };
volatile near struct Commondata commondata __attribute__((cregister("PRU_DMEM_0_1", near), peripheral));

int main() 
{
  CT_ECAP.ECCTL2 = 0x02C0;
  CT_ECAP.CAP1 = 4096;    // PWM clock period
  CT_ECAP.ECCTL2 |= 0x0010;

  long channelcounts[NOTECHANNELS];
  for (int i = 0; i < NOTECHANNELS; i++) 
    	channelcounts[i] = 0;

  int mid50 = CT_ECAP.CAP1/2;
  int guardlo = mid50/8;   // clock range safe to change
  int maxamplitude = mid50 - guardlo;

  while(1){

    int waveamp = 0;
    for (i = 0; i < NOTECHANNELS; i++) {
      if ((pid.notes[i*2] == 0) || (pid.notes[i*2+1] == 0))
        continue;
      channelcounts[i] -= 16;  // granularity of steps per PWM cycle
      if (channelcounts[i] < 0)  // countdown crosses zero, set wave back up
        channelcounts[i] += pid.notes[i*2];

      // calculate sawtooth wave amplitude within period
      int amp = (pid.notes[i*2+1] * channelcounts[i]) / pid.notes[i*2] - pid.notes[i*2+1] / 2;
      waveamp += amp;   // sum up the amplitudes
    }

    // attenuate rather than truncate
    waveamp = waveamp*maxamplitude/(abs(waveamp) + maxamplitude);

    // wait till we are outside of the lower values of the clock
    while (CT_ECAP.TSCTR < guardlo)
      ;
    // wait till the clock has ticked over (but hasn't counted above 100)
    while (!(CT_ECAP.TSCTR < guardlo))
      ;

    // set the next duty cycle length (safe as value greater than guardlo)
    CT_ECAP.CAP2 = waveamp + mid50;
  }
}

It's about 50 times less code and effort than I thought it was going to be, mainly due to the use of the PWM subsystems, rather than attempting to generate timed PWM in realtime from the PRU code. This could only have been possible were I authoring the assembly code directly instead of using a compiler, because only that way can you count the cycles. This is a good move because, while it would have been fun to write carefully hand-coded division routines that used a fixed amount of processor cycles, it would have been a waste of my time. This way we're simply using the PRUs as co-processors that we assume are running fast enough to service those other subsystems in the chip.

The other subsystem we need to read are the quadrature encoders in order to drive the motors to a given position -- and read what position they have been dragged to by other forces (like human hands).

This is the current state of the project plan to get to a milling machine that responds to cutting forces with changes in toolpath trajectory (which requires the abolition of G-code).
projectplan

It's all about us keeping an eye on where we are trying to get to, picking the route to it that takes us across the known unknowns in a way that exposes us to maximum learning, and then cutting corners (eg by further bodging the circuits we already have).

I couldn't do this if I had to explain, repeat and clear every change of plan with a boss who was remote to the project.

On the other hand, if we did have a boss maybe we'd get there at the same rate on account of a lot fewer holidays per year.