P0533 will ride again

Unfortunately, P0533 (see here for previous posts) didn’t make it into C++20 either (originally targeted at C++ 17). It seems that there were just too many good papers and they couldn’t work through them all in the available time.

There’s lots of good stuff and clearly a strong and growing interest in constexpr’ing everything that can be constexpr’d, so I hold out hope for both it and P1383 in C++2.. uh… 2b? Or not 2b?

Follow their progress in the trackers here:

Light chasing robot part 2 (of 2)

The first version worked, but oscillated a lot in its motion. If you haven’t read it yet, I recommend reading it first otherwise this post won’t make as much sense. And if you have, it might be worth a re-read, since it took me nearly two years to post the followup.

The reason for the oscillation is that it has essentially very high feedback. If it’s very slightly off to one side, then the opposite motor comes on full, because the direction sensor divider goes into a simple comparator. Also, it turns out (I found this about a year later–yes I am a bit lazy about writing blog posts) the response of the LDRs is really slow, measurable over the timescale of a second, so the robot will swing round a significant amount before the resistive divider starts to respond. Either way making the response have a much lower gain will help.

I can reduce the gain by making the motor come on at a reduced speed in proportion to the ratio between the two LDRs.

The circuit is a little more complex than the previous one. It also falls into the category of “should have used a microcontroller” since then the upgrade would just be software and a lot more flexible. Essentially I have used a CMOS 555 in equal duty cycle mode and I’m using the capacitor voltage to get a sawtooth wave. That’s thresholded  by the comparator (opamp) to make a PWM signal. I could have also used the other amplifier in the dual opamp chip to do the same job. That would have been neater in hindsight.

Snapchat-1093110546

Simple PWM circuit

 

The result is really pretty good! See:

 

Er… take 2!

That works well, and is a good validation of the directional light sensors (the original point of this project).

Self feeding flat bits

In knocking together a case for something holding a Raspberry Pi, I needed to cut a 24mm hole for some of these:

f8621579-01

USB bulkhead

My usual go-to stockists didn’t have a 24mm flat bit (or Forstner), so I went to ebay and had a quick dig around. I found a Bosch “Self Cut” spade bit for cheap (maybe not used, old). It looks like this:

Snapchat-926218252

Bosch self-cut bit

Bosch is one of those respectable brands and you won’t go wrong with Bosch tools if you pick the right one for the job.

Speaking of that…

Turns out self feeding bits are wildly unsuitable for the kind of things I do most of the time. They are flat bits but the tip is a screw so it feeds itself into the wood. This should  gives a very consistent depth of cut and chip load. It also means you don’t need to apply any pressure with the drill: it applies an immense amount of drilling pressure using the drill’s torque instead.

They are amazingly, astonishingly aggressive and will happily plough through thick birch ply in seconds (if your drill is up to the task; the level of torque required is vast), and completely split a piece of pine. Note the rather rough cuts with the large amount of tear out:

Holes drilled with self feeding bit

It took much less time to go through the thick birch ply than it took me to drill the holes with a normal bit in a thinner piece of pine.

Great tool, utterly the wrong one for the task.

14 Years

I’ve been working on model based 3D tracking on and off for quite a while now.

Year 1 (2005)

This was my main contribution to the field of 3D tracking. To my knowledge, it was the joint first (there was another paper from my lab mate using a different technique) real time tacking system that processed the entire image frame. Both techniques were much more robust than the ones that went before. My one also debuted an early version of the FAST corner detector (I didn’t put that page there).

You can see the tracking works because the model (rendered as purple lines) stays stuck to the image.  The tracker operated in real time, well field rate, which was 50Hz fields of 756×288 pixels of analogue video from some sort of Pulnix camera, captured on a BT878 card of some sort on a dual PIII at 850 MHz (running Redhat of some description). It wasn’t mobile (I had two 21″ CRT monitors), so I wasn’t watching the screen as I was capturing video; I found a long spool of thin 75 ohm co-ax which is why it had any kind of mobility. It, somewhat unexpectedly, tracked almost until I put the camera down on the table at the end. It was a bit of an anticlimactic finish, but I didn’t expect it to work quite so well.

Year 14 (2019)

This is the project I’ve been working on recently (landmarkers). It’s nice to see technology move from a proof of concept, academic curiosity to a robust production system usable in the wild by people who aren’t computer vision researchers. Also, I didn’t do the graphics in this one which is why it looks rather cooler than a bunch of purple lines.

 

 

 

Building an automatic plant waterer (4/?): Calibrating the sensor

A short day in the attic today.

  • Part 1: resistive sensing
  • Part 2: finding resistive sensing is bad and capacitive sensing is hard
  • Part 3: another crack at a capacitive sensor
  • Part 4: calibrating the sensor

Day VII (weekend 6)

First, to check everything’s OK, I’m going to calibrate the sensor. I have a box of cheap ceramic capacitors in the E3 series and I’m going to go from 10pF to 2200pF, and I’m going to measure them with my old Academy PG015 capacitance meter since it’s likely to be more accurate than the capacitor rating.

Here are the measurements:

Rating Measured capacitance (pf) count
0 0 12.99
10 10.5 18.84
22 22.6 25.80
47 48.3 40.48
100 101.7 70.90
220 221 134.03
470 453 259.21
1000 965 539.16
2200 2240 1227.2

I’m not 100% sure how to fit this. The obvious choice is a least squares straight line fit to find the slope and offset. However, the variance increases with the measurement and I didn’t record that. Also, I don’t know what the error on the capacitance meter is like.

So, I think the best choice is a fit in log space. The fixed slope of line works well with errors on both measurements and it deals with higher measurements having higher variance, to some extent. The equation to map measurements (M) to capacitances (C) is:
C = p_1 ( M + p_2)

So we just take the log of that and do least squares on the result. The code is really simple in Octave:

% Data
d = [
0 0 12.99
10 10.5 18.84
22 22.6 25.80
47 48.3 40.48
100 101.7 70.90
220 221 134.03
470 453 259.21
1000 965 539.16
2200 2240 1227.2
];

% Initial parameters: zero point and shift
p=[1 1];

% Least squares in log space
err = @(p) sum((log(d(2:end,2)) - (log(p(1)) + log(d(2:end,3) + p(2)))).^2);

% Find the parameters
p = fminunc(err, p);

count=115;

% Compute the capacitance for a new measurement
p(1) * (count + p(2))

Nice and easy now does it work? Well, it seems to work with a variety of capacitors I tried it with. And to get intermediate values, I tried it with this rather delightful device from a long dead radio (range 16pF to 493pF):20190317_173744

and it works beautifully!

So, then I tries it on the wire wound capacitive sensor. Can you guess if it worked?

Well, it did! Funny thing though is that my capacitance meter didn’t work on that. Naturally I assumed my home built device was wrong. But it seems life wanted to troll me. Here’s what my capacitance meter does when all is good:

SCR25

Nice and easy. Changing the range switch alters the speed of the downwards decay curve. So far so good. But when I attached my sensor, this happened:

SCR26

Well, it did! Funny thing though is that my capacitance meter didn’t work on that. Naturally I assumed my home built device was wrong. But it seems life wanted to troll me. Here’s what my capacitance meter does when all is good:

Absolutely no idea why. It is a big coil, so it might have something to do with the inductance, or maybe pickup. I expect it has a higher input impedance than my device.

TL;DR a short one today, but the sensor works well and is in excellent agreement with my dedicated capacitance meter.

Building an automatic plant waterer (3/?): capacitive sensor try 2

Finally some progress!

  • Part 1: resistive sensing
  • Part 2: finding resistive sensing is bad and capacitive sensing is hard
  • Part 3: another crack at a capacitive sensor
  • Part 4: calibrating the sensor

Day V (weekend 5, has it really been going that long?)

OK, so I’m not really happy about the enameled wire design. It feels like the insulation is a bit fragile and I don’t really feel I know what’s going on well enough to rely on it. So, I’ll so something much better: smear some 5 minute epoxy over some stripboard and hit it with a heat gun…

 

 

 

 

Yes, this is not at all dubious. Well turns out it is. Who knew? Nonetheless it works decently well, though the insulation only goes a few cm up and I think it’s hovering at around 1GΩ. The capacitances are:

  •  Out: 13pF
  • Dryish soil: 20pF
  • Quite wet soil: 30pF
  • Very wet soil: 44pF

Substantially less sensitive than the previous one, but proves the principle. If I can actually sense that level of capacitance using the Arduino, then I can get a nice double sided one made with the good quality thin and robust coating you get on PCBs.

On to the Arduino!

So the Arduino environment doesn’t natively support the comparator. Fortunately its not hard. Just fiddly. As in spending 2 hours on a really silly mistake…

It’s fairly straightforward given the datasheet, specifically section 27 AC (analog comparator). The easiest way to get started is:

  • Not using the multiplexer, which means the negative input is AIN1
  • Using the bandgap (1.1V reference) for the positive input
  • Polling by reading ACSR.ACO (analog comparator status register.analog comparator output)
  • No low power stuff (it’s a high power application anyway)

It’s surprisingly easy. The Atmega328p has nice defaults for prototyping (everything starts on), there are not too many registers to swizzle up the pins and its happy to have two functions (GPIO and comparator) on one pin at the same time. The bit that I got hung up on for hours is that AIN1 is the Atmega328-P’s AIN1 pin, not the Arduino’s AIN1 pin. AIN1/PD7 (in Atmel-speak) is actually digital pin 7 in Arduino speak. N00bish mistake but really easy to make.

The basic code to control an LED looks like this:

const int led = 13;

void setup() {
  pinMode(led, OUTPUT);     

  // Set ACME bit to 0 to disable the multiplexer
  // This also sets some ADC related flags
  ADCSRB  = 0; 

  // Set the positive input to the bandgap reference.
  // This also sets disable to off, interrupts to off
  // and a bunch of other stuff to off.
  ACSR = bit(ACBG);
}

void loop() {

    bool result = ACSR & bit(ACO);
    digitalWrite(led, result);
}

It works. Yay. Only slightly dampened by the wild goose chase over pin numbers.

HONK!

A wild goose, for illustrative purposes. (CC by SA https://commons.wikimedia.org/wiki/File:Greylag_goose_(Anser_anser)_head.jpg)

Day 6 (Weekend 6)

Well, this is interesting. The epoxy based probe (above) is now reading a steady 10M even in dry soil. Looks like that isn’t a long term solution. The best wire based one is now faring a lot better. I’m resigned to either having a custom board made with proper soldermask or using conformal coating.

So back to the circuit. Now because for some reason I’m intent on absolutely minimizing cost, an important part is minimizing the pin usage. So the circuit is simply this:

20190317_121550

All the clever bits of the circuit are provided by the microcontroller.

The capacitor charges from the positive rail through a 1M resistor.  Internally, I’ve got the comparator connected to 1.1V. The equation for the voltage is:
V = V_0(1 - e^{-\frac{t}{RC}}).
Rearranging gives:
t = -\ln (1-\frac{V}{V_0})RC
Substituting in the test capacitor (47pF), the 1M resistor, the 5V supply and the 1.1V reference gives a rather marginal 12μs. For now to make life easier, I’m going to use this circuit:

20190317_121721

Making a 1.65V rail with resistors means that the 1.1V threshold is on a much flatter part of the charging curve, increasing the time a lot.

Making a potential divider off the 3.3V rail gives 1.65V for the supply, and a much more generous 50μs. Passives are cheap, and I can greatly extend the charging time pretty easily by dividing down the supply. But we need some code to drive it.  The code implements a basic relaxation oscillator: let the capacitor charge then when the voltage exceeds the threshold, short out the capacitor to restart the cycle, then let the capacitor charge…

void setup() {
  // Set ACME bit to 0 to disable the multiplexer
  // This also sets some ADC related flags
  ADCSRB  = 0; 

  // Set the positive input to the bandgap reference.
  // This also sets disable to off, interrupts to off
  // and a bunch of other stuff to off.
  ACSR = bit(ACBG);

  // set PD7 to either hi-Z or low (depending on DDR)
  PORTD &= ~bit(7);
}

void loop(){
    DDRD &= ~bit(7); // Set pin 7 to hi-z

    //Loop until the AC outputs 0 (i.e. when the capacitor
    //exceeds 1.1V)
    while(ACSR & bit(ACO)){}

    DDRD |= bit(7); // Pin7 to low, emptying the cap

    delayMicroseconds(50);
}

And here’s what the voltage looks like in operation:

 

 

In order to get nice graphs I either had to touch a grounded thing or switch off my fluorescent desk lamps since they seem to spew noise all over the place.

It’s not really very useful like this since all it’s doing is displaying a nice graph. The scope also disturbs the signal since it’s got a non-trivial capacitance and resistance. To do some further analysis, I wrote the following code:

void setup() {
  ADCSRB  = 0;
  ACSR = bit(ACBG);
  Serial.begin(9600);
}

float o=0, o2=0; //IIR filter state for count and count squared
int i=0;

void loop(){
    PORTD &= ~bit(7);
    DDRD |= bit(7);
    DDRD &= ~bit(7);

    uint16_t count=0;
    while(ACSR & bit(ACO)){
      count++;
    }
    DDRD |= bit(7);

    o = 0.999*o + 0.001 * count;
    o2 = 0.999*o2 + 0.001 * count * count;

    if(i++%256 == 0){
      Serial.print(o);
      Serial.print(" ");
      Serial.println(sqrt(o2 - o*o));
    }
}

This code counts during the charging part of the cycle, then does a moving average on both the count and count squared using a simple IIR filter and prints the running mean and standard deviation of the counts to the serial port. I happen to be a big fan of IIR filters, I think they’re fun, interesting and efficient. Even the simplest one is much better than a naïve moving average. The trick of filtering both the value and value squared is one I’ve used many times for getting a running standard deviation in addition to mean.

By default I get counts of about :

  • No touch: 88.2 (σ=4.1)
  • Light touch: 110 (σ=5.5)
  • No touch with scope: 139

I can even spot proximity, so its really pretty sensitive, and you can see how much the scope loads it down by. It also turns out I was really pessimistic earlier. Reverting back to the simpler circuit, the numbers I get are:

  • No touch: 19.9 (σ=1.3)
  • Light touch: 26 (σ=1.7)

I can still spot proximity, but only with the aid of the filter: it’s about a count of 0.2 or less. So for fun, I modified the code to turn on the LED when the count exceeds 20.2, and you can see just how sensitive it is:

 

I think now that having faster charging helps: while there’s more quantization noise in the signal, the comparator changes state on a steeper part of the curve which means that electrical noise has less effect on the time.

Today’s conclusions

  1. The capacitive sensor is really good, cheap and easy to make. I’m going to have to use that for other things too
  2. It’s definitely the way forward for this project
  3. Something worked easily!

 

Building an automatic plant waterer (2/?): resistive sensing

This was harder than I expected.

  • Part 1: resistive sensing
  • Part 2: finding resistive sensing is bad and capacitive sensing is hard
  • Part 3: another crack at a capacitive sensor
  • Part 4: calibrating the sensor

Day III (weekend 3)

Not really much time this weekend. I pulled out the electrode and (it had been sitting there unpowered) and saw this:

Snapchat-910764504

Copper salts deposited on the electrodes. It was really hard to get my phone to reproduce the colour.

It looks like corrosion has already started. There’s not much but it’s only been there a few weeks and has probably spent a few of hours powered by now. With my current plan (maybe waking up every 30 minutes), the amount of time ‘on’ would be about 16 minutes per day (10 seconds of higher current charge in each direction). That’s only a week or two before it reaches these levels of corrosion. So, that I think precludes 10 second measurements, or at least 10 seconds of direct charging without a resistor in the way.

Day IV (Weekend 4)

Wow really not getting as much time on this as I’d like. So, what about capacitive measurements? Having insulated electrodes should preclude any corrosion problems and I’ll bet that using soil as dielectric will increase the capacitance as the water content increases. First, an initial experiment:

capacitor-1

The sensor is a bit of electrical tape over some strip board.

This indicates we’re into the realms of possibility, though the number of picofarads is still small enough to be pretty irritating. It’s also a pretty useless soil sensor: soil/water get through the holes behind and the result is a measurable resistance between the electrodes (about 9M or so). And the insulator is pretty thick which is going to make the capacitance low and reduce the sensitivity.

I do have some enameled wire in various grades. The finest (0.14mm) has a very thin coating. I made a couple of different sensors using the wire, mostly wrapping it around lots to get a decent surface area:

Snapchat-605221828

A couple of attempts at a capacitive sensor. Left, interleaved wires, right the two plates are well separated.

One slight problem: it doesn’t measure open circuit; there’s about 15M between the two sides, rising as it dries off. The flat one measures about 28pF when in the air, and about 280 in damp soil, rising to about 2nF when just watered. Unfortunately I don’t know how much the resistance is affecting this, so I’m going to have to try again. I’m going to try the next thicker grade of wire I have (0.23mm) and incidentally it has a different color coating.

Having a nice large spacing between the two plates seemed to work well in that it was easy to clean and reset back to the dry state. So, on to version 2:

Snapchat-2045180743

Version two of the sensor with thicker wire and nicely soldered joints. 40 turns of wire in each section.

As a reminiscent aside, I remember soldering lacquered wire back in the olden days with my fixed temperature iron. I could never settle on fine sandpaper versus a flame to remove it. Those days I do not miss, now I just crank up the iron temperature.

Anyway this seems to be going better: the resistance is greater than 2G. I think I might have mentioned it before but my multimeter skipped leg day. It can measure up to 2GOhm, but only down to 20mA. Weird. On to the capacitance measurements. So they are:

  • BOGUS! that’s what they are, bogus!

Well shoot. It seemed to be working great, but after a bit of use the resistance is back to being about 10M. That’s disappointing. OK, try3! I’m going to wrap the wires longitudinally so that they never even cross:

WLPjJ2i

I forgot to take a picture of it! Look at the “fix” below with hot-melt to get the idea.

Anyway the wires are always separated by about 4mm. So the measurements are:

  • First use: 12pF
  • Finger lightly on one side: 28pF
  • Fingers pressed on both sides: 100pF
  • Damp soil: 185pf, 233pF, 202pF, 190pF
  • Slightly compacted damp soil: 323pF,
  • Same place during watering: 680pF
  • Resistance: 12M

orly

OK well, this is getting suspicious. The 20M range is maxed out. But the 2G range reads low (there’s nothing in between, that’s only a few % difference). Now the capacitance reads in the nF range as well. Hitting it with a heat gun seems to reset everything.

So putting a blob of water on in the middle doesn’t do anything. Butting a blob of water on the end where the wires are bent round quickly drops the resistance back town to 10M. I think the act of wrapping the wire breaks the insulation very slightly. Well, that’s irritating. Let’s see:

Fixed with hot melt

If you use hot melt and don’t have a reflow style hot air gun, you’re really missing out.

OK, so the new measurements:

  • Damp soil: 250pF, 360pF
  • During watering: 1nF
  • After watering: 600pF and dropping
  • Resistance: 𝟚𝟘𝕄

rage

Apparently there is something hot-melt can’t fix. Observing more, the resistance is climbing very slowly, up to 26 now, now 40. Well, it might not matter. If I keep my measurement resistors well under the 20M range (say 200k), then the small error incurred due to leakage won’t matter. Still, I’d prefer to have it work properly.

So where are we? The capacitance sensor definitely works after a fashion, but we need to measure it. It bottoms out at 30pF, and is well into useful readings at about 300pF or so. I think I could get away with a 1M resistor safely. For an RC circuit, that would give a time constant of about 30us, which is small, but that’s at the 0 end of the range. It’s just about measurable on an Attiny85 with the 16MHz clock.

Additionally, the Attiny85 has a built in comparator. So, my current mental design has a relaxation oscillator in mind: charge up the capacitor through a 1M resistor, then discharge through a GPIO pin once the voltage crosses a threshold.

Sounds like a plan.