Friday, 26 August 2016

A bit more on PWM IR and Arduino

We've had a few questions about our PWM IR data transfer idea. And most of them revolve around "why send an end of message marker at the start and the end of the data?"

Some people went so far as to suggest that only an end marker would be necessary, We disagree with this. Some people asked why we weren't using a start marker and an end of message marker. This makes some sense. But here's why we did it the way we did:

Firstly, we need a marker at the start AND end of the message. Otherwise while the IR receiver is exposed to sunlight, it might start creating extraneous bits and bytes (unlikely, since we have a defined PWM width we listen out for and ignore anything outside of these widths, but still possible).

At the start of a message, we clear down our byte value buffer so we know that what follows is being added to a "clean" variable, and not tacked onto the end of some random noise.

At the end of a message, we parse the contents of the bits and bytes received. We could have used a different start pulse, but our pulse widths are already getting quite wide. A bit value zero is up to 4ms long, a bit value of one is up to 12ms long, and our EOM marker is up to 20ms long. To make another, clearly definable pulse wdth, we'd probably have to go up to 40ms long. That's as long as it would take to send x10 zero values!

There's nothing wrong with creating a different start-of-message pulse width, but we just felt it was unnecessary. At the start of a message, if we sent an end-of-message width, we'll parse any random noise that's been received and expect it to fail (since all messages have a checksum byte at the end). After parsing a message we reset the internal buffers anyway. So there's no reason why we can't use the same pulse width at both the start and end of each message.

So that's what we did.
Hope that clears that up!

Wednesday, 24 August 2016

Sending/receiving IR data via PWM on an Arduino

Many years ago we did some low-level data exchange using radio modules and Manchester encoding. In a recent project, for real-life, work work, we were tasked with sending simple packets of data via IR. Naturally an IR 38khz receiver was tried and worked quite well.

Every now and again, the received data sort-of burped, so we sent each byte along with it's compliment value (so a value, say of 0xF0 would always be followed by a value of 0x0F or b11110000 would be followed by b00001111). The idea being that for every pair of 8-bit values, the XOR sum would always be exactly 0xFF.

We found that if we sent a single byte value, followed by it's compliment, and repeated this "packet" of data twice in quick succession, even if one packet failed validation, the second would always "get through".

Everything was great - for one-way communication.
Once we decided we wanted two-way comms, things got a bit trickier. But only because we're working to really tight margins when it comes to space; we simply don't have enough room to mount a 38khz IR receiver and a 3mm IR LED in two different devices.

 Because of space constraints, we just didn't have the room to use both an IR receiver and LED together in each device.

With space being tight, we figured that we could use an IR reflective sensor to give us our IR receiver and LED in a single, tiny, 1206-sized package. Some IR reflective sensors are just a 3mm LED and a 3mm photo-transistor in a single package


But what we were after was one of those really tiny ones, with the same kind of pinout and independently controlled LED/phototransistor combination, but in a not-much-bigger-than-a-1206 sized package.


The idea with these is that you activate the IR LED and then look for a reflected signal (when the photo-transistor receives IR light, it can be used to pull an input low, for example). But there's nothing to say we can't use two of these, facing each other, and have one device "listening" while the other is "talking". Instead of reflected IR, we'd just capture IR light sent directly from the other device. Genius!

The only thing is our photo-transistor doesn't respond to a 38khz carrier, like the larger, single, IR sensors (which is useful if you're firing IR light across a room, to a TV and need to filter out extraneous IR light from the sun and fluorescent lights). Our photo-transistor will simply conduct as soon as it sees and IR light, from any source. But given that we'll be transmitting data in a controlled environment (and not across the room) we either have to generate our own 38khz carrier wave (and decode it on the receive end) or simply forget all about it...
Guess which approach we took?

So doing away with the 38khz carrier, we simply have a receiver that pulls an input pin low when it can see IR light. We decided to try simple PWM to send data into the sensor.

The basic approach is that whenever a device sees a high-to-low transition on the input pin, we reset a timer/counter. This is because a high-to-low input signal means the IR led has just gone from low-to-high (i.e. just turned on). Then, when the input goes low-to-high, we know that the LED has just turned off (since we're using pull-up resistors on the input and using the photo-transistor to pull to ground when it sees IR light).

Following a low-to-high input, we look at the width of the pulse (in milliseconds). A simple look-up goes like this:

1-3 ms = bit value zero
6-10 ms = bit value one
15-20 ms = start/end of message marker

any other duration, ignore.

Whenever we get a "wide" pulse, we've either just started, or just ended, a message. Irrespective of which, look at the previously received bits of data and parse them. At a "start" pulse, we'd expect their to be no previous data, so we can skip parsing. After an "end" pulse, we should have a load of bits of data to parse. After a wide pulse, we reset the binary bit counter and set the incoming message buffer to blank again.

It's simple.
It's crude.
It works surprisingly well.

The only thing is, we want to make sure we're not parsing gibberish data. Which means we need some kind of checksum, to validate all the previously received data. We figured that the easiest method would be to send data in 3-byte packets, with the fourth byte acting as the checksum.

On receiving data, we'd recreate the checksum value from the first three bytes and compare it to the fourth. If the fourth byte and the checksum byte match, we accept the data and decide what to do based on the three-byte message.

The send routine uses simple delay routines to send bursts of IR light


int ir_pin = 2;
long ir_val;

void sendIRValue(){

     // start of message marker
     digitalWrite(ir_pin,HIGH);
     delay(16);
     digitalWrite(ir_pin,LOW);
     //delayMicroseconds(200);
     delay(1);
     
     for(int i=0; i<32; i++){
          int j=ir_val & 0x01;

          digitalWrite(ir_pin,HIGH);
          if(j==0){
               delay(2);
          }else{
               delay(8);
          }
          digitalWrite(ir_pin,LOW);
          //delayMicroseconds(200);
          delay(1);

          ir_val = ir_val >> 1;
     }

     // end of message marker
     digitalWrite(ir_pin,HIGH);
     delay(16);
     digitalWrite(ir_pin,LOW);
     
}

void setup() {
     // put your setup code here, to run once:
     Serial.begin(9600);

     // light the LED for a couple of seconds just so
     // we can see if it's working
     pinMode(ir_pin,OUTPUT);
     digitalWrite(ir_pin,HIGH);
     delay(2000);
     digitalWrite(ir_pin,LOW);
}

void loop() {
     // put your main code here, to run repeatedly:

     long k = random(0,256);
     long j = random(0,256);
     long     i = random(0,256);
     long h = k ^ j;
     h = h ^ i;

     Serial.print(F("sending values - k:"));
     Serial.print(k,HEX);
     Serial.print(F(" j:"));
     Serial.print(j,HEX);
     Serial.print(F(" i:"));
     Serial.print(i,HEX);     
     Serial.print(F(" checksum:"));
     Serial.print(h,HEX);
     
     k = k << 24;     
     j = j << 16;     
     i = i << 8;

     k = k | j;
     k = k | i;
     k = k | h;
     ir_val = k;

     Serial.print(F(" sent:"));
     Serial.print(ir_val,HEX);
     
     Serial.println();
     
     
     sendIRValue();

     delay(2000);
     
}


The receive routine uses interrupts to detect when the IR photo-transistor goes either low-to-high or high-to-low


int ir_in = 2;
int led_pin = 13;

long int_vcc;
long min_vcc;
long mil_ir_start;
long mil_ir_end;
long mil_ir;

long ir_val;     // we'll just make this a 32-bit value
int ir_bit_count;


// IR high and IR low are back-to-front in the receiver.
// If we're sending IR, the sensor will be low (its an open drain collector that
// pulls an input LOW when it can see IR light) So IRLow relates to the LED being lit

void IRLow(){
     // this fires on a high-to-low transition
     // whenever the line is pulled low it's because we're receving IR light
     // so reset the timer/counter
     mil_ir_start = millis();     
     digitalWrite(led_pin,HIGH);
}

void IRHigh(){
     // whenever the line floats high, its because we've just turned off the IR light
     // that is sending data to the receiver, so measure the width of the last pulse
     // and do something wisth the data if necessary
     mil_ir_end = millis();
     mil_ir = mil_ir_end - mil_ir_start;
     digitalWrite(led_pin,LOW);
     
     if(mil_ir < 11){
          Serial.print(mil_ir);
          Serial.print(F("."));
     }

     // decide what to do with the pulse width
     if(mil_ir >=1 && mil_ir <=4){
          // treat this as a zero
          ir_val = ir_val << 1;
          ir_bit_count++;
          
     }else if(mil_ir >=6 && mil_ir <=12){
          // treat this as a one
          ir_val = ir_val << 1;
          ir_val = ir_val|1;          
          ir_bit_count++;
          
     }else if(mil_ir >=14 && mil_ir <=20){
          // this is a start/end message marker
          // if we've received a message, validate it and parse
          Serial.println();
          if(ir_val != 0){ parseMessage(); }
          
          // now reset everything ready for the next blast
          ir_bit_count = 0;
          ir_val = 0;
     
     }

     
}

void parseMessage(){
     // a message can be up to three bytes long
     // we'll do simple XOR checksum on the fourth byte
     // and squash them all together

     int a = ir_val >> 24;
     int b = ir_val >> 16;
     int c = ir_val >> 8;
     int d = ir_val & 255;

     a = a & 0xFF;
     b = b & 0xFF;
     c = c & 0xFF;
     d = d & 0xFF;

     int k = a ^ b;
     k = k ^ c;
     if(k==d){
          // checksum success
          Serial.print(F("Received: "));
          Serial.print(ir_val,HEX);
          Serial.println();
          
     }else{
          // checksum fail
          Serial.print(F("checksum fail a:"));
          Serial.print(a,HEX);
          Serial.print(F(" b:"));
          Serial.print(b,HEX);
          Serial.print(F(" c:"));
          Serial.print(c,HEX);
          Serial.print(F(" d:"));
          Serial.print(d,HEX);
          Serial.println(F(" "));
          
     }
     
}

void IRChange(){
     int b = digitalRead(ir_in);
     if(b==HIGH){ IRHigh(); } else { IRLow();}
}

void setup() {
     // put your setup code here, to run once:
     Serial.begin(9600);

     pinMode(led_pin,OUTPUT);
     pinMode(ir_in,INPUT_PULLUP);

     // create an interrupt on pin 2 (IR receiver)
     attachInterrupt(digitalPinToInterrupt(ir_in), IRChange, CHANGE);
     
}

void loop() {
     // put your main code here, to run repeatedly:
     
     delay(1000);
     
}


We also added a bit of debugging to ensure that we were getting accurate data. Whenever we see a single pulse of IR light, we output the duration of the pulse. This makes it easy to debug.


8.2.8.8.8.7.7.2.2.2.8.2.9.8.8.2.7.8.7.8.8.2.2.9.2.8.7.1.7.1.1.7.
Received: BE2EF969

8.2.2.7.7.1.1.1.7.1.1.1.1.7.8.8.8.7.7.7.7.9.7.1.7.1.7.1.
checksum fail a:9 88 7F EA

8.9.7.7.1.1.1.8.1.7.2.2.2.2.2.8.2.3.2.8.2.1.2.7.7.2.7.1.1.1.1.7.
Received: F14111A1



-- interrupted here ---
2.7.8.1.7.7.
checksum fail a:0 0 0 1B




3.8.8.2.2.8.3.2.8.2.8.2.8.9.2.8.2.2.8.2.2.2.3.8.8.8.8.2.9.3.3.3.
Received: 64AD21E8

2.8.2.8.2.9.8.8.2.2.8.9.2.8.8.8.2.9.7.8.2.2.8.2.2.2.2.8.2.2.8.2.
Received: 57377212

If we take the first line and look at the length of the pulses, we can see that 8ms = 1 and 2ms = 0. So our pattern becomes

1011 1110 0010 1110 1111 1001 0110 1001

A quick binary-to-hex conversion shows us that

1011 = B
1110 = E
0010 = 2
1110 = E
1111 = F
1001 = 9
0110 = 6
1001 = 9

And that's exactly what appeared in our serial output.
So we've got some data. So we take the first byte 0xBE and XOR it with the second byte 0x2E. Then we take the result and XOR that with the third byte 0xF9 and the result.... 0x69,

And that's what our fourth byte value is. So we know we've got a valid message. If any single bit value of the message were incorrectly received, the XOR sum of the fourth byte would be different, and we'd know to throw that message away.

To prove this, we interrupted the IR signal as it was trying to send data.
At this point (see debug output above) as soon as we received a "long" pulse to indicate the end of a message, the XOR checksum failed (because the XOR sum of the bits received did not match the value of the final byte in the message).

As we're sending 32 bits with a maximum delay of 8ms, the longest time we'd spend sending a message is 256ms (actually it'd be 288ms because we have a 16ms long pulse at the start and at the end of each message). So about a third of a second to blast data across.
Often it's much less (since a zero bit value takes only 2ms to send).

So it's slow.
And crude.
But also very robust.
At least in our, specific, controlled environment.

Which means it'll do for now!


Sunday, 21 August 2016

Google - please stop breaking the internet

Google is killing the internet.
For a while, we've argued it's advertising.
Back in the 90s it was porn.

But in 2016, it's Google.
And they need to stop it!

Google Chrome was a great browser when it launched, but it has for years been a bloated monstrosity that would make Microsoft cringe with any of their earlier IE offerings (in fact, we thought IE10/11 was a great browser - exactly what Chrome promised to be).

But it's not just their browser. Google also encourage websites to link to their hosted ajax. Which makes some websites to run slooowly, as the entire javascript framework has to load from an external site before the page even renders. And it also encourages web builders to embed Youtube videos directly into their pages. And that causes some websites to run slooowly as often the jQuery based layout requires the video to populate the frame before the rest of the site appears.

And Google also infects almost every website (that hosts Ad-sense banners) with stupid, slow-to-load adverts that cause the entire computer - not just the browser, or the current page - to lock up entirely until every last bit of shite has finishing loading.

In short, the experience of browsing a simple web page in 2016 is slower than it was in 1998. And back then we had 56kbs dial-up and GIFs. Today I've got 100mbs broadband and a computer at least x8 times more powerful than my desktop PC at the time.

The irony that we're hosting a blog on Google-owned Blogger, and embedding Google-owned Youtube videos in the pages isn't lost on us, here at Nerd Towers. And it has been very tempting to give in to their almost constant demands that we apply AdSense to the account and rake in about twenty pence per month in return for making the site unusable with adverts - but there's no point complaining about other sites spoiling their user's experience and then doing the same thing ourselves!

Now I'm no internet privacy prude.
I don't mind Google reading my Gmail emails in return for free email and targetted ads. I'm not one of the tin-hat brigade who get paranoid about companies tracking my every move on the internet. I can't help but think that it'd make for pretty boring reading. I understand that linking content from different hosts makes for a richer experience.

But it's almost like Google is actively breaking the 'net.
The latest example of this was Youtube simply not working tonight. And not just in the Chrome browser.


Tonight I tried to tune in to the Terrain Tutor's live stream to see Mel in his new studio in Stoke-on-Trent. The video refused to play. The comments and live-chat thing worked just fine, but the video frame showed a freeze-frame of a gurning face and no video (or audio) was forthcoming. The little busy logo just span in the centre of the video, where a play/pause button should have been.

That was in Chrome. In IE the video was replaced with a static white-noise animation and the message "an error occurred, please try later". Same in Edge, and Firefox.

The problem was with the Youtube site, not my computer, as the same result happened on a second PC and the video refused to play (in a Chrome browser now I come to think of it) on my phone. Then I came across this question:

http://stackoverflow.com/questions/28195610/why-is-this-error-appearing-in-chrome-load-resource-neterr-quic-protocol-erro

load resource: net::ERR_QUIC_PROTOCOL_ERROR

so out of curiosity I entered chrome://flags/#enable-quic into my address bar.



And disabled Experimental QUIC protocol.
Suddenly Youtube started working properly.
And websites which were either unusable, or ran really, really slowly were now just running annoyingly slowing (instead of un-usably slowly). Now how this managed to affect the IE/Edge brower, I've no idea.

But with all the shit that Google is pumping out into the internet, it's making many websites literally unusable. The problem is, even if I were to boycott every Google-based product and only ever use Opera browser to view web pages, the Google Rot is in just about every web site written since 2004 - so there's no getting away from it.

Please, Google.
The internet used to be amazing.
Put it back how you found it.
If you can't make it better, just stop bloody-well breaking it.


Saturday, 20 August 2016

Soldering hall sensors to our copper strips

With the copper in place and the hall sensors prepared, it's time to stick them all down! It's quite easy (if not a little tedious) but if you're not confident with soldering, you can always do away with the solder and use conductive glue (we'll have to make a video showing how to use conductive glue as an alternative).

We prefer solder because it's instant. Conductive glue requires time to set (usually overnight) before it even works properly. With solder, as soon as it's cooled, you've got an electrically conductive, as well as a strong mechanical, joint.

Here's how we go about sticking our hall sensors down


This video only ever had an intended audience of one. We made it to give to one person who hadn't seen any of the ongoing builds, to see if they could understand and follow it. It's poorly lit, the sound is terrible, the noise from slurping coffee is distracting, and hands and arms get in the way all over the place. Sorry.


Thursday, 18 August 2016

Preparing the hall sensors for our electronic board game

With all the copper tape in place on the board, it's time to stick down the hall sensors. Before sticking them down, it's worth taking a bit of time to prepare a load of them beforehand - preparing, cutting, placing and sticking one hall sensor at a time is pretty tedious and time-consuming. We like to prepare 16 at a time, so you can feel like you're really making progress as you can complete an entire quarter of the board section in one go!

This video only ever had an intended audience of one. We made it to give to one person who hadn't seen any of the ongoing builds, to see if they could understand and follow it. It's poorly lit, the sound is terrible, the noise from slurping coffee is distracting, and hands and arms get in the way all over the place. Sorry.


Links to files, templates, laser-cutting layouts and schematics and firmware will be posted once the assembly process has been finalised.

Sunday, 14 August 2016

Finishing the copper for our electronic board game panel

After creating eight horizontal "rows" of copper strips, we had to complete the grid effect with vertical columns. We used masking tape as an insulator between the "layers" of copper tape.

Frustratingly, the camera slipped during the filming, so a lot of stuff is off-screen or right at the edge of the video. Stupid, cheap, poundland phone-camera tripods!


This video only ever had an intended audience of one. We made it to give to one person who hadn't seen any of the ongoing builds, to see if they could understand and follow it. We gave them a kit of laser-cut bits, some components and wanted to see if they could make a board section, without any intervention, just by watching the video.

It's poorly lit, the sound is terrible, the noise from slurping coffee is distracting, and hands and arms get in the way all over the place. Sorry.

Saturday, 13 August 2016

BHPC vs Herts petanque trophy


This weekend the might Brighton & Hove Petanque Club are playing their annual challenge match against Herts. It's an occasion in the boules calendar that everyone looks forward to - because it's boules at the beach with beers.

This year, we thought it'd be nice to play for something other than just bragging rights. As the competition has been dubbed "the stags against the seagulls" I cobbled together this concoction:


The stag in rampant pose is from the Hertfordshire County shield. Instead of an opposing stag and shield in the middle, I thought we needed something a bit Brighton-y. And a boule. A quick hunt around on Google images and some manual tracing in Inkscape (pencil tool set to 40% smoothing) and the resulting outline looks quite nice.

Note to self: don't ever Google search images for "rampant stag" unless safe search is turned off....

I figured we could cut the design from some nice shiny acrylic (sourced from Brighton and Hove Plastics in Portslade no less) and mount it on a posh plinth as a trophy to play for at the weekend. For anyone who plays petanque in either Brighton or Hertfordshire, has a laser cutter and who wants to look like they're a member of the winning side in this illustrious competition, here are the design files to create your own:

 
EDIT:
The trophy has since been awarded. So we don't have a photo of it with our spangly Stags v Seagulls topper on it. However, here's a photo of the two teams - on a lovely sunny August afternoon.