All posts by georgedewar

Fun with UI blocking and progress bars

I recently stumbled across an interesting problem, which I can’t find many people asking questions about. I’ve been working on some visualisations to do with New Zealand’s electricity spot price market, which rely heavily on dc.js and crossfilter. That Generation tab you see has a lot of data behind it, and it takes a good few seconds to load.

The obvious thing to do was to show a sensible progress bar, so users could see that something was in fact happening. NProgress fit the bill very nicely – except that the various tasks involved in setting up crossfilter and building the charts block the UI thread, preventing any progress bar updates from actually taking effect.

This (in the general sense) is a common problem, and the common solution seems to be to use

window.setTimeout(myCode, 0);

to asynchronously queue the code up to be called after a zero millisecond delay (which means, after the stack is empty). This works great, but what if you have more than one thing you need to do?

I actually couldn’t find much in the way of people talking about this, which probably means that either there’s an incredibly obvious solution I don’t know about, or nobody is trying to show a progress bar for dc.js… After all, we do try to avoid big computations in the browser under usual circumstances. After you’ve read this, let me know if you’ve dealt with something similar!

Anyway, things are executed in the right order if you have a sequence of these calls, in Chrome at least:

window.setTimeout(function() { console.log("Hello"); }, 0);
window.setTimeout(function() { console.log("Hello again"); }, 0);
window.setTimeout(function() { console.log("Goodbye"); }, 0);

But the UI thread is still blocked! I think this is because the stack is never free for UI things to do their business until after all three of these calls have completed.

So, then, it seems that one must nest these calls:

window.setTimeout(function() {
console.log("Hello");
window.setTimeout(function() {
console.log("Hello again");
window.setTimeout(function() {
console.log("Goodbye")
}, 0);
}, 0);
}, 0);

Yuck! After verifying that this did in fact solve my problem, I thought it was time to encapsulate the technique into something a bit more convenient. So I wrote a function called LoadChain:

function LoadChain() {
  this.queue = [];

  this.push = function(f) {
    var self = this;

    // Push a function onto the queue that executes the user-specified function, then sets a timeout to execute the
    // next function if there is one
    this.queue.push(function() {
      f();
      var next = self.queue.shift();
      if(next) window.setTimeout(next, 0);
    });
  };

  this.start = function() {
    var first = this.queue.shift();
    first();
  };
}

Now my code can look like this:

var loadChain = new LoadChain();
loadChain.push(function() { console.log("Hello"); });
loadChain.push(function() { console.log("Hello again"); });
loadChain.push(function() { console.log("Goodbye"); });
loadChain.start();

This is basically what I did in my aforementioned app, and it works well – now I can increment the progress bar when the data is loaded, when dates have been parsed, when crossfilter has been set up, after creating each dimension, after creating each chart, etc and have a good indication of the actual loading progress – invaluable on a slower machine where there might be a several second wait.

Have you solved this problem a different way? I’m interested to hear any thoughts.

 

Advertisements

Using PID on an Arduino to control an electric heater

I’ve done a lot of small hacky home electronics projects, but this is my first time writing a blog post about one. Here goes…

20150726_195355
Trusty old oil-fin heater

My wife and I live in a typical ’40s New Zealand house (which has minimal insulation in the ceiling, none in the walls and single-glazed windows), and like most Kiwis our normal winter behaviour is (at least some of the time) to simply put up with the cold.

Upon having a baby, this had to change somewhat for a while, so we turned to the trusty electric oil fin heater to keep our bedroom warm. This has a basic mechanical thermostat, numbered 1 – 6 which corresponds not so much to the room temperature as the heater temperature.

What this means is that the thermostat needs to be constantly adjusted as external factors change (such as the temperature outside). With practice one can get quite good at this, but for me it was an opportunity to make a new gadget.

First, though, I went looking for a product that solves this problem – a plug-in thermostatic controller. I found something which in Australia and New Zealand is sold as the HeaterMate.

The HeaterMate (image from HeaterMate website)
The HeaterMate (image from HeaterMate website)

This appeared to be exactly what the doctor ordered, but turned out to be quite unimpressive. The first problem is that the plug of an appliance drawing ten amps can easily have a bit of warmth to it, and relays have their losses as well. I think this is why, once it’s been in use for a while the temperature that the HeaterMate thinks the room is becomes up to 4 degrees too high! The second issue is that the HeaterMate’s approach to temperature control appears to be frustratingly naive. It turns the heater on until the room temperature reaches the setpoint, then turns it off again until the temperature is 1 degree below the setpoint. The heater itself stores a reasonable amount of energy, which compounds the problem by making it undershoot and overshoot this range. Furthermore, the location where a heater plugs into the wall is (a) usually not a convenient spot for temperature controls and (b) in some cases may be close to the heater itself (in the case of panel heaters).

What I wanted was something that could find the right power level for the heater, and maintain that to provide a near-constant room temperature, and I thought that the PID algorithm (which is what makes your cruise control work) might be exactly what was needed. I also figured that it would help a lot to separate the temperature sensor from the part where the heater plugged in – more on that later.

I had a go at explaining PID at this point in the post (because a really simple explanation would have been extremely useful for me), but it turned out to be far too long. I don’t want to bore anybody, so I’ll see if I can write that up later in case it’s interesting.

Anyway, onto the implementation.

20150728_082313

I used an Arduino, and the super handy PID Library. This allowed me to set an output range of 0-100, which I used as a percentage power to run the heater at. I would then control the heater using really slow pulse width modulation, which initially was a 4 minute cycle (so, 75% power would mean that the heater was on for 3 minutes and off for 1 minute). I had a few of these lying around, so I simply got my Arduino to send the 433MHz on and off codes to one to control the heater. I switched to a 20 minute cycle after burning out the cheap relay within a couple of weeks…

20150726_195406
The Watts Clever remote control socket operates on 433MHz and can be easily controlled using the Arduino RCSwitch library.

Because I’m lazy, I’ve used the Seeduino Lotus, which is an Arduino Uno clone with a bunch of Grove connectors on it. This allows me to easily plug in bought modules (the I2C LCD screen, the temperature sensor, the buzzer) and use the connectors (which each have GND, +5V and two I/O lines) to connect my own peripherals (the 433MHz transmitter and the IR receiver).

Mainly because I didn’t have any buttons handy, I decided to use a spare remote control to control the thing, which gives me a luxurious set of “buttons” to control it with. All I’ve implemented so far is adjusting the temperature and the backlight brightness, but my intention would be to build a menu system where all aspects of the device can be adjusted.

I have not done much experimentation with tuning, but I used a proportional value of 45% (meaning that a 1 degree error will increase the power by 45 percentage points) and an integral value of 0.05, meaning 0.05 percentage points per degree error per second, or 3 per minute. I did not use a differential component. Despite the lack of tuning, I have had excellent results. This approach keeps the room temperature with 0.1 degree of the setpoint most of the time, and adjusts well to changes in conditions.

In the image above, the room temperature is exactly on setpoint, and the power level shown is the integral term which is doing its job of keeping it there. If something changes (like me opening a door or upping the setpoint), the proportional term helps to quickly react.

I feel that a product could be made of this (considering that the HeaterMate appears to be a successful product), but I don’t think I’d actually try to take it that far. My vision for it is that the controller unit would be a small battery-powered device that could be mounted on the wall. If I took this any further, the first things on my todo list would be:

  • Use an SSR for the plug-in unit for silent, fast switching
  • Use a larger display, that looks good without a backlight and can display information in a prettier format
  • Add a few buttons to the controller
  • Add timer functionality (because why not)
  • Add an alert feature – it could start beeping or at least light an LED if it becomes unable to achieve the desired temperature (due to the failure of the heater or something)
  • It could control multiple heaters in a zone
  • It could provide power usage estimates, as it would know when the heater was on (and could be told the power consumption of the heater when on)

My code, which is pretty messy, is up at https://github.com/GeorgeDewar/pid-thermostat. Finally I’d like to apologise for the formatting of this post. First time wordpressing, you see…

About Me

I’m a software engineer with a passion for making cool stuff that solves problems. Cool stuff doesn’t necessarily mean software.

Sometimes it’s software, sometimes it’s hardware, sometimes it’s a bit of both and sometimes it’s made of wood.

I’ve decided to start writing this in case some of my projects are interesting to people. Coming up will be write-ups on my in-dash Nexus 7 installation, my home automation system (it controls our heat pump and a few other things), and maybe a few little apps…