Category Archives: Code

Traffic light and pedestrian crossing implemented with an Arduino


This video shows the Traffic light and pedestrian crossing I’ve implemented with an Arduino. It’s a reproduction of the crossing near my home, timings taken from a video of it.

Pedestrian light_bb

Incidentally, I produced the diagrams for this using a product called Fritzing.  It’s a nifty piece of software that allows you to draw a breadboarded version of your circuit, lay out the circuit schematic and then automatically design the artwork for a etched circuitboard. I haven’t experienced the latter, because of an autoroute bug in version 0.8 of Fritzing.

I exported the images as SVGs from Fritzing and discovered that WordPress won’t allow them to be uploaded because of security issues; presumably the ability to include JavaScript inside a SVG for animation (etc).  So then I exported as PNG, the lossless format.  One of the two images wouldn’t upload, but was acceptable to WordPress after scaling down. I started out publishing on the web using notepad and FTP, and look where I am now.

Hardware

Circuit diagram for pedestrian lights controlled by an AVR microcontroller

I’ve been using an Arduino Mega2560 as the development environment but I’m targeting something smaller for implementation. The code compiles (on the bulky Mega instruction set) to 3.5Kb, so I’m satisfied that as things stand I’m not going to blow any memory budget.

The LED lights all share a single 220 ohm current-limiting resistor, and the call button is pulled low with a 47K ohm resistor to prevent the input pin from floating all over the shop when the button isn’t pressed.

You may notice that the video doesn’t exactly match the diagram. That’s because it’s built out of bits and bobs I had lying around. The ~200-ish Ohm resister had leads that wouldn’t insert into the breadboard. Thus, alligator clips all over the place.

Software

The light cycle is handled with a state machine; the flashing of lights is effected via state changes. The state machine is triggered by interrupts; the ISRs (Interrupt Service Routines) are lightweight, with the “heavyweight” processing for the state machine occurring in response to changes made in the ISRs. To minimise the processing load in the buttonpress ISR a test has been cached in a variable.  The timer ticks over every half second, giving the state machine a half-second resolution – which seems to match what happens in the real world.

The state machine is initialized into a safe state of having the traffic face a red light, and the pedestrians facing the flashing red man.  That means if the system restarts in the middle of a crossing cycle, no one gets killed.

Although the timer is fired via an interrupt, it won’t fire during a delay() so the delay in the main loop is very short.

Although the environment gives an opportunity to develop an OOP solution, their wasn’t any clear need for that level of abstraction, and microcontrollers tend to feel the additional cost of indirection. For example, accesses to members of the state were costly in terms of instructions and lead me to consider using multiple single dimension arrays, accessed by pointer.

#include <TimerOne.h>
//#define DEBUG
/*
Simulate a pedestrian crossing

An Australian pedestrian crossing has three traffic control lights, 
two pedestrian control lights and a light to acknowledge "call requests" 
(i.e. pressing the crossing button).
The traffic control lights cycle red -> green -> amber, solid in all.
The pedestrian control lights cycle red -> green -> flashing red.
The crossing button lights up the call request light, which stays lit
until the pedestrian control light turns green.
Once the traffic control light turns green, it stays that way for some time
before it will yield to a call request.  This is to ensure the road is not
continuously blocked servicing pedestrian crossing needs.

This code responds to two events: the passage of time and the pressing of
the call request button.  Outside of responding to these events the program
has no secondary task.  To optimize the performance of the CPU in its
secondary task, the primary tasks occur in response to interrupts.
*/
// Pin allocation:
const int CallbuttonPin = 2;        // the "I want to cross" button
const int lightCallAcknowledge = 3; // the light that says "you pressed the button"
const int lightGreenMan = 4;        // Pedestrian "walk now"
const int lightRedMan = 5;          // Pedestrian "Do not start walking"
const int lightGreen = 6;          // Traffic go
const int lightAmber = 7;          // Traffic stop if safe
const int lightRed = 8;            // Traffic stop
const int timerPin1 = 9; // lost to timing, can't be used for IO
const int timerPin2 =10; // lost to timing, can't be used for IO
const int onBoardLED = 13;      // on board, can be over-ridden or even cut

typedef struct {
public:
  byte timer_length; // How long to stay in this state (1 tick = 500ms)
  byte action;  // state to set the lights to
  char next_state_on_timer;
  char next_state_on_call_button;
} StateTransition;

const int bitClearCallButton = B00000100; // Clear call acknowledge
const int bitGreenMan =        B10001000; // "walk now"
const int bitRedMan =          B00010000; // "Do not start walking"
const int bitGreen =           B00110000; // Traffic go
const int bitAmber =           B01000000; // Traffic stop if safe
const int bitRed =             B10000000; // Traffic stop
const int maskControlLights = 
            bitGreenMan | bitRedMan | bitGreen | bitAmber | bitRed;

const char NoTransition = -1;
const StateTransition state[] = {
  {8,  bitAmber|bitRedMan,  1, NoTransition},  // Amber and Red Man (4 seconds)
  {4,  bitRed|bitRedMan,    2, NoTransition},  // Red and Red Man (2 seconds)
// Red light lasts for 28 seconds total - 56 ticks
  {21,  bitRed|bitGreenMan|bitClearCallButton,  
                            3, NoTransition},  // Red and Cross
// 7.5 Seconds of flashing red man                            
  {1,  bitRed|bitRedMan,    4, NoTransition},  // Red and Flashing Red Man
  {1,  bitRed,              5, NoTransition},  // Red and Flashing Red Man
  {1,  bitRed|bitRedMan,    6, NoTransition},
  {1,  bitRed,              7, NoTransition},  // 2s
  {1,  bitRed|bitRedMan,    8, NoTransition},
  {1,  bitRed,              9, NoTransition},  // 3s
  {1,  bitRed|bitRedMan,   10, NoTransition},
  {1,  bitRed,             11, NoTransition},  // 4s
  {1,  bitRed|bitRedMan,   12, NoTransition},
  {1,  bitRed,             13, NoTransition},  // 5s
  {1,  bitRed|bitRedMan,   14, NoTransition},
  {1,  bitRed,             15, NoTransition},  // 6s
  {1,  bitRed|bitRedMan,   16, NoTransition},
  {1,  bitRed,             17, NoTransition},  // 7s
  {1,  bitRed|bitRedMan,   18, NoTransition},
  {1,  bitRed,             19, NoTransition},  // 8s
  {9,  bitRed|bitRedMan,   20, NoTransition},  // Red and Red Man
// Allow at least 25.5 seconds of traffic through
  {51, bitGreen|bitRedMan, 21, NoTransition},  // Green and Red Man
  {99, bitGreen|bitRedMan, NoTransition,  0},  // Green and Red Man  // Loop if button pressed
  {1,  bitRed|bitRedMan,    3, 3},  // initial state
};
volatile char current_state = 16;
volatile char next_state = 3;  // Start in a safe state:
volatile byte ticks_remaining = 1;
boolean call_button_disabled = true;

void transition_to_next_state()
{
#ifdef DEBUG
  Serial.print((int)current_state);
  Serial.print(" transitions_to ");
  Serial.println((int)next_state);
#endif
  if (next_state == NoTransition) return;
  current_state = next_state;  
  next_state = NoTransition;

  // turn on the lights as per this state
  byte mask = B00001000;
  byte light=lightGreenMan;
  while (light < = lightRed)
  {
#ifdef DEBUG
    Serial.print("light pin ");
    Serial.print(light);
#endif    
    if (state[current_state].action & mask)
    {
      digitalWrite(light, HIGH);  // turn on the signal
#ifdef DEBUG
      Serial.println(" HIGH");
#endif    
    }
    else
    {
      digitalWrite(light, LOW);  // turn off the signal
#ifdef DEBUG
      Serial.println(" LOW");
#endif    
    }
    light++;
    mask = mask << 1;
  }

  // Turn off the call acknowledge light if that's something we do
  call_button_disabled = state[current_state].action & bitClearCallButton;
  if (call_button_disabled)
  {
#ifdef DEBUG
    Serial.println("CallButtonDisabled()");
#endif    
    digitalWrite(lightCallAcknowledge, LOW);  // turn off the signal
  }

  // start the timer until the next state
  ticks_remaining = state[current_state].timer_length;
}

void timer_tick()
{
  if (--ticks_remaining == 0)
  {
    next_state = state[current_state].next_state_on_timer;
  }
  // See if we can service any existing call
  else if (digitalRead(lightCallAcknowledge))
  {
    next_state = state[current_state].next_state_on_call_button;
  }
}

void call_button_pressed()
{
  // Don't acknowledge if it would be cleared
  if (!call_button_disabled)
  {
    digitalWrite(lightCallAcknowledge, HIGH);  // Acknowledge the request
  }
}

// the setup routine runs once when you press reset:
void setup() {
#ifdef DEBUG
  Serial.begin(9600);
  Serial.println("Traffic light simulation");
#endif    
  pinMode(CallbuttonPin, INPUT);     
  pinMode(lightCallAcknowledge, OUTPUT);     
  pinMode(lightGreenMan, OUTPUT);     
  pinMode(lightRedMan, OUTPUT);     
  pinMode(lightGreen, OUTPUT);     
  pinMode(lightAmber, OUTPUT);     
  pinMode(lightRed, OUTPUT);     
  Timer1.initialize(500000);         // initialize timer1, and set a 1/2 second period
  Timer1.attachInterrupt(timer_tick);  // attaches callback() as a timer overflow interrupt
  attachInterrupt(0, call_button_pressed, CHANGE);
}

// the loop routine runs over and over again forever:
void loop() {
  if (next_state!=NoTransition)
  {
    transition_to_next_state();
  }
  delay(50);
}

 

Convert an Access table to a Wiki table

Copy/paste entire table or query into Notepad++

Replace newlines: \n
with: \n|-\n|.

Then replace tabs: \t
with: \n|.

(In the above two replaces, period = space)

You should end up with a structure like this:

|-
| data line 1, value 1
| data line 1, value 2
|-
| data line 2, value 1
| data line 2, value 2

Then you need to add the table header to the top – in this case I’ve gone for sortable columns:

{| class=”wikitable sortable”
|-
! scope=”col” | Value 1
! scope=”col” | Value 2

…and the footer for the bottom:

|}

That should be about it.

More info on Wiki tables

Remote server frustration

I can understand the principle of locking down web browsers on server machines, but there should at least be a straightforward way of overriding it.

The other week we were connected to a remote server trying to debug some ASPX code. That’s remote as in: on another continent, and not using the fastest connection. (It was designed to be fast for a remote population of users, not us.)

A good way to debug the code without switching on debug errors for everybody is to RDP onto the box and browse it from there.

This didn’t work because, despite Windows 2008 IE ESC (Internet Explorer Enhanced Security Configuration) not being enabled, it was blocking cookies, and every option I could find to try and turn it back on was either disabled, or did nothing.

‘Cos you know, browsing localhost (which has your own code on it ferchrissake) is a terrible security risk. Sigh.

In a rush to resolve it, we eventually resorted to downloading and installing Firefox on the machine. (I love Chrome, but its automatic updates and things scare me slightly; probably not good for a server. Some day I’ll dig around and figure out if it can be turned off. Come to think of it I should make sure FF doesn’t do the same thing.)

Firefox brought its own problems. Straight after installation, it decided to load up some hideously slow (on this less than ideal link) page with video. No, actually, two pages — using two tabs — and despite it proclaiming how fast and responsive it is, wouldn’t respond. Blargh. Thanks a bundle, Mozilla.

It must have taken a minute or more to come back — a long frustrating time when you’re in a hurry.

This solution did, however, work — we could finally see the debug messages, thank goodness.

Is there an official way of getting IE to behave itself?

Census night is coming

The census delivery chick turned up and offered us the option of paper or electronic form.

Two programmers looked at each other, thought about how they value their time and the response was a no-brainer:

“We’re programmers,” I explained, “we’ll take the paper form.”

“There’s a phone number you can call if you have any trouble filling out the electronic form” reassures the collector.

Cathy thinks: “Sure, that line won’t have any trouble when twenty million Australians simultaneously log into the web site to fill in the forms via a broken SSL link, using IE specific controls (that only work under some versions Windows assuming they’re correctly patched and have the right libraries loaded), demanding full round-trips to the underspec’d Windows servers to populate unnecessarily complex custom controls, some of which will no doubt demand Flash or COM. Come to think of it, it probably won’t even be web based, and we’ve only got two Windows boxes, one of which is tucked under a table (Yay! Census night on the floor swearing at the ABS’s programmers!) and the other has a screen resolution that went out with buggy whips (I’ve had programs barf and refuse to run because the resolution was unacceptable).”

We chose paper. For another view of the world, I’m looking forward hearing to how census night worked for Daniel…

Is Django MVC doing it wrong?

I’ve just starting fooling around with Django (a Python web framework), and was looking to produce a form. Bear in mind that Django doesn’t really do MVC, but follows the philosophy – separation of logic, representation and appearance:

class BookForm(forms.Form):
    title = forms.CharField()

def BookView(request):
    form = BookForm()
    return render_to_response('book.html', {'form': form})

With boot.html containing (amongst other things):

<form action="" method="get">
{{ form.as_table }}
<input type="submit" value="Search" />
</form>

Which is great! MVC, separation of data, presentation and business logic. Now, how do you get a CSS class onto that title field? CSS, being the way of separating out the presentation part of a HTML page from the data that’s embedded in it? As above, but chuck it in as such:

class BookForm(forms.Form):
    title = forms.CharField(
        widget=forms.TextInput(attrs={'class':'title-field'}))

Seeing this crunched the gearbox in my mind. All that messy designer stuff, where they make things look nice, that’s worming it’s way into my business logic? Perhaps it’s not so wrong, as the business logic does indeed know that this is a title-field. But it doesn’t quite sit right with me. I’m not convinced it’s wrong, but if you were, you could instead do this in your CSS and HTML:

<style>
.title-field input {background:#ccC68f;}
</style>
<form action="" method="get">
<table>
<tr><td class="title-field"> {{ form.title }} </td></tr>
</table>
<input type="submit" value="Search" />
</form>

Which pretty much forces you to individually place fields — you get to specify the order of fields plus their individual CSS classes.

I’m not sure what the answer is here. Anyone care to enlighten this noob? Bear in mind that there’s a thing to magically tie a model to a form meaning you don’t even need to specify the fields in both the form and model, which you can’t use if you start tossing styles into each field.

Pressing a button does not demand JavaScript

The state of software produced by web developers is highly variable.  The things the good programmers can do is little short of astonishing, as it always has been with limited environments.  But the bad programmers…

Fifteen years ago I did a Microsoft certification thingy, and now they want me to do a satisfaction survey on it – for no compensation.  I think not.  But I notice an unsubscribe link at the bottom of the email, so I follow it: http://www.mailingsvcs.com/optout.aspx?type=email&optout=1&service=1&networkid=9001&id=josh@example.com&pid=p53457652, see the Submit button, click on it… and nothing happens.  And then I realise – it needs JavaScript to press.  A button, one of those things right at the heart of HTML 2.0.  What is this, amateur hour?  Turns out, yes it is because if you follow the hacked URL above — which if filled with bogus data — and click on the Submit data, the back end proceeds happily without validating any of the data, and asks you another question before confirming that it’s done:

We’re sorry you no longer want to receive e-mails from us. Please allow one week for us to process this request, during which time you may still receive e-mails from us. We apologize for any inconvenience.
To help us improve our service, please tell us the primary reason why you no longer wish to receive our messages:

There appears to be some kind of problem with their computers.  Last time I checked, the time it takes a computer to remove a record from a database is in the vicinity of “I’m already finished”, not one week.

I’m of the opinion that people who construct software ought to be required to put their name on it in a visible way, so they can go on my list of people to smack in the face when I meet them.  It’s for the best.

Chrome doesn’t sandbox the CPU; Goggle docs waits really hard

Chrome doesn’t attempt to sandbox CPU consumption. I just closed an inactive Google docs spreadsheet, and saw CPU fall from pegged-at-100% to bubbling along at 10%.

Does it really need each available CPU cycle to wait for the other end to do something? Apparently so, in the way it’s coded.

Google: not as clever as the press release makes out.

HTML5test.com

Less crazy than the Acid Tests is www.html5test.com

Here’s what I get from a few random browsers I have lying around the place:

Firefox 3.5.9 scores 100 out of 160.

Chrome 4.1 scores 118 out of 160.

IE6? 11 out of 160.

IE8? Surprisingly, only 19 out of 160.

The browser on my Nokia N95 phone doesn’t load the page properly; it just says “Working…” and 0 out of 4 (eg it stalls on the first round of tests).

Interestingly, I also tried IE6 with the Google Chrome Frame in it; it scored 137 out of 160, better than Chrome itself. Weird.

Obviously all the browser authors have a way to go to support this if it’s going to be the bold new standard on the web.

(Found via Andrew)