Subscribe via RSS
6Jan/201

Miniworld, Rotterdam – December, 2019

Just like Miniature Wonderland in Hamburg, Rotterdam has it's own version tailored to The Netherlands, located just a few hundred metres from the central exit of Rotterdam Station. And speaking of which, the station entrance is an amazing piece of architecture!

DSC02940

Anyway, back to the wander... head west along the main road from the station entrance and you'll soon find Miniworld!

DSC02941

Admission was less than 20 euro and totally worth it. The entrance is just after the restaurant and you'll start off at a beachside town that looked similar to Enkhuizen.

DSC02951 DSC02950 DSC02946

DSC02952 DSC02953 DSC02956

DSC02965

DSC02971

DSC02964 DSC02970 DSC02984

DSC02980

You'll then wander around to a port. Note also that the days cycle through in beautiful colour... you can actually see it in the background of the following shot as the colour change started sweeping across the layout.

DSC02986

DSC02988 DSC02990 DSC02993

DSC02995

As you're cornering around the you'll notice the control room and model-building area on the left. Check it out... the software is amazing, all digital and alerting when the trains are having issues.

DSC03001 DSC03024 DSC03025

As you continue around, you'll find yourself in a more modern city, finishing with a landmark that we've already seen in real life.

DSC03002 DSC03004 DSC03010

DSC03015

DSC03018 DSC03019 DSC03020

Finally, there's a back room with two older, non-functional layouts. They're actually a lovely tribute to a previous member of the organisation who had passed away. These were from the garage in the garden!

DSC03022

Next, it's time to head downstairs! There's currently another layout under construction in the theme of the UK! There's a few bits and pieces running, but they're expecting it to be complete in another 2 years.

DSC03031

DSC03027 DSC03028 DSC03032

DSC03029

DSC03030 DSC03033 DSC03034

DSC03037

DSC03038 DSC03040 DSC03041

DSC03047

I loved the sign outside... A whole world is waiting for you!

Filed under: INTL 1 Comment
29Dec/190

Vintage Trams In Amsterdam – December, 2019

Thanks to Saint Nicholas hanging around, there's a lot to see on the rails in the main center of Amsterdam. Electrische Museumtramlijn Amsterdam is located in the south of Amsterdam, but it still connected to the cities tram lines. Good news for us as this means that, at certain times of the year, they can run their vintage stock around town! Over Christmas, this happened to be from 12-5pm on the 26-30th of December.

The vintage tram's route was from the Dam itself, anti-clockwise down Rozengracht, left at Marnixstraat, straight through to Fredriksplein, north to Rembrantplein and back to the Dam. Thanks to the winter sun, there weren't too many opportunities near the Dam to take shots, but after viewing the consist, I headed west to the first corner for a photo.

DSC02858

A two-car consist had already been hiding in the shadows in the Dam, waiting in the Dam for passengers to board. How can one even get a good shot of it whilst it's half in the shade? I'd thought there'd only be one set running, but it turns out that whilst one set was doing the lap, the other was paused to advertise the route and take on passengers.

DSC02868

DSC02864 DSC02867 DSC02870

Along the way to rembrantplein, the lighting was not much better...

DSC02906

But down in the plein itself, the sun was still trying to shine!

DSC02922

DSC02925 DSC02926 DSC02929

From there, it was home time. Fortunately, we ended up in town the next day, so I tried some full nighttime shots.

DSC03048 DSC03050 DSC03053

Nicely, they were running another consist... the blue and grey was a really nice combination!

DSC03061

DSC03067 DSC03069 DSC03078

And that was about it. Great to see them running and they all happened to be full when I was watching. I'll try and check out the actual museum itself this trip; there's even a model railway shop near it!

Filed under: INTL No Comments
28Dec/190

Apeldoorn Steam Trains – December, 2019

Back to Apeldoorn, but this time to check out heritage equipment operated by the De Veluwsche Stoomtrein Maatschappij. Again, it was a very early start via Amsterdam Centraal, which coincided with the Thalys arriving from Belgium.

DSC02790

A standard Intercity was taken through to Amersfoort with a small transfer over to another service through to Apeldoorn. It was quite the dreary day, so apologies that all shots hence-forth are in low-light... the temperature was exactly as it looks!

DSC02792

The picture above is the northern side of the station and via this exit you can get to the town center. I had travelled there on December 26 and there was absolutely no point of doing so... there are no boxing day sales in regional towns in Holland! After a quick lap of the town (even McDonalds was shut), I ventured to the southern side and then to the east with a plan to intersect with the branch line that the steam engine runs along. From the station it's about a 15 minute walk.

DSC02794

DSC02795 DSC02796 DSC02797

I walked from the first level-crossing down to the next along the line in search of photo opportunities. Thanks to the weather, the sun was hidden... otherwise it'd be head-on into the lens! Regardless, there wasn't much chop, apart from straight-on photos down the line, or side-on from across the canal. Instead, I wandered back to the bridge at the first crossing and lined up a 30-degree angle with the track. This also let me see the two 'white' signals down the line.. of which I hoped would indicate occupancy, or at least triggered crossings... but did neither with the up service.

DSC02799 DSC02801 DSC02809

I was happily kept amused by the wildlife, watching my clock as the minutes clicked past the expected times on the schedule. Running around 15 minutes late, the steamer arrived and paused at the crossing right next to me!

DSC02813 DSC02815 DSC02822

DSC02818

The train had stopped as the crossing next to me required manual activation. The guard quickly alighted, unlocked the control box and triggered the gates.

DSC02826

DSC02835 DSC02833 DSC02832

DSC02831

The consist then rolled on through to Apeldoorn Station. I noted the steam pipes running through the entire length of the train, presumably for heating? Once it passed and the crossing cleared I light-footed it back as well. As I was running to make it to the opposite platform, the same gas/oil train rolled through as happened last time I was in Apeldoorn. In fact, that was the only freight I saw all day... which is really only one more than I saw last time I was here!

DSC02837 DSC02839DSC02840

DSC02842

The steamer had also already run around and was ready to roll away. After being 15 late, it still left on time! I managed to format my card before I remembered that I had a video of it on there. Whoops. After all the fun was over, I stopped for a burger at the restaurant in the station building.

DSC02851

And that was a day... it was cold enough to not want to hang around!

Filed under: INTL No Comments
27Dec/190

Emmerich – December, 2019

After visiting Geldermalsen, a station near the junction with the Betuworoute in the south of the Netherlands, I decided it was better to find the very start of the line. Sure, not all freights would traverse the entire length of the line, but at least some would have to enter/exit from the German side?

The line starts at Zevenaar, an eastern bordertown in the Netherlands that sits next to the locality of Emmerich in Germany. Getting here from Amsterdam was easy enough with a few transfers along the way.

Amsterdam Centraal

Whilst waiting at Amsterdam Centraal, the usual thing happened whilst waiting for my train; a freight passed when I wasn't ready. Even funnier that it happened whilst I was discussing the fact that there's lots of freight movements in europe, just not when you want them. It was also too bloody dark to take good photos.

DSC02623

DSC02631 DSC02632 DSC02633

DSC02636

From here, an Intercity was caught to Arhnem Centraal. It was still dark for the entire trip, with the sun rising at around 0830 each morning in Europe in winter. Something I'm still really not fond of!

At Arnhem I needed to change to a private railway. Thanks to the great setup of the ticket machines, this is a very easy task. Below you'll see the ticket validators for both companies sitting side by side. All one has to do is touch off NS and touch on Arriva to transfer. No need to exit the station!

DSC02640

Before long the diesel was humming away and we were heading east to Zevenaar. The transfer here wasn't as easy as above as we were now crossing international borders. Of course, being all in fhe EU, there's no actual passport checkpoints... You could just walk across if you wanted to. I did need a new ticket, and this was as simple as going to the DB machine. Emmmerich-Elten wasnt a valid destination, for an unknown reason, so I chose Emmerich itself.

DSC02641

I then had to turn around and bolt to the train as it had just arrived from Arhnem Centraal, ready to take everyone into the Motherland.

Emmerich

There's a big bi-directional staging yard here where freights lay over before or after crossing the border. A lot of westbound freights lined up side by side whilst I was loitering, with the german drivers alighting to let another pair take the consists further on their journeys.

DSC02645

DSC02676 DSC02675 DSC02674

DSC02677 DSC02678 DSC02679

From the platform, the views are therefore very side-on and, honestly, not the best. Every so often a freight would pass straight through, but most of them went into the yard. Fortunately, there was a diesel shunter that had just detached three tankers from a freight for delivery to a local factory. I'd arrived just in time to see it run around and take the tank wagons away.

DSC02649

DSC02647 DSC02653 DSC02672

Something interesting then happened. A coal (or possibly any other commodity) train passed through... though the carriages were eerily familiar. Was this the same train that passed me in Amsterdam Centraal? It sure looked like it... but there's probably 100 trains of similar consist on the line at any point.

DSC02661

DSC02665 DSC02666 DSC02667

A few ICE trains passed through...

DSC02686 DSC02688 DSC02691

And then I was off to the next destionation.

Emmmerich-Elten

My initial plan had always been to get to this station as it looked, from google maps, that all trains would pass through at full speed. I caught the next train westbound to check it out.

DSC02700

DSC02703 DSC02711 DSC02716

Unfortunately, the sun chose to come out just as I arrived, so all the westbound freights were hard to photograph. There were also no eastbound freights to be seen, so I quickly headed off into the small town for coffee and a pitstop.

Praest

With the initial plan not proving effective, and seeing that all the westbound freights were coming through to the yard, I chose then to head east past Emmerich to Praest.

DSC02723

DSC02717 DSC02724 DSC02739

It didn't take long for freights to pass... but I must say there weren't as many as earlier in the morning.

DSC02732 DSC02734 DSC02737

This little side-platform station was beautiful. Lush foliage with tiny platforms and a level crossing to provide forewarning of impending trains. Actually, on that note, there were three level crossings in the vacinity and they all went down at the same time... At least 8 minutes prior to a train coming! I'm not exaggerating... 8 bloody minutes!

After an hour, I was ready to head back to the big smoke, but I hadnte realised the obtuse timing of the crossing gates and ended up stuck on the wrong platform right when my train passed through! Blessing in disguise though... The shunter I'd observed earlier came in the opposite direction and in perfect light.

DSC02746

DSC02749 DSC02750 DSC02755

With the light coming from the south, I chose the southern platform where possible to take photos, but the trains all seemed to be coming from the west, meaning they were easily too close to the lens.

DSC02762

DSC02771

DSC02776

DSC02777 DSC02780 DSC02782

Thanks to missing my train, I had another hour to kill. Pretty easy though as there were numerous freighters and ICE trains passing.

Filed under: INTL No Comments
24Dec/190

Geldermalsen – December, 2019

The goal was to get close enough to a junction with the Betuweroute, the freight-exclusive railway line, of which I can't even pronounce, that links Germany to Rotterdam. Trains either run the entire length of the railway to get to the port of Rotterdam, or they exit at one of the many off-ramps onto the standard NS railway lines. Geldermalsen is one of these locations as there's a junction with the Betuweroute just a few KM south.

's Hertogenbosch

Geldermalsen is a lesser station and therefore only served by NS' Sprinter services. You can get there from either side: Utrecht or 's Hertogenbosch, another name I can't pronounce. I chose the latter.

DSC02491

DSC02493 DSC02496 DSC02498

The main station building is quite beautiful. There's a ton of throw-backs to the previous factories, or maybe even the previous station structure; I couldn't quite tell. There was also a cute little shunter on the side, not doing much at all... I wonder if the station receives freight? I didn't hang around for long though as the connections were great to get the next northbound sprinter.

Geldermalsen

This station is pretty much in the middle of nowhere, but still well patronised and very clean and tidy. There's a really handy pedestrian bridge crossing all lines, but with caternary, it doesn't provide the best view. The station has three roads per direction, including a passing lane as the final road. Further below you'll see how the freight use it to let the express trains pass.

DSC02499

DSC02500 DSC02501 DSC02502

The express trains didn't stop. They are scheduled with 30-minute head-ways and so there's always one heading in one direction or the other.

DSC02505 DSC02511 DSC02557

DSC02552

It wasn't long before a southbound freight train arrived. The consist entered the far road and held back until another express passed through.

DSC02518

DSC02527 DSC02528 DSC02529

DSC02530 DSC02533 DSC02536

There's actually a branch line to the north-west that heads off to Dordrecht. This is run by smaller consists that park at the far end of platform 1. There's then a crossover that allows the sprinters to use the same platform, but at a more convenient location, closer to the station building.

DSC02537 DSC02540 DSC02544

DSC02547 DSC02546 DSC02545

DSC02550

Another freight train passed through northbound, but also had to wait in the third road for a northbound express.

DSC02558

DSC02563 DSC02564 DSC02570

DSC02577

Culemborg

It was bloody cold, so I jumped on the next northbound sprinter; there was family to enjoy out the front o' the Rijksmuseum ... ice skating! I had a few more minutes and so I stopped at the next station north for a quick hop. Culemborg is a stanfard country station with no passing lanes. It has a great waiting room, of which I failed to take a photo.

DSC02591

DSC02595 DSC02597 DSC02599

The expresses bolt through, but there was no time to hang for a sprinter after the one that was approaching; I jumped on and returned to Amsterdam.

DSC02602 DSC02603 DSC02605

Check that last shot out! Google translate app working real-time translating whatever my phone camera was pointed at!

Filed under: INTL No Comments
20Dec/190

Amersfoort and Apeldoorn – December, 2019

It was time for another family adventure to Amsterdam, but this time for Christmas! I was just about ready for Australian summer before being shipped over into the depths of winter in The Netherlands. Lots of research had been completed: I'd found sites for photography spots, live maps of the passenger services and freight timetables. Unfortunately, the latter has been taken down in the last 4 days... can you believe it? Milliseconds before I travelled to the country, the information disappears! Despite this disappointment, I decided to trek out to the regional towns to hunt down freight.

The trip started from Amsterdam North and, thanks to the now-open Northern Metro, it was a quick 5 minutes to get there. I was then very happy to realise that my services would all be run by Koplopers (my total favourite)!

DSC02335

DSC02337 DSC02339DSC02341

That last shot is cute... the poor onboard information system had a disk failure and tried to boot... the weirdest part being that the display starts off upside-down!?

Amersfoort

This town is located south-east of Amsterdam and, via the intercity services, only about 40 minutes away. From the station, there's a large yard to the north-west which hosts infrastructure testing equipment, a train simulator for NS staff, and the shunting yard for the automotive branch. The automotive branch runs south-east from the station, down to a few factories that process half-completed cars from Germany. The goal was to exit the station and loiter near the start of the branch, near a level-crossing, to try and see something run through. Fortunately, as I was approaching the station, a small diesel was already at the head of a long rake of new cars, ready to be taken down the line.

But first... the station... some Koplopers... and the yard...

DSC02344

DSC02348 DSC02349 DSC02352

DSC02345

That shot above was a total accident... turns out you can shoot and focus at the same time and get some pretty weird effects. The top was the only one of 5 that turned out, not that I was even trying. It was a total mistake.

DSC02355

So many Koplopers, but then the yard... at the eastern end there's a stash of vintage locomotives in various liveries and owned by various companies?

DSC02360 DSC02359 DSC02358

DSC02361 DSC02363 DSC02364

One thing I need to admit is that the lighting at this time of year in the northern hemisphere is dismal! I mean, it's beautiful for an hour or so when it's 'dusk', but that's 3pm! The sun is gone by 4!

DSC02366 DSC02367 DSC02369

Wandering to the end of platform 5, I could see the car-carrier rolling towards the station. I then consulted maps and realised that it'd been shunting backwards, whilst I was arriving, to access platform 2/3, which would then let it take the branch. I was obviously in the wrong spot, at the wrong time, and therefore bolted to platform 2. Fortunately, Amersfoort is beautifully designed and there's stairs at both ends of the platform. Before-long, it rolled through...

DSC02371

DSC02372 DSC02374 DSC02377

DSC02381 DSC02379 DSC02378

DSC02401 DSC02395 DSC02387

DSC02402

Quite a few Porsches on the end! An Intercity was coming in through next, bound for Berlin, and so I exited the station to get a shot of it along the line to the east.

DSC02410

DSC02413 DSC02417 DSC02421

The NS loco-hauled services look very similar to the older SNCF locomotives in France. I wonder if they're the same manufacturer? I'll do a little research when I'm sleeping on a french train later in the month. From here, I returned to the station to check out what else was going on. Prior to actually entering, you have to cross the branch where the auto-train went...

DSC02422

The line looks like it's heavy-railed, but the smaller diesel indicates otherwise... then again, they might just be saving fuel. Out the very front of the station, there's a strange clock that seems to be offsetting the current datetime for something relevant to somewhere else?

DSC02427

DSC02428

And one can't forget an obligatory front-on shot of the station.

DSC02429

From here, things got awkward. I had time and decided I'd do a round-trip to Apeldoorn and so I approached platform 2 once more. From the yard, an oil train approached without warning. Fortunately, my camera was at the ready... but after the second shot, my camera seemed to stick in half-focused mode. I turned it off and on again, but as soon as it powered up, it did a focus, as if I had my finger on the trigger, half-pressed.

DSC02451

And so, the train passed... and I had a dead camera. I jumped on the east-bound service to Apeldoorn.

Apeldoorn

As we rolled away, I sat down and started pulling apart my camera. After having the lens, battery and memory card out, the camera finally snapped back into action. Funnily enough, as we were heading towards Apeldoorn, the conductor came over the PA and mentioned something sounding like an apology... this, of course, is a guess as my Dutch is non-existent. The guess was that we were dawdling thanks to the freighter taking its time in front of us. Soon enough, we were accelerating again and I saw a glimpse of a train in out the right windows. Turns out there's a passing loop near Stroe and the freighter had been put away... I'd get to see it again in Apeldoorn?

DSC02457

DSC02460 DSC02463 DSC02465

Amazing. Another fluke... playing leap-frog with freight trains in the middle of The Netherlands. Apeldoorn is also a branch for the Arriva Zutphen line. This is run by two-car diesels which are remarkably similar, in layout, to DERMs from the Victorian railways.

DSC02469

Anyway... after that mild success, I headed back to Amersfoort. I'd bought an initial return ticket from Amsterdam to Amersfoort and then another return from Amersfoort to Apeldoorn, so I had to exit the station to keep all my tickets valid. Another point, I took a loco-hauled intercity like the one above. Even though these are ICE carriages from DB, it seems that they operate as standard intercity services once in The Netherlands. Although I didn't actually get my ticket checked.

Back at Amersfoort

Whilst coming back in, I saw something interesting. Past a building, down near the auto branch, was a stuffed-and-mounted wooden EMU? The building seems to be an old station building, is a Gibson store/function-center, and the loco must be from Austria or Switzerland?

DSC02473

DSC02474 DSC02475 DSC02476

Very nice actually, but the sun was already ready to set. Actually, the EMU reminded me of the railway line from Palma to Port De Soller.

DSC02432

I then did a lap of the whole station and wandered over to the northern side of the yard. There's a building that used to be carriageworks that I thought was a bar, but turned out to just be a function center. One good thing was that it allowed access to the other side of the stored locomotives...

DSC02434

DSC02436 DSC02438 DSC02439

DSC02440

DSC02441

Finally, on the way back into Amersfoort station, I stumbled past a beautiful piece of stained-glass art. That's totally a Koploper!

DSC02430

And that was then it for the day... jetlag was kicking in and although a nice beer was had at De Wagenmeester on the southern side, including a great view of the tracks!,...

DSC02480

It was home time.

Filed under: INTL No Comments
5Dec/190

More (Bit)Bang For Your Buck

Arduinos are a great hobbyist platform for projects, but you'll often encounter speed and memory issues when you try to squeeze in too many features. Fortunately, being an open source system, one can easily bypass the standard libraries and push these little units as hard as possible. Of course, once you're past the warranties and disclaimers, you're out on your own.

I've previously had to jump out of the IDE and use 'faster' code whilst using a Dreamcast Controller for my Model Railway, but that was a little more advanced than what we're about to do here. Today's goal is to bitbang the data stream to the Red LED Sign as quickly as possible. If you check that post, you'll see I'm already using digitalWriteFast, but it seems that we can go even quicker with the SPI library.

What's SPI, you ask? To steal from Arduino: Serial Peripheral Interface (SPI) is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. As it turns out, that's exactly what we want to do! We want the display to be a slave and, well, we're just going to hack the right RX/TX lines together to get the data to flow. A fellow Arduino-er has done this here whilst interfacing with a 74HC595 and provides a few hints as to problems we might run in to.

Actually, now that I think of it, the data is to be sent out in bytes, but my screen is no where near the order of a clean multiplication of bytes... will have to work on that. Also... the data I read is the top 'line' of each letter, it's not a clean char in any memory array. Hmmm...

Test Patterns

Without pulling apart my currently-hacked-together-and-functional-display, I used another Uno I had lying around and hooked it up to the two spare LED panels. The whole display came with 5 panels, but I wasn't able to smoothly run them all at once, so these two were not in use.

The hook-up is pretty straight forward. The Wikipedia article on SPI gives a little more information on the bus and, more specifically, dictates which wires we need to use. We'll need the data output wire and the clock, known as MOSI, or Master Out-Slave In, and SCLK, the serial clock. Note that some devices read the data pin when the clock transitions from LOW to HIGH, and some vice-versa. Fortunately, this can all be configured via the SPI library.

With the following code, I managed to get a test pattern on the display...

#include <SPI.h>
void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
}

bool isEvenRow = false;
void loop() {
  isEvenRow = false;
  for (int row = 0; row < 7; row++) 
  {
    if (isEvenRow) {
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
    } else {
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
    }
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(150);
    digitalWrite(row + 3, LOW);
    isEvenRow = !isEvenRow;
  }
}

Well, neat! It worked? Playing with the SPI_CLOCK_DIv variable made the loop even quicker, down to the point where I had to up the delay at the end so that the LEDs would illuminate for a longer timeframe. SPI_CLOCK_DIV determines the speed at which the data is sent out, dividing the main 16mhz clock on the Arduino. DIV2 halves it (8mhz), DIV4 = 1/4 = 4mhz, DIV8 = 1/8 = 2mhz, DIV16 = 1/16 = 1mhz, etc...

Anyway, the test pattern was great... but I needed to output text, in rows of bytes!?

What About Text?

So this is where it gets interesting. My font array has 7 rows of 5 pixels per font. I then have up to 6 characters per LED display unit, equalling a total of 30 bits each. Of course, there's 8 bits to a byte, so the neatly rounded-up value would be 32 bits. I could therefore send out 4 bytes to get each row transmitted over the wire. But do be warned, if you start the data on the first bit out, it'll 'run off the edge' of the screen as the screen is only 30 bits wide...

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00

As you can see, the text to be displayed is "TEST!" in the cute Arduino 5x7 font. Our display is 30 bits wide, so there's two columns of blank to the left. After the 2 pixel offset, we start throwing out each row of data. This won't be overly-easy either, as we need to get the rows of bits per character per font.

So, based on the current pixel to be pushed out, firstly get the character from the string array. We then need to look up the font pixel array for this character, only getting the relevant row that we're trying to display. Once we have that, we can then just send the bits out to a temporary array of bytes. As that we'll only have 5 bits per font line row, we'll actually need to merge multiple characters into each byte of the array. If we then want to scroll text, we'll have to put a little more effort in. This isn't overly different from when we were sending the data out bit-by-bit; we're just stuffing it into bytes now, making sure we get everything into the correct byte in the output array.

I jammed this calculation into one row below and the output was actually quite surprising! Mainly in the fact that it actually worked!

#include <SPI.h>
#include "myfont.h"

String serialString = "TEST! ";
const int BUFFER_LENGTH = 4;
const int DISPLAY_LENGTH = 30;
byte* datarow = new byte[BUFFER_LENGTH];

void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
}

void loop() {
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < DISPLAY_LENGTH; col++) {
      datarow[((col + ((BUFFER_LENGTH * 8) - DISPLAY_LENGTH)) / 8)] |= 
        ((font[serialString[col / 5]][col % 5] & (1 << (6 - row))) 
          ? 1 : 0) << ((col) % 8);
    }
    for (int col = 0; col < BUFFER_LENGTH; col++) SPI.transfer(datarow[col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(500);
    digitalWrite(row + 3, LOW);
  }
}

Everything was actually working nicely... but then I tried to extend it out to 4 displays. 120 pixels out, even at the fastest SPI, caused severe flickering. It dawned on me that I was doing some pretty hefty lifting in my display loop, presumably slowing down the drawing. It's actually a critical loop and it seems that any processing will slow down the line drawing, causing the flickering I was seeing.

With this problem in mind, it became apparent that I'd need to move the 'buffer' calculation out of the main loop. I quickly tested this theory by moving it to a once-off in the setup procedure.

#include <SPI.h>
#include "myfont.h"

String serialString = "TEST! ";
const int BUFFER_LENGTH = 4;
const int DISPLAY_LENGTH = 30;
const int DISPLAY_HEIGHT = 7;
byte* datarow = new byte[DISPLAY_HEIGHT][BUFFER_LENGTH];
void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);

  for (int row = 0; row < DISPLAY_HEIGHT; row++) 
  {
    for (int col = 0; col < DISPLAY_LENGTH; col++) {
      datarow[row][((col + ((BUFFER_LENGTH * 8) - DISPLAY_LENGTH)) / 8)] |= 
        ((font[serialString[col / 5]][col % 5] & (1 << ((DISPLAY_HEIGHT - 1) - row))) 
          ? 1 : 0) << ((col) % 8);
    }
  }
}

void loop() {
  for (int row = 0; row < DISPLAY_HEIGHT; row++) 
  {
    for (int col = 0; col < BUFFER_LENGTH; col++) SPI.transfer(datarow[row][col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(500);
    digitalWrite(row + 3, LOW);
  }
}

My text was static, so I now only built the buffer once. Would you believe it? The rendering was beautiful! I couldn't even notice a flicker. This was then short-lived when I realised I needed to scroll text. Again, there was no need to rebuild the buffer on each loop, so I wrote a procedure and only called it when there was text to move; defined by a delayed scroll rate.

This worked nicely, but there was an obvious jarring delay as the text shifted along. You could feel it re-processing in-between the character movements. I was still happy with it! I went ahead and reconfigured my initial display setup to use two Arduinos: one for the remocon+wifi and the other to receive serial data and light this dispalay.

But Wait, Why Don't I Build The Entire Text Buffer?

Whilst writing this up, it occurred to me that I was only rebuilding the buffer for the text that was visible on the display, not the entire string. If I had the full text buffer already created somewhere in memory, I then would only need to get SPI to send out the data from a specific bit offset. But, how do you start sending data via SPI from half-way through a byte? My fonts/characters were 5 bits wide and each byte had 1.5ish characters in them! I considered just shifting the pointer along the bytes, but the scrolling would be horrible.

So, I want to send out data from half way through a byte? Let's just borrow that table from above again:

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00

Officially, on the 3rd loop of scrolling, I would want to send out the green bits. I'd also then want to send out five zeroes at the other end so that the scrolling text trails off and doesn't wrap around. I can't tell SPI to start at the 4th bit of a byte? So I'll need to create a new buffer and populate this as quickly as possible, line by line, just as we're about to render it. Thanks to the glory of the internet, there's always someone else who wants to do something similar. Effectively we have an array of bytes (unsigned chars, meaning we get all 8 bits) and we'll need to shift the first one and append the next one. It'll be very much like a catepillar crawling along.

So, if we build the full text buffer array when the string comes in, we can then push the relevant chunk into the display buffer. There'll be no font calculations, just bit for bit copying, and this will hopefully still be fast enough. We can even make sure we only do it line by line, and only as required... if we're on a byte boundary, then we don't need to shift anything!

I mentioned shifting above, and that's what we'll need to do to get the chunks of bytes into the final display buffer. If you look at the table above, you'll notice I coloured the cells in light green and dark green. The first 3 bits are light green and come from the 'end' of the first byte of the text buffer. The next 5 bits are from the 'start' of the second byte in the text buffer. This chain then continues on as we shift the bits. The >> and << C operators will assist us with this task as that's exactly what they're designed to do: shift bits in a variable in a certain direction by a certain amount. Let's try some pseudo-code first....

define a string buffer that has the string to display: "TEST!";
build a buffer for this string: stringBitBuffer[7][4];
define a display buffer that is enough for 1 panel: displayBuffer = byte[7][4];
if our scroll offset is a multiple of 8
  foreach stringBitBuffer[scrolloffset /8] SPI.writeRow();
  write extra zeroes at the end.
else if our scroll offset is NOT a multiple of 8
  foreach byte in stringBitBuffer starting from (scrollOffset/8)
    shift the first block of the text buffer right scrollOffset times
    make anything to the left of the text in that byte zero.
    move the resulting value into the current displayBuffer byte.
    get the next text buffer byte. 
    take the first (8 - scrollOffset) bits and add them to the current displayBuffer byte
  next
end if

Here's an animation showing what bits we want where...

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
TB 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 02 02 02 02 02 02 02 02 03 03 03 03 03 03 03 03
Bytes 00 01 02 03

The table above shows the 8 frames that need to be copied over to the framebuffer between bytes. Once the data has shifted a whole byte to the left, then the drawing routine just needs to start from the next byte, there's no need to send out the initial bytes if they're offscreen. We need to copy the bits in the main area of the table into the buffer bytes listed on top. I've added a new row at the bottom which indicates the first bit/byte of the text buffer (TB). With the duplicated Byte row underneath, you can see how we'll need a part of one text buffer and the rest of the next to fill the gaps.

Back to that forum post I mentioned above, and the description I gave about bit shifting, we can build up our buffer. We need to, based on the scroll offset, take the first (8 - offset) bits from every byte and then the 'offset' bits from the following byte. i.e. if the offset was 3, we want the last 5 bits of byte 1 and the first three of byte 2. If we're on the last byte, then we just fill the end with zeroes. The AND masks for row 2 are shown below. Row 1 is nearly all bits set... so wouldn't be a good test case.

Bytes 00 01
Pixels 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00
AND #1 00 00 00 01 01 01 01 01 00 00 00 00 00 00 00 00
AND #2 00 00 00 00 00 00 00 00 01 01 01 00 00 00 00 00

And then we just need to shift the first 5 bits to the left... as we're stored in MSB.

#include <SPI.h>
#include "myfont.h"

int ccol = 0;
byte datarow[7][60];
int displayLength = 120;
int bytesRequired = (displayLength + (displayLength % 8) + 8) / 8;
int totalPixels = bytesRequired * 8;
byte frameBuffer[7][16];

unsigned long last_time = millis();
unsigned long scroll_time = millis();
unsigned long scroll_pause = millis();
unsigned long next_text_time = millis();
int charOffset = 0, loop_count = 0, charcol = 0;
String displayString;

void buildTextBuffer() {
  bytesRequired = ((displayString.length() * 5) / 8) + ((displayString.length() * 5) % 8 == 0 ? 0 : 1);
  totalPixels = bytesRequired  * 8;
  for (int row = 0; row < 7; row++) 
  {
    for (int b = 0; b < bytesRequired; b++) datarow[row][b] = 0;
    for (int col = 0; col < totalPixels; col++) {
      ccol = col + 8;
      datarow[row][ccol / 8] |= 
        ((font[displayString[col / 5]][col % 5] & (1 << (6 - row))) 
          ? 1 : 0) << (ccol % 8);
    }
  }
}

void buildFrameBuffer(int offset = 0) {
  int tOffset = offset / 8;
  int cOffset = offset % 8;
  int bb = 0;
  for (int row = 0; row < 7; row++) 
  {
    for (int b = 0; b < 16; b++) {
      bb = b+tOffset;
      frameBuffer[row][b] = (datarow[row][bb] >> cOffset);
      if (cOffset > 0) {
        if (bb <= bytesRequired) {
          frameBuffer[row][b] |= (datarow[row][bb + 1] << (8 - cOffset));
        }
      }
    }
  }
}

void setup() {
  Serial.begin(9600);
        
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV64);

  displayString = "Warming up ... ";
  buildTextBuffer();
  buildFrameBuffer(0);
}

String newString = "";
void getNextIndex() {
  for (int i = 0; i < 7; i++)
    for (int x = 0; x < 60; x++)
      datarow[i][x] = 0;
      
  if (Serial.available()) {
    newString = Serial.readStringUntil('\n');
    if (!newString.equals(displayString)) {
      displayString = newString;
      next_text_time = millis();
    }
  } else {
    displayString = "";
  }
  if (displayString.length() > 0) buildTextBuffer();
  buildFrameBuffer(0);
}

void loop() {  
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < 16; col++) SPI.transfer(frameBuffer[row][col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(150);
    digitalWrite(row + 3, LOW);
  }

  if ((millis() - scroll_pause > 2500)) {
    if ((displayString.length() > (displayLength / 5))) {
      if (millis() - scroll_time > 30) {
        charOffset++;
        if ((charOffset / 5) > displayString.length()) {
          charOffset = 0;
          loop_count++;
          scroll_pause = millis();
          if (millis() - next_text_time > 5000) getNextIndex();
        }
        scroll_time = millis();
        buildFrameBuffer(charOffset);
      }
    } else {
      loop_count++;
      if (millis() - next_text_time > 5000) {
        getNextIndex();
        loop_count = 0;
      }
      charOffset = 0;
    }
  }
}

And it all actually worked... beautiful scrolling.

Further Possible Optimisations

We're sending the text into this Arduino from another Arduino over SoftSerial. Why send text when I could send the framebuffer bits instead? I wonder if sending (string-length * 5 * 7 * 8) bits would be quicker than the initial string and calculations on the secondary Arduino's side? Should I test it? Maybe later...

Filed under: Arduino No Comments
4Dec/190

Atari Mouse – Replacing Microswitches

I'd recently acquired an Atari 520STFM (more about that later) and the package came with two mice. One is actually optical and has a switch that allows it to also be used on an Amiga, but it really hated the kitchen bench. I do remember, back in the day, that first-generation optical mice couldn't deal with glossy single-coloured surfaces. The other mouse was the original Atari 2-Button Ball-Mouse. It tracked nicely, but the buttons were as soggy as a wet week?

DSC02237

DSC02238 DSC02240 DSC02243

DSC02241

Open 'Er Up

Very easy to do... two screws up the top-end where the cable enters. Lift at the front, up near the buttons and pull forward to clear the latch at the bottom end.

DSC02245

DSC02248 DSC02250 DSC02251

From here, the microswitches are your PCB-mounted standard, easily available from Jaycar. I toddled off and purchased some of the exact-same replacements, but also two slightly-taller switches. The latter had a much clickier click. The standard replacements were also clickier than the existing switches, but I wanted moar.

DSC02254 DSC02258 DSC02260

A quick look at the circuit board underneath saw that only one side of both microswitches was in use. You can see, per four-hole-mounting of each switch at the top left and top-right of the board, that only the bottom left and bottom right pins are used respectively. The top two are bridged, but the 4th pin on each goes nowhere.

DSC02252

Just because things change over the decades, I quickly checked that my microswitches contacted on the same dimension...

DSC02256

A simple de-soldering saw the old switches out. With the solder removed from the holes in the PCB, I could trial the clearance with the taller switches...

DSC02262

The case was easily re-assembled to test...

DSC02266

But, as you can see, the case wouldn't even close. Testing the buttons, with the case half-ajar, saw them super clicky... maybe toooo-clicky. So I switched in the new same-sized switches and these were nice!

DSC02267

Although they're not that clicky when they're just in your fingertips in the shop, they're great once mounted in the mouse!

Testing...

All soldered up and plugged in, it was time to test it all out. Previously I had to mash the left-mouse-button a few times to get one click, so I was happy to see that a single click working perfectly!

DSC02278 DSC02279 DSC02280

DSC02281

DSC02269

DSC02271 DSC02272 DSC02274

DSC02275

And yeah, straight into Railroad Tycoon... damn that Grasshopper is a slow first train!

Filed under: Retro No Comments
27Nov/190

Welding Rail In South Yarra

There was a total shutdown of all lines past my apartment on the weekend of the 16th-17th November as Metro we're upgrading the signalling. It's well-needed to allow better head-ways for more services, and also to allow brand new 'high-capacity' trains to run. To do all this, they've had to cut in new isolated track joins. I assumed they'd just cut through the rails in-stu and clamp an insulated joiner over the top... but I assume the tension in the rails prevents them from doing this? Instead they've been busy removing a 20 metre length of track and welded in a new length that includes a bypassed insulated joiner!

DSC02083

It's bypassed as they don't want to break the track-circuit just yet. The rest of the infrastructure isn't in place yet, so a break in the circuit here would actually cause a 'blind' area on one of the sides. Hence the jumper cables. There's also a longer length of cables running down the current work area, to keep the current circuit in operation whilst the work is carried out. I don't really see the reason though, as there's a lot of protection at either end of the entire work area to prevent vehicles from entering.

The weather was reasonable, and I was half brain-dead from a cold, so I spent a good bit of time on the bridge near Cromwell Road, watching the professionals carry out their business. You could tell they'd done the job 100s of times before; their efficiency and precision was great to watch.

Step 1 - Align The Rails

The first step would probably be the most important in the whole process; misaligned rails would cause untold problems in the future and therefore a lot of time was spent getting the elevation and angle spot-on. There's a large brace/jack on the outside of the rails that was aligned first. This unit uses friction to grip all four rails and, when air pressure is applied, pneumatically draws them closer together.

DSC02086

DSC02084 DSC02090 DSC02092

The workman was constantly measuring the gap between the rails until it was within tolerance. I note that they didn't just bring them closer in one hit. The workman operating the compressor only applied pressure for short periods, maybe 3 seconds each time, and then his colleague would measure again. They'd then let the whole contraption rest for 5 seconds before applying further pressure.

I'm actually astonished that the rails even moved. It's a relatively straight section of track and where does the slack come from? I can't imagine they actually stretch the steel? They had removed around 6 rows of clips from the original rails to allow freedom of movement. I'd say the gap was about 40mm to start with, but they brought it right down to less than 20mm!

Once it was as close as required, the rails were further adjusted using (what looked like) rail spikes between the closest sleepers and the base of the rail. These were hammered in to raise or lower the rails. The worksman spent around 5 minutes doing this, making sure everything was totally level. The ruler was around a metre long, allowing him to see how much the rails tapered off on either side. You could tell he did not want to create any kind of gradient on either side of the join.

Step 2 - Build The Mould

From what I could see, the mould was made of some form of terracotta? The colour was the standard red, but it really could be made of any sort of compound. The base was removed from the packaging first and a layer of glue applied down each long edge. This was then smoothed around the edge and along the ridge to make sure that there'd be no gaps once joined. This base was then placed into the metal tray which would soon form the case that holds the mould together.

DSC02094 DSC02095 DSC02098

The whole base was then placed under the gap between the rails. It was held in place with clamps and, once again, adjusted once and again to make sure that it was completely square and level with the join.

DSC02096 DSC02100 DSC02101

DSC02102

The sides of the mould were then taken out of the pack. These were placed in the 'sides' of the metal case and both units were then assembled onto the rail. From here, the mould was complete, with an opening at the top where molten metal would be poured in? You could see that, at the top of the mould there was one short edge that was lower than the others; presumably this was for excess molten metal to flow over.

DSC02105

Once this was done, the final outer frame was dropped on and the 'drip tray' inserted on the side that had the overflow 'spout'.

DSC02106

DSC02107 DSC02108 DSC02111

From here, a large block of malleable clay (or other playdough-esque material) was split up and used to totally fill all gaps around the edges of the case and mould. The goal was to ensure that all heat, once the mould was full, was to stay trapped inside.

DSC02114

The entire block was applied to all facades of the mould, specifically where the case and the mould met.

Step 3 - Add Fire!

A cute little terracotta (or other substance) pot had been sitting on the back of the work truck for a while, but it was now its time for action.

DSC02113

To 'set the mould', a small mount was clamped to the rail and then the oxy-acetylene torch was flamed up and positioned on it, aiming the fire directly into the mould. The flame from the torch burned a strong blue, but eventually yellow flames began rising from the openings on either side of the torch. One of the worksman then grabbed the terracotta pot whilst the other pulled the torch out of the mould. Without being able to see inside the mould, one couldn't really work out what exactly was being heated, but you'd have to assume the rail ends were red-hot by this point!

DSC02117

DSC02122 DSC02123 DSC02124

The pot was placed directly on top of the whole mould and the torch was placed in the small opening on top.

DSC02128

I'll let the following video explain the rest...

A lot of trust placed in a set of serious gloves!

Step 4 - Clean Up

From here, there was a 10 minute break whilst the burning-box-of-death cooled down. The overflow tray on the side was thrown track-side once it could be lifted.

DSC02132 DSC02130 DSC02134

After a while, the outside metal case was unscrewed and whacked a few times until it fell loose. Now the mould was perfectly visible, and perfectly-solidly-formed as a single unit, welded to the rails!

DSC02135

To get this off, another utensil was used. The workmen brought over another flat-frame-style machine and placed it over the mould. With a few clamps, they secured it on all corners to the rail and then one of the guys started pumping a lever handle. I couldn't quite see what the action resulted in from where I was, but I assume there was a flat blade that was slowly, flush with the railhead, cutting into the mould on a horizontal plane.

DSC02140

DSC02143 DSC02144 DSC02147

The other worksmen started beating the mould with a mallet when the cutter wasn't being used. After a lot of intimidation, the mould finally started budging... but instead of a clean splice, it decided to split to pieces... pieces of 1000 degree red-hot danger.

DSC02149

More time was spent letting the bits cool down and then it was all moved to the rubbish pile track-side.

DSC02154

From here, a portable grinder-on-wheels was used to finally trim down the weld. Once complete, it finally resembled rail!

I'd actually watched the 2nd of 4 joins be welded before I had decided to get my camera and record the one above. This part, the removing of the mould, was much smoother on that one; a single knock after a slight clamp saw the whole lot just break free in one hit. There was no grinding required afterwards either! I hadn't really noticed anything done differently between each session, so I wonder how many variables come into play when it comes to doing this and how easy it is to stuff up!?

Gantry Foundations

Whilst all the welding was taking place, another vehicle had been busy drilling a column on the other side of the track. The colour of the earth was quite interesting, being somewhere between clay and red earth? A re-bar metal frame was then built up and inserted, with the square frame of pre-built bolt rigging for the base of a pylon. The alignment of this frame in the hole was actually a big thing and watching the surveyor get it correct was pretty interesting.

DSC02158

Turns out there was a remote surveyors camera sitting half way down the track, fixed on the location of the pylon.

DSC02159

And, with a remote mirror, with a very fine tip, the surveyor measured each corner of the frame. The workers around nailed, cut and hammered the external wooden frame to get the metal frame in the exactly correct position.

DSC02161 DSC02162 DSC02165

The surveyor was holding a handheld computer that was relaying the stats from the surveying equipment.

DSC02160

Good to see technology helping all departments.

Tamping And Cleaning

Whilst everything else was going on, there were also tampers and ballast cleaners working away. Turns out they were tidying up a cut-in insulated joint that had been installed the night before.

DSC02156

DSC02167 DSC02082 DSC02169

The ballast cleaner sounded like it was in pain, chewing rocks up and spitting out a lot of dust.

DSC02171

After all of the above, they managed to clean up and the trains were running again the next morning.

Filed under: AUS No Comments
24Oct/190

Arduino Uno WiFi + TV Remote + LED Sign

Over the weekend, whilst watching TV, I realised that I needed some kind of sign to work out when trains were passing my apartment. There's a railway line right next to me and around four-or-more services pass daily. I'd prefer to be notified in advance and, since I have data sources to tell me when trains are about to come by, I want to make the most of it. Currently that's done by RSS both on my phone and PC, but the whole point is that I'm watching TV and don't want to have to be checking my phone every 2 seconds.

After getting the red LED marquee to work on the old ISA I/O card, I decided it was time to get it plugged into the Arduino. I actually already have an Arduino Uno Wifi next to my TV, which I've recently been using to translate my TV remote control codes (similar to what I did with the old B&O TV) into Yamaha remote control codes for control of volume with one remote. Adding the LED marquee would let me know when a button was successfully pressed ... and it would also tell me when trains were coming past!

I hadn't actually worked with the WiFi on the Arduino yet, so that was a bit of an experience. The RF side of things was working fine and I had already worked out the wiring requirements for the LED display thanks to the old I/O card.

Getting the ESP8266 Online

The Arduino Uno Wifi is an Arduino Uno board with an embedded ESP8299 microcontroller. The basic idea is that the two units talk serial to each other, when configured to do so. If you want to program one, or the other, you have to adjust the serial communications path on the board via a tiny row of switches. Jaycar has a minimal instruction sheet here, but it's enough to get you started. From the information, please set your Arduino Uno Wifi's tiny switch row to: 1:OFF,2:OFF,3:OFF,4:OFF - 5:ON,6:ON,7:ON - 8:OFF.

I would want this unit to act by itself as both a web server and web requestor, so I needed to find code for both. Before this we need to set up the Arduino IDE for use with the ESP8266. I found a great tutorial here, but otherwise, the steps are pretty simple. Open the Arduino IDE, go to Preferences and then paste this URL into to the additional boards list: http://arduino.esp8266.com/stable/package_esp8266com_index.json.

Screen Shot 2019-10-20 at 11.37.10 am

Once done, go to the board manager and search for ESP8266...

Screen Shot 2019-10-20 at 11.37.54 am

Install the relevant row and then restart the Arduino IDE. From here, you should have a new selection list in the boards drop-down...

Screen Shot 2019-10-20 at 11.39.41 am

...and then, once selected, a hideous amount of new options to adjust the programming!

Screen Shot 2019-10-20 at 11.44.27 am

The main advice is to not touch any of them, apart from the serial port. You'll need to work out which one your Arduino is connected to, but depending on if you even had serial ports in the first place, it should be pretty obvious. I'm working on a Mac Mini and my Arduino was connected via cu.usbserial-1460. From here, open the Serial Monitor and hit reset on the Arduino.

Screen Shot 2019-10-20 at 11.44.50 am

What garbage is that? I then started from the slowest and tested each baud... turns out if you set to 74880 then you'll get the following...

Screen Shot 2019-10-20 at 11.46.29 am

What a weird port number? It seems that just the initial header information is at that BAUD rate. Afterwards, it'll be at whatever you've set in the code you upload.

Running A Web Server

So, where were we? We have a connected device, so let's grab the first example from here and compile it. After installing the ESP8266 libraries, this code should compile with zero issues. If you happen to have any, then write a comment below, providing as much detail as possible. If it's worked, then check the code and adjust the Wifi SSID and password to match your local AP. Hit upload and cross your fingers and toes... hopefully you'll get the following output:

Screen Shot 2019-10-20 at 11.49.07 am

Yes! Now, you need to switch OFF switch 7 on the little switch header on the Arduino. This pin enables the programming mode and we now want it in the run mode. Note also that we've now set the baud to 115200, so change your serial monitor to that too... Do you get the following after hitting the reset key on the Arduino?

Screen Shot 2019-10-20 at 11.50.08 am

Associated! And with a nice IP! So what does the web browser say?

Screen Shot 2019-10-20 at 11.54.58 am

WIN!

HTTPS Web Requests with the ESP8266

The basic ESP8266 examples use WiFiClient, but this only works with HTTP requests. My server runs over HTTPS, so we need to use WifiSecureClient for secure web requests. To call an HTTPS service, you'll need to get the fingerprint from the SSL certificate. Browse to the site in a regular web browser and check out the properties of the lock next to the URL in the address bar. Somewhere in there you'll find the required data.

Screen Shot 2019-10-20 at 12.39.49 pm

And from there, edit the WifiClient Example to carry out an SSL request using these instructions:

#include <esp8266wifi .h>

const char* ssid = "********";
const char* password = "********";
const char* host = "api.github.com";
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";

void setup()
{
  Serial.begin(115200);
  Serial.println();

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
}


void loop()
{
  WiFiClientSecure client;
  Serial.print("[connecting to ");
  Serial.println(host);
  if (client.connect(host, 443)) {
    Serial.println("connected]");
    if (client.verify(fingerprint, host)) {
      Serial.println("[certificate matches]");
    } else {
      Serial.println("[certificate doesn't match]");
    }
    Serial.println("[Sending a request]");
    client.print(String("GET /") + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n" +
                 "\r\n");
    Serial.println("[Response:]");
    while (client.connected() || client.available())
    {
      if (client.available())
      {
        String line = client.readStringUntil('\n');
        Serial.println(line);
      }
    }
    client.stop();
    Serial.println("\n[Disconnected]");
  }
  else
  {
    Serial.println("connection failed!]");
    client.stop();
  }
  delay(5000);
}

And hopefully, you'll get something similar to the following in your serial terminal.

{ll⸮⸮|⸮d⸮|⸮d⸮b|⸮⸮⸮⸮s⸮b⸮c⸮⸮'o⸮dg'⸮⸮⸮cp⸮⸮dsdrlx⸮o⸮⸮d⸮⸮co⸮|l⸮⸮c⸮⸮go⸮d⸮⸮$`⸮'o$`gs⸮⸮⸮ob⸮$;⸮⸮gc⸮l⸮⸮dl⸮⸮d`⸮⸮'⸮

Connecting ...
scandone
........scandone
.scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 1
cnt 

connected with COMEGETSOME, channel 6
dhcp client start...
ip:192.168.1.121,mask:255.255.255.0,gw:192.168.1.1

Connected to COMEGETSOME
IP address:	192.168.1.121
mDNS responder started

connecting to api.github.com
Using fingerprint '59 74 61 88 13 CA 12 34 15 4D 11 0A C1 7F E6 67 07 69 42 F5'
requesting URL: /repos/esp8266/Arduino/commits/master/status
request sent
headers received
esp8266/Arduino CI has failed
reply was:
==========
{"state":"pending","statuses":[],"sha":"1e17dddd895883806c9bfd3dd7b7042aa813d94f","total_count":0,"repository":{"id":32969220,"node_id":"MDEwOlJlcG9zaXRvcnkzMjk2OTIyMA==","name":"Arduino..."}
==========
closing connection

Nice, we can successfully pull data from a HTTPS source. Let's rig up a polling system to get the data each minute.

Polling for Data + Extra Buttons

So, we're able to pull data from the internet, but I also want this unit to be a mini webserver. If I used Delay() to spread out the web-polling calls, then I'd halt the entire unit. We can't have it wait when it needs to be handling button presses from the web interface. Instead, we'll take a snapshot of the current internal millisecond counter using millis() and then check how many milliseconds have passed to work out if we should try and grab new data.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>   // Include the WebServer library

ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80

void handleRoot();              // function prototypes for HTTP handlers
void handleNotFound();
void handleRemote();
unsigned long lastMillis;
const char* host = "trainfinder.otenko.com";
const int httpsPort = 443;
const char fingerprint[] PROGMEM = "BC 9C 56 D5 8E 7A FE CC 0C F7 A2 21 1F C5 7B 9A C0 FA 15 41";
String last_line = "";

void setup(void) {
  Serial.begin(9600);
  delay(100);
  Serial.println("\n!START");
  wifiMulti.addAP("COMEGETSOME", "blahblahblah");
  while (wifiMulti.run() != WL_CONNECTED) { delay(250); }
  Serial.println(WiFi.SSID());
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, handleRoot);
  server.on("/buttons", HTTP_POST, handleRemote);
  server.onNotFound(handleNotFound);
  server.begin();
  
  lastMillis = millis();
}

void loop(void){
  server.handleClient();
  if ((millis() - lastMillis) > (60 * 1000)) {
    WiFiClientSecure client;
    client.setFingerprint(fingerprint);
  
    if (!client.connect(host, httpsPort)) {
      Serial.println("!FAILED");
    } else {
      String url = "/some/cool/url";    
      client.print(String("GET ") + url + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n");
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") break;
      }
      bool foundLastLine = false;
      String line = "";
      while(client.available()) {   
        line = client.readStringUntil('\n');
        if (last_line.equals("") || foundLastLine) {
          Serial.println(line);
          last_line = String(line);
          delay(6500); //space out the data to the Arduino
        }
        if (last_line.equals(line)) {
          foundLastLine = true;
        }
      }
      if (!foundLastLine) last_line = line;
    }
    lastMillis = millis();
  }
}

void handleRoot() {
  server.send(200, "text/html", "<form action='/buttons' method='POST'>" \
      "<input type='submit' name='pwr_plz' value='PWR!'/>" \
      "<input type='submit' name='vol_dn' value='VOL-'/>" \
      "<input type='submit' name='vol_up' value='VOL+'/>" \ 
    "</form><br/><br/>Last Line: <pre>" + last_line + "</pre>");   
}

void handleRemote() {
  if (server.hasArg("vol_up")) {
    Serial.println("!VOLUP");
  } else if (server.hasArg("vol_dn")) {
    Serial.println("!VOLDN");
  } else if (server.hasArg("pwr_plz")) {
    Serial.println("!POWER");
  }
  server.sendHeader("Location","/");
  server.send(303);
}

void handleNotFound(){
  server.send(404, "text/plain", "404: Not found");
}

Just for fun, here's the first shot of me writing the code. Instead of 'text/html', I was still outputting 'text/plain' and, well, as expected, got the following...

Screen Shot 2019-10-20 at 12.04.08 pm

After fixing that, the screenshot below was taken. Of course, it doesn't match the code above, but you get the idea.

Screen Shot 2019-10-20 at 12.06.02 pm

The basic idea is to print out the raw html to the browser. From here there's a form that has the buttons which post back to the ESP8266. The controller then sees the post, sends the command via Serial to the Arduino and then redirects the user back to the main form.

Screen Shot 2019-10-20 at 12.06.05 pm

Now to get the Arduino to consume it.

ESP8266 to Arduino

We've currently had the ESP8266 piped directly out the USB Serial port. Now we want it to talk to the Arduino internally. To do this, the tiny onboard switch needs to have all switches off except for 1 and 2. This then routes the RX/TX directly from the ESP8266 to the Arduino. From here though, the unit becomes a black-box. We have no idea what the ESP8266 is saying to the Arduino, and vice-versa, as the connection via the USB serial port has been severed. We can only hope that the data we're sending through is what we want!

If you check the shots above of the data the ESP8266 sends, you can see that we want to skip a bit of the earlier stuff. To do this, I defined a "!START" command which the Arduino should look for before bothering to deal with any of the data from the serial channel. From there, anything starting with a "!" is a command, whereas anything else is to be printed to the LED Display.

Oh yeah, that TV Remote bit

I previously had an amplifier that ran over ARC over HDMI and also received controls... but half the time it'd switch on to Optical and just would not switch back to ARC without a lot of screwing around. No amount of power cycling, cable switching or button pressing would get it back. So it went to the farm. Instead, I purchased a beautiful old Yamaha amp for AUD$5 and then realised I had to get up and control it by hand. Not optimal, so I search google for the remote codes.... they didn't exist, so I search eBay for a spare remote... they didn't exist... but one guy in Spain had a company that programmed third-party remotes and had one for this amp!

It arrived, and I plugged it through the same code I used for the B&O TV. Over the serial, the codes and bits were reported, showing me that it used the "NEC" protocol. I recorded the codes for the buttons I wanted. I then did the same with my Sony TV Remote for buttons that I wanted to re-purpose. The goal was to have the TV Volume buttons also trigger the amp volume. This worked nicely, via an external IR LED that sits in front of the amp.

Of course, the TV volume still shifts, so I made the amp volume shift 4 times per button press... meaning the surround is always louder than the TV. Doesn't hurt to have a little bit of tinny sound from the TV also... a second center channel?

To make everything compile, install Ken Shirrif's IRremote library, available via the Arduino GUI...

Screen Shot 2019-10-20 at 2.31.18 pm

The code is in the next segment.

Hooking up the LED Sign

I've used a font found online, but it seems that Arduino has one built-in? 5x7 font. Either way, the 3 data lines and 7 row-enable pins need to find homes in the Arduino digital IO pins. Make sure you don't use digital pin 0 or 1 as that's the serial channel to the ESP8266. I found this out later below...

Once hooked up, just use a similar loop process as per any LED display: Disable all rows, send out the columns to be lit for the first row, enable that row and quickly disable it. Then do the same for the next 6 rows. As quickly as possible! More information on lighting this sign is over here.

#include <IRremote.h>
#include "myfont.h"
#include "digitalWriteFast.h"

int RECV_PIN = 13;
IRrecv irrecv(RECV_PIN);
decode_results results;
IRsend irsend;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  pinModeFast(0, OUTPUT);
  digitalWriteFast(0, LOW);
  pinModeFast(2, OUTPUT);
  digitalWriteFast(2, LOW);
  pinModeFast(12, OUTPUT);
  digitalWriteFast(12, LOW);

//matrix led row drivers
  for (int p = 0; p <= 11; p++) {
    pinModeFast(p, OUTPUT);
    digitalWriteFast(p, LOW);
  }
}

unsigned long last_time = millis();
unsigned long scroll_time = millis();
unsigned long scroll_pause = millis();
bool is_off = true;
int loop_count = 0;
String serialString = " Warming up..";
bool found_start = false;
int charOffset = 0;
int ccol;

void loop() {
  if (irrecv.decode(&results)) {    
    loop_count = 0;
    switch (results.value) {
      case 4841:
      case 0xA90:
        irsend.sendNEC(0xDE21807F, 32);
        if (is_off) {
          serialString = " Power ON!";
          is_off = false;
        } else {
          serialString = " GOOD BYE!";
          is_off = true;
        }
        break;
      case 0x490:
        irsend.sendNEC(0xDE21B04F, 32);
        delay(50);
        irsend.sendNEC(0xDE21B04F, 32);
        delay(50);
        irsend.sendNEC(0xDE21B04F, 32);
        serialString = " VOLUME UP!";
        break;
      case 0xC90:
        irsend.sendNEC(0xDE21708F, 32);
        delay(50);
        irsend.sendNEC(0xDE21708F, 32);
        delay(50);
        irsend.sendNEC(0xDE21708F, 32);
        serialString = " VOLUME DOWN!";
        break;
      case 0xFFFFFFFF:
        irsend.sendNEC(0xFFFFFFFF, 32);
        break;
        //sony teletext red
      case 21225:
        irsend.sendNEC(3726721215, 32);
        serialString = " INPUT!";
        //sony teletext green
      case 13033:
        irsend.sendNEC(3726717135, 32);
        serialString = " MODE UP!";
        break;
        //sony teletext yellow
      case 29417:
        irsend.sendNEC(3726735495, 32);
        serialString = " MODE DOWN!";
        break;
      default:
        Serial.println(results.value);
        Serial.println(results.bits);
        break;
    }
    delay(250);
    irrecv.enableIRIn();
    irrecv.resume(); // Receive the next value
  }

  if (charOffset == 0 && Serial.available() && ((millis() - last_time) > 4000)) {
    last_time = millis();
    serialString = Serial.readStringUntil('\n') + '\0';
    loop_count = 0;
    scroll_pause = millis();
  }
  
  //draw LEDs
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < 90; col++) {
      if (((col / 5) + charOffset) < 60) {
        ccol = (charOffset * 5) + col;
        digitalWriteFast(2, ((font[serialString[ccol / 5]][ccol % 5] & (1 << (6 - row))) > 0) ? HIGH : LOW);
      } else {
        digitalWriteFast(2, LOW);
      }
      digitalWriteFast(12, HIGH);
      delayMicroseconds(5);
      digitalWriteFast(12, LOW);
    }
    digitalWriteFast(row + 5, HIGH);
    delayMicroseconds(75);
    digitalWriteFast(row + 5, LOW);
  }
  
  if ((millis() - scroll_pause > 2500)) {
    if ((serialString.length() > 18)) {
      if (millis() - scroll_time > 180) {
        charOffset++;
        if (charOffset > serialString.length()) {
          charOffset = 0;
          loop_count++;
          scroll_pause = millis();
          if (loop_count > 10) serialString = "";
        }
        scroll_time = millis();
      }
    } else {
      loop_count++;
      if (loop_count > 100) serialString = "";
      charOffset = 0;
    }
  }
}

Overloading Arduino Pins

Anyone watching above, or in the previous post where I hooked the display up to the old PC, was probably screaming in their seats. It's well known that you should NOT draw too much current through the pins on any microprocessor. As soon as I started hooking up more modules onto this unit, things started going haywire and it quickly dawned on me. My seven line-enable pins were being brought LOW to enable the rows... but these were actually working as the single GND conduit for the entire bloody LED display!

DSC01969

I quickly referred to the previous module that ran this sign and saw there was a 74LS145 binary counter in between the Atmel Microcontroller and the 7 enable rows. A quick review of the datasheet shows that this chip can 'sink' up to 15v and is 'great for driving LEDs'. Right... they were properly routing the GND wires away from the microcontroller and using the 145 as a set of transistors. They even saved 3 data lines in the process! I only had a ULN2003 (which would still use 7 lines) and there were no 74LS145 to be found at Jaycar!

DSC01988

This now directed the current away from the microcontroller... but didn't enhance the brightness.

Speeding up the Refresh Rate

It occurred to me that my refresh rates weren't anywhere near as good as the original controller that the sign contained. My loop is busy checking clocks, serial ports and mucking around, so it was never going to actually go fast enough. The code above could run a single segment OK, but started to scale worse as the bit shifting got longer. One trick, which is actually already implemented in the source above is to use an external library to make the digital pin manipulation faster.

With this implemented, there was less flickering and I found that three segments (90 LEDs per row) looked good. One final note is that you shouldn't really use pins 0 or 1 if you've got the serial enabled. They actually present the TX/RX lines and the serial data and the serial data to the Arduino is visible on them. In this case, it was the serial data to/from the ESP8266. In the case below, I had the three data lines required to drive the display on digital pins 0,1,2...

DSC01980

Shifting those to spare pins higher...

DSC01983

Yessssss! It works really nicely.

Filed under: Arduino No Comments