The Southern Spirit – January 2011
I'd checked out The Southern Spirit before, but this time I thought I'd chase it across the state. It's inaugural 2011 voyage was to be from Adelaide to Brisbane starting over the weekend of the 29th and 30th of January.
The Southern Spirit
This train, run by Great Southern Railways, is a once-a-year (although it'll be running the 'journey' twice this year) special service run from Adelaide to Brisbane and return. It's quite a long trip and the journey includes stopovers at stations along the way; including bus tours to local attractions. The train is targeted at people with a large amount of disposable income and a lot of time to spare... you can therefore imagine the average age of the passengers on-board is around 65. Check out more information on The Southern Spirit on the GSR website.
Timetables
I'd done a little investigation and found that The Southern Spirit was to cross 2 freight trains (one twice) and then The Overland. I knew The Overland would be more-or-less on time (when compared to freight) and so decided to start my planning around it. I'd leave Melbourne bright and early and get to Ararat in time for a midday photo of The Overland dropping through. I'd then head west, watch it meet The Southern Spirit and then return home. The Southern Spirit was to stay overnight out west and I would catch up with it again in Melbourne the next morning.
I drew up a diagram, similar to a 'diamond' (a popular Japanese method of showing train paths intersecting), of the trains that would be around the area for Saturday. The y-axis was slightly useless, so I labeled the passing locations and times. Note that 4PM6 didn't show the standard times as it had been modified by ARTC to stop in certain loops to allow trains to pass it. I'd also listed Manor Loop in there, as The Overland was scheduled to pass a freighter; but I've never seen this happen and probably wont get up early for it.
The goal was now set, I was to get to as many of the passes as possible. I also wanted to stop at locations along the way to get the trains in action. Unfortunately, I've never been this way and had no idea where to stop. I also had to make sure I kept to the times as most services would have an NR locomotive on the front and they aren't scared to do line-speed.
Location | Google Time | Better be moving by | Deadline |
---|---|---|---|
Melbourne to Ballan | 1 hour 7 minutes | 0720 | 0829 : V/Line Ballarat to Melbourne |
Ballan to Beaufort | 59 minutes | 0900 | 1007 : V/Line Ballarat to Ararat |
Beaufort to Ararat | 35 minutes | 0958 ## | 1033 : V/Line Ballarat to Ararat 1147 : Overland at Ararat |
Ararat to Diapur Station | 2 hours 23 minutes | 1140 ** | 1342 : Southern Spirit at Diapur Station 1404 : Overland pass Southern Spirit |
Diapur Station to Dimboola Station | 50 minutes | 1358 | 1443-1448 : Southern Spirit at Dimboola |
Dimboola Station to Horsham | 30 minutes | 1445 | 1513 : Southern Spirit arrives Horsham 1521 : 5BA6 pass Southern Spirit |
Horsham to Dimboola Station | 30 minutes (to Station) ~32 minutes (to Loop) |
1523 | 1559 : 5BA6 pass 4PM6 (at Loop) 1614-1619 : 4PM6 (at Station) |
Dimboola Station to Horsham | 30 minutes | 1626 | 1702 : 4PM6 pass Southern Spirit 1748 : Depart Horsham |
Horsham to Ararat | 1 hour 15 minutes | 1745 | 1900 : Southern Spirit arrives Ararat |
## Seems the Regional Fast Rail to Ararat can beat me from Beaufort to Ararat.
** Check that out, The Overland is still meant to be at Ararat Station until 1147 but I need to get going at 1140 (based on Google's time estimate) to see it at the pass The Southern Spirit at 1404 at Diapur Station.
After google'ing the locations, directions, distances and times... it occured to me that catching all of the above passes would be quite a challenge. If the trains did in-fact run at their tabled times, then I would pretty much be neck-and-neck with them along each leg. This wouldn't allow time for any in-between shots. Fortunately I'd still be just-in-time for the passes in each of the loops.
Determining the locations of the 'loops' versus the 'stations' was a little tricky. Fortunately the Vicsig Website has a complete detailed plan of the 'Western SG' line and gives you the distances of the loops from certain landmarks. Google maps didn't know where 'Dimboola Loop' was, but after a little research I found out it was around 5km north/west of Dimboola. It also looked quite difficult to get to from the Western Highway, so I decided to skip the 1559 passing of 4PM6/5BA6 and instead chose to wait for the latter at Dimboola Station.
Now, planning is all well and good when the trains follow their paths... unfortunately this isn't always the case. The Gheringhap Loop Sightings Website has a well-documented list of train movements through the Gheringhap Loop (near Geelong) and it shows, specifically last Saturday, that the two east-bound trains were up to 6 hours late, with 4PM6 being 1.5 hours early. This, to say the least, is disconcerting. The contingency plan was to take all roads as close to the railway as possible and keep an eye out for anything out of the ordinary.
Note: The entire photo gallery of this trip is located here.
V/Line in Country Victoria
The plan was in place and we started out for Ararat at 7am on Saturday the 29th of January, 2011. Our first stop was Ballan and this was made in good time. Google had indicated over an hour, but the trip was easily done, without speeding, in 55 minutes. Here we saw a single V/Line V/Locity DMU arrive on it's way to Melbourne. There's also a nice water tank in the Station carpark.
We then proceeded to Beaufort, bypassing Ballarat. Here we met the first service from Melbourne to Ararat. Again, the trip was quicker than what Google had predicted as the roads were all 110km/h running and quiet.
We then departed for Ararat. There was no chance of beating the V/Locity there and so we took our time. The Overland wasn't due in Ararat until 11:47 and we were easily going to be there an hour early.
Ararat
As we arrived we saw the V/Locity terminated on the platform and used it as an excuse to check the station platforms out.
After grabbing a coffee in the main street we attempted to find a suitable position to photograph The Overland. We would need a quick departure from Ararat to meet The Overland again as it had priority on the tracks. The next station would be Horsham which was around 100km away.
Although the sun wasn't in our favour, we chose a spot on the other side of the railway, close to the highway. I also chose the wrong lens, but got a few photos of The Overland arriving at Ararat 20 minutes early.
We didn't wait for The Overland to leave... we jumped in the car and headed for Horsham. Unfortunately the roads were all 100km/h and we were passed by The Overland about 20km out of Ararat.
Horsham
We hadn't had any visibility of the rails for around 40km prior to Horsham, but had expected that all hope was lost. It was a nice surprise that, upon arrival to the station, we found passengers waiting for the train. There were even a few freight locomotives shunting around the yard.
And then The Overland arrived.
We, again, didn't give it a chance to leave before us... We knew what it was capable of and needed a head start.
Horsham to Dimboola
This was the best part of the trip. The drivers were on to us, they knew we were tagging along. They also made us know that they were perfectly capable of beating us... blowing their horns as they passed us on the highway. The rail between Horsham and Dimboola runs parallel for 90% of the way and is great when you're running side-by-side. Unfortunately The Overland had no intention of hanging around.
We then fell behind quite heavily and watched as the train seemed to drive across the road around corners... it really is a great sight. We proceeded to Dimboola hoping to go straight through and get another head start.
Dimboola
As we came in to the town we knew we'd been beaten. The level crossing was already quiet and, as we crossed it, we saw the tail of the train in the platform. This meant we had around 2 minutes to get in front of it. Finally the sun was on our side and we parked a few metres west of the station to watch the train depart.
Now it was decision time. The Overland was meant to cross The Southern Spirit at Diapur Station. This was around an hour away by car, but we couldn't guarantee that the roads/traffic would allow us to get there in time. We also knew that The Overland was running around 20 minutes early. This meant that, depending on the timing of The Southern Spirit, the cross could be made at another location...
We had decided to proceed through to Dimboola Loop. I'd known, thanks to the Vicsig website, that it was around the AWB facilities near Dimboola, but from the road, it wasn't easy to spot. Either way, we saw no trains around the area. We continued on, expecting to travel as far as Nhill.
As we were around 25mins west of Dimboola, a headlight appeared on the tracks. The last thing we expected was dirty NRs on a freight train, but there was 4PM6 hurtling towards us. The Overland had already passed it, somewhere west of Dimboola Loop and the freighter had already built up speed and was heading for it's scheduled stop in Dimboola. This train was expected to be held back at Tailem Bend and was meant to run behind The Southern Spirit until Horsham but had instead been allowed to proceed.
We then pulled a strategic u-turn and followed the freight back to Dimboola. This was an easy chase, as the freighter was unable to hold 100km/h on the gradients. We got back to Dimboola in time and had the sun on our side for once.
I had a quick chat to the driver who confirmed it was 4PM6 and that The Southern Spirit was due through not long after. The drivers swapped over and the freighter departed quickly. We then waited around for our first sighting.
The Southern Spirit at Dimboola
Around 35mins later we could hear an NR powering its way towards Dimboola. A headlight then appeared over the incline from the west and the next thing we knew, the whole train had passed. We had seen that the signal was green and that the train didn't have to stop but, after the freighter crawled though, we weren't expecting line-speed. I managed to scramble a few photos but, even in broad daylight, the motion blur couldn't be avoided.
We had now finally seen the train and followed it back to Horsham. There was absolutely no chance of beating it and we knew it was to stable for around 3 hours there.
Horsham Station
As we were arriving back in to Horsham, we saw the tail of the train... It was doing around 10km/h towards the first level crossing in the town which was still inactive. After hitting it's horn, the lights and bells started chiming and it proceeded further. Fortunately, we were doing 60km/h and easily made it to the station before it.
The train had to take two attempts to get everyone off. I believe I counted 16 cars and there was no way it would fit on the platform at once. There was an El Zorro grain train with T386 and C501 playing around in the container yards as well.
Horsham itself wasn't very photogenic and so we decided that Ararat would be a better option. The goal was also to find a line-side position somewhere along the way to get The Southern Spirit once again. Unfortunately the line deviates a long way off the beaten path and we gave up. We therefore also missed the west-bound container train (if it ran at all.)
After arriving much too early at Ararat, we decided that it was time to return back to Melbourne; we'd see the train again in the morning.
The Southern Spirit in Melbourne
I assumed my usual position at the North Melbourne flyover and met a few new people who were also waiting for the same train. The XPT arrived on time and then the Southern Spirit arrived, attached it's pilot loco and then proceeded to Southern Cross Station.
The consist then made its way back to the freight yards after dropping the passengers off. The pilot loco did all the work here over the flyover. The XPT also started its return journey to Sydney.
The consist then sat in the freight yards for around two hours. I had enough time for breakfast and then returned to the Canal Sidings to watch it come back into Southern Cross.
The final trick then was to get out to the bridge over the same "Railway Canal" near Jacana. This should have been an easy shot but I chose the wrong lens again. Either way, it was a great way to end the chase.
The Southern Spirit will return via Melbourne and be at Southern Cross at around 7pm on Tuesday the 8th of February. The pilot locomotive will be attached at the same location but will be detached well out of town. This will be well worth a photograph or two and I'll attempt to get them next week.
The whole journey from Adelaide to Brisbane and return is also to be repeated, starting on the weekend of the 12th and 13th of February. I'm not so sure if I'll cover the 1000km again, but you never know, there might be other interesting things to see in the area.
Chichibu Railway – September 2010
An apology: I'd traveled here last year whilst in Japan and had completely forgotten to write up the experience. Hopefully I haven't mis-recollected too much of the following information :)
I'd seen the freight operations in Chichibu online in multiple places, but wanted to go and check out the 'rolling museum' for myself; it was one of the many private railways that I had intended to visit and one that I had the freight timetables for.
The Chichibu Railway
The Chichibu Railway (Official site, Japanese only) is a private railway in Japan which runs west from Hanyu Station to Mitsumineguchi Station via Kumagaya. The railway operates both passenger and freight (limestone) services. It's rolling stock consists of many handed-down locomotives and multiple units.
Getting to Chichibu from Osaka
Since I'd been visiting friends in Osaka, I wasn't in the best location to be getting to Chichibu early enough for some of the freight operations. Fortunately, Japan still has quite a few overnight services and one of these, the Kitaguni, would get me to Nagaoka in time to transfer to the Shinkansen to Kumagaya.
The Kitaguni departs Osaka Station just before 11:30pm each day and arrives at Niigata just before 7:00am the next morning. The service is operated by dedicated 583 Series EMUs and has multiple types of sleeping accommodation. I chose the cheapest bed, but I don't recommend this. See the photo below; I was in the top bunk and you get only a single peep-hole for a view.
Nagaoka to Chichibu
We stopped at Naoetsu Station briefly on the way through to Niigata. I grabbed a few photos before we continued on to Nagaoka.
At Nagaoka Station I transferred to the next southbound service to Kumagaya. I had breakfast at the station and then found the Chichibu platforms downstairs. Tickets were purchased from a vending machine and I chose to travel to Takekawa. This station is west of the branch that runs to the Taiheiyo Cement Factory and is the first place to see traffic heading east-bound.
Upon arriving at Takekawa I found several of the electric freight locos stored in the yard. This was to be an ominous sign, as it seemed most of the services I wanted to see that morning weren't running.
I walked a lap around the yard and the station and checked out the surroundings. Takekawa is a very quiet little suburb, but the locals seem to be used to railfans hanging around. I greeted one or two people who didn't seem too upset with me loitering and taking photos of the infrastructure. I was also greeted by around 30-odd small children on a school excursion crossing the pedestrian bridge.
After walking about 3/4 of my lap the 'express' EMU passed and I got a shot of it from the level crossing east of the station.
I looked again at my timetable and realised that there was to be another freight coming in and so positioned myself on the station island platform. I watched as one of the staff inspected (and tightened) the handbrakes on a rake of limestone hoppers (WAKIs).
The level crossing west of the station then sounded. The previous east-bound passenger train had already passed and so I realised I was finally going to see a freight movement.
In came locomotive 504 with a small rake of limestone hoppers. It stopped on the road closest to the platform and another engineer jumped on the front. They then left the hoppers and trundled down the rails towards the factory.
That then ended my brief tour of the Chichibu. I returned to Kumagaya on the next passenger service and took the Shinkansen into Tokyo. The rest of the afternoon was then spent with friends in Akihabara.
As per usual, with any freight railway in any country, any timetables available must be taken with a level of doubt. The paths set for trains are only really useful when there is a train to be moved. I had a feeling that there were too many stored locos in the yard and this turned out to be true; as out of the 5 movements to be seen in the timeframe I was there, only one ran.
Either way, I was more than content with seeing preserved locomotives still operating and was also impressed with the other hand-me-down rolling stock on the Chichibu.
Oh! That's right, I was also there to see the Paleo Express, which was meant to run on that day.
...It didn't...
An attempt to simulate Acceleration and Braking
In my previous post, I'd managed to get my Densha-De-Go Dreamcast controller hooked up to my Arduino Mega. Now although this now meant that I had a great way to control my model railroad, it also meant I had to work out how to code a throttle and a brake lever.
The rules
After a few hours of plotting, I had decided on the following system. It involves a 6-position throttle and an 11-position brake. Each 'position' is to have a 'max speed' and 'speed adjust' associated with it.
Notes
- It is to be assumed that if the brake is on, the throttle is automatically disabled
- MAX is 255 on the PWM Throttle (or max voltage from supply)
- At Throttle 0, the train is neither powering nor braking; we will simply slowly decrement the speed
- There is no feedback to know how fast the train is currently travelling
- There are multiple emergency brake points on the throttle, but we don't care about them.
The next table shows my acceleration and braking deltas. This will be a simple addition and subtraction on the current speed.
Lever position | Max Speed | Speed Adjustment |
---|---|---|
Emergency Full | Instant Stop | |
Emergency 5 | -50 | |
Emergency 4 | -30 | |
Emergency 3 | -25 | |
Emergency 2 | -20 | |
Emergency 1 | -10 | |
Brake 9 | -2.4 | |
Brake 8 | -1.8 | |
Brake 7 | -1.2 | |
Brake 6 | -0.8 | |
Brake 5 | -0.4 | |
Brake 4 | -0.2 | |
Brake 3 | -0.1 | |
Brake 2 | -0.05 | |
Brake 1 | -0.025 | |
Throttle 0 | 0 | 0.00 |
Throttle 1 | 55 | +0.25 |
Throttle 2 | 75 | +0.5 |
Throttle 3 | 90 | +1 |
Throttle 4 | 100 | +1.75 |
Throttle 5 | 120 | +2.5 |
And now a better way to represent it.
The code
The table above translates to code quite easily... the goal is to have the lever position values coded into an array and then just select the correct entry. Once determined, the main code loop can then determine how to adjust the current voltage output to the rails.
const int throttle_positions = 21; const int throttle_absolute_maximum_speed = 255; const int throttle_minimum_speed = 20; int current_throttle_position = -1; // 0 is EM FULL. Lever must be moved to EM FULL to begin. float current_speed = 0; float target_speed = 0; int throttle_max_speed[throttle_positions] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //brake positions and Throttle 0 0, 55, 75, 90, 100, 120 }; float throttle_delta[throttle_positions] = { 0.025, 0.05, 0.1, 0.2, 0.4, 0.8, 1.2, 1.8, 2.4, 10, 20, 25, 30, 50, 9999, //brake 0.00 /*coast*/, 0.25, 0.5, 1, 1.75, 2.5 };
We then need to determine the current throttle position. We will make it that, at the start of code execution, the train should not move until the throttle has been reset to EM Full and the throttle at '0'.
#define BRAKE_MASK 0xf0 #define BRAKE_SHIFT 4 #define ACCEL_MASK 0x07 void read_throttle_position() { int accel = packet.data[6] & ACCEL_MASK; int brake = (int)((packet.data[7] & BRAKE_MASK) >> BRAKE_SHIFT); if (current_throttle_position == -1) { //check that we have EM FULL and Neutral if (brake == 15 && accel == 1) { //set the initial '0' (EM FULL) position. current_throttle_position = 0; lcd.clear(); } } else { if (brake != 1) { //1 == "BRAKE 1", if it's higher, we're braking. if (brake > 0) current_throttle_position = brake; } else { //BRAKE == 1 and then we check the throttle //we're accelerating. if ((accel + 15) < 22) current_throttle_position = accel + 15; } } }
And now the main game loop needs to determine the current lever locations and then choose the appropriate action:
void update_speed() { digitalWrite(13, LOW); //make sure we are allowed to go. if (current_throttle_position >= 0) { if (current_speed > throttle_max_speed[current_throttle_position - 1]) { current_speed -= throttle_delta[current_throttle_position - 1]; //braking... don't go negative. if (current_speed < throttle_minimum_speed) current_speed = 0; } else if (current_speed < throttle_max_speed[current_throttle_position - 1]) { //accelerating, so start from minimum speed. if (current_speed < throttle_minimum_speed) current_speed = throttle_minimum_speed; current_speed += throttle_delta[current_throttle_position - 1]; //don't go faster than current throttle max setting. if (current_speed > throttle_max_speed[current_throttle_position - 1]) current_speed = throttle_max_speed[current_throttle_position - 1]; } //set light if we have met max speed for throttle. if (current_speed == throttle_max_speed[current_throttle_position - 1]) digitalWrite(13, HIGH); //output speed to railway. analogWrite(7, current_speed); } else { //flash the LED to alert user to reset controls. delay(200); //delay a little to flash the LED digitalWrite(13, HIGH); delay(200); } }
There's also some code in the main loop to update the 16x2 LCD I've hooked up. Since we need to reset the controller when we start, it'll tell you to do so and afterwards will tell you the current throttle/brake position, current speed and speed delta.
Note that this does not include the full arduino-maple code. Download that here. You will also need the LiquidCrystal library from the Arduino site.
Action shots
Shown is the controller in certain positions. Note that the 'Throttle' positions may show a negative speed delta; this just means that they are no longer accelerating.
Arduino + Dreamcast Densha-De-Go Controller
I've had Densha-De-Go and the controller for the Dreamcast for a while now... I'd even invested a few hours in playing the actual game, but the accuracy required is crazy. Supposedly in Japan it's that realistic that even real train drivers have a hard time getting it spot on :)
Anyway, I'd wanted to get this going for train control for a while after managing to make a Wii Nunchuck control my trains.
You can find more information on the controller at SEGA Retro, SEGAGAGA Domain, Wikipedia, Play Asia and genki Video Games.
Previous attempts
Quite a few months ago I spent a few hours with my Densha-De-Go controller and my Arduino Mega in an attempt to get them to communicate. The goal was to be able to read the controller and then use it to control my model railroad. Unfortunately, I was doing this blind, running off information from Marcus Comstedt's 'Dreamcast Programming' site; specifically his breakdown of the Maple Bus Protocol.
I ended up with nothing working and sent out a few pleas for help on the Arduino forum and to Marcus himself. I received information regarding the fact that it should work (the Arduino had the horsepower), but I would have to ensure the timing was intricate and that the Arduino was always ready to receive data.
I then posted to the Arduino Forum for help. A few months later WzDD came to my rescue with word that he had successfully made the Arduino communicate with a Dreamcast Controller. I hadn't had much time up until now to work on this, and WzDD hadn't done any further work on it, so I took it that he just wanted to prove the concept and that I'd have to get off my backside to make things progress further. In the end, I did want to get my controller functioning.
I had previously had everything I needed to test this again, so I gave it another go. My previous setup was a cut-in-half Dreamcast controller extension cable and my Densha-De-Go controller. The extension cable meant I didn't have to hack around with the actual controller or port imitation.
Getting set up...
Due to the requirement to use assembler for the actual low-level controller interactions, we cannot use the Arduino IDE and must use WinAVR (or just avrdude on Linux.) Download this from here (select the latest version) and install to the default directory.
You then need to download the arduino-maple source code and extract somewhere locally. I've put the folder on C:\arduino-maple\.
Open Programmers Notepad [WinAVR] from the start menu and then open the arduino-maple.cpp file from where it has been extracted. (C:\arduino-maple\arduino-maple.cpp in my case.)
If all is installed correctly, then you should be able to choose Tools - [WinAVR] Make All and have the following output in the output window:
> "make.exe" all avr-gcc -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -ffreestanding -funsigned-char -funsigned-bitfields -mmcu=atmega328p -DF_CPU=16000000UL -I./arduino -c arduino/pins_arduino.c -o build/arduino/pins_arduino.o In file included from arduino/wiring_private.h:30, from arduino/pins_arduino.c:26: c:/winavr-20100110/lib/gcc/../../avr/include/avr/delay.h:36:2: warning: #warning "This file has been moved to <util/delay.h>." ... Lots of warnings, no errors... ... avr-g++ -Os -Wl,-gc-sections -mmcu=atmega328p build/arduino/pins_arduino.o build/arduino/WInterrupts.o build/arduino/wiring.o build/arduino/wiring_analog.o build/arduino/wiring_digital.o build/arduino/wiring_pulse.o build/arduino/wiring_shift.o build/./arduino-maple.o build/arduino/HardwareSerial.o build/arduino/Print.o build/arduino/Tone.o build/arduino/WMath.o build/arduino/WString.o build/./libmaple.o -o app.elf avr-objcopy -R .eeprom -O ihex app.elf app.hex avr-size --format=avr --mcu=atmega328p app.elf AVR Memory Usage ---------------- Device: atmega328p Program: 3380 bytes (10.3% Full) (.text + .data + .bootloader) Data: 796 bytes (38.9% Full) (.data + .bss + .noinit) > Process Exit Code: 0 > Time Taken: 00:02
Now, as you can see above... that's not my Arduino! I have an Arduino Mega and therefore we need to adjust the Makefile correctly for my setup. Here you'll need to know the CPU code, interface type and the port number. Also make sure you change the upload task to program so that we can use the menu items in WinAVR.
# Makefile for building small AVR executables, supports C and C++ code # Author: Kiril Zyapkov # Hacked up by nfd SOURCE_DIRS = . arduino INCLUDE_DIRS = arduino MMCU = atmega1280 F_CPU = 16000000UL SRC_ROOT = . BUILD_DIR = build CFLAGS = -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -ffunction-sections \ -fdata-sections -ffreestanding -funsigned-char -funsigned-bitfields \ -mmcu=$(MMCU) -DF_CPU=$(F_CPU) $(INCLUDE_DIRS:%=-I$(SRC_ROOT)/%) CXXFLAGS = -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -ffunction-sections \ -fdata-sections -ffreestanding -funsigned-char -funsigned-bitfields \ -fno-exceptions -mmcu=$(MMCU) -DF_CPU=$(F_CPU) $(INCLUDE_DIRS:%=-I$(SRC_ROOT)/%) LDFLAGS = -Os -Wl,-gc-sections -mmcu=$(MMCU) #-Wl,--relax TARGET = $(notdir $(realpath $(SRC_ROOT))) CC = avr-gcc CXX = avr-g++ OBJCOPY = avr-objcopy OBJDUMP = avr-objdump AR = avr-ar SIZE = avr-size SRC = $(wildcard $(SOURCE_DIRS:%=$(SRC_ROOT)/%/*.c)) CXXSRC = $(wildcard $(SOURCE_DIRS:%=$(SRC_ROOT)/%/*.cpp)) ASMSRC = $(wildcard $(SOURCE_DIRS:%=$(SRC_ROOT)/%/*.S)) OBJ = $(SRC:$(SRC_ROOT)/%.c=$(BUILD_DIR)/%.o) $(CXXSRC:$(SRC_ROOT)/%.cpp=$(BUILD_DIR)/%.o) $(ASMSRC:$(SRC_ROOT)/%.S=$(BUILD_DIR)/%.o) DEPS = $(OBJ:%.o=%.d) $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.c $(CC) $(CFLAGS) -c $< -o $@ $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.S $(CC) $(CFLAGS) -c $< -o $@ $(BUILD_DIR)/%.o: $(SRC_ROOT)/%.cpp $(CXX) $(CXXFLAGS) -c $< -o $@ all: app.hex printsize #$(TARGET).a: $(OBJ) # $(AR) rcs $(TARGET).a $? app.elf: $(OBJ) $(CXX) $(LDFLAGS) $(OBJ) -o $@ $(BUILD_DIR)/%.d: $(SRC_ROOT)/%.c mkdir -p $(dir $@) $(CC) $(CFLAGS) -MM -MF $@ $< $(BUILD_DIR)/%.d: $(SRC_ROOT)/%.cpp mkdir -p $(dir $@) $(CXX) $(CXXFLAGS) -MM -MF $@ $< #$(TARGET).elf: $(TARGET).a # $(CXX) $(LDFLAGS) $< -o $@ app.hex: app.elf $(OBJCOPY) -R .eeprom -O ihex $< $@ clean: echo $(RM) $(DEPS) $(OBJ) $(TARGET).* printsize: avr-size --format=avr --mcu=$(MMCU) app.elf # Programming support using avrdude. Settings and variables. PORT = /dev/tty.usbserial-A700ekGi #PORT = /dev/ttyUSB0 AVRDUDE_PORT = com3 AVRDUDE_WRITE_FLASH = -U flash:w:app.hex MCU = atmega1280 AVRDUDE_PROGRAMMER = stk500v1 #AVRDUDE_FLAGS = -V -F -C \app\arduino-0021\hardware\tools\avr\etc\avrdude.conf AVRDUDE_FLAGS = -V -F \ -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ -b $(UPLOAD_RATE) UPLOAD_RATE = 57600 # # Program the device. INSTALL_DIR = \app\arduino-0021 AVRDUDE = avrdude program: app.hex #python pulsedtr.py $(PORT) $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
The first line in the program target (Line 93) 'pushes' the reset button on the Arduino. As we don't have Python installed we have to do this manually. So, build the source code via the [WinAVR] Make All and ensure there are no errors. Now press the 'reset' button on the Arduino and then quickly choose Tools - [WinAVR] Program. If all goes correctly then you'll see the code uploading to your Arduino:
#python pulsedtr.py /dev/tty.usbserial-A700ekGi avrdude -V -F -p atmega1280 -P com3 -c stk500v1 -b 57600 -U flash:w:app.hex avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.05s avrdude: Device signature = 0x1e9703 avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file "app.hex" avrdude: input file app.hex auto detected as Intel Hex avrdude: writing flash (3508 bytes): Writing | ################################################## | 100% 1.09s avrdude: 3508 bytes of flash written avrdude done. Thank you. > Process Exit Code: 0 > Time Taken: 00:03
And that's it, our the compiled code for the arduino-maple project is now on the Arduino and running!
Using the Python code on Windows
I lied, I said I didn't have Python installed... but I ended up installing it anyway. The job to convert the Python code to C# was going to take too long and, to prevent a debugging nightmare, I decided I would get the known-to-work Python code going under Windows first. So, I installed Python from the official website and then started learning :)
Note that I downloaded and installed Python Version 2.6.6 as this was the version that would have been available when arduino-maple was created.
After selecting 'IDLE' from the start menu, I was presented with a light-weight GUI. I opened up the 'maple.py' that's included with the arduino-maple code and attempted to compile it.
I had problems at the start, as in the included Makefile there are two declarations of CPU type. Initially I hadn't set these both correctly and the Arduino includes were not correctly compiled... make sure you carry out a proper clean whenever changing code; this includes manually deleting all of the .o files.
Once this was sorted, it all finally worked... sort of?
connecting to COM3: connected SENT: 0000200121 No device found at address: 0x20 SENT: 0000010100 1c20000501000000ff0f3f000000000000000000415400ff204f544920313030746e6f436c6c6f7 2202072652020202020200024191bdc94191958dd481e508815481c9bdc99591b98da5308195 cdb995bdc91881154c8c9b40481051d491551394d25494130b14d1480b911508080808007d00371 117 Command 5 sender 0 recipient 20 length 1c Device information: Functions : CONTROLLER Periph 1 : 0x3f0fff Periph 2 : 0x0 Periph 3 : 0x0 Name : ..TAITO 001 Controller $. License : .....X...P.H..H..Y...S....\....[..T.....Q.I.I%M9M.0A.......P Power : 53251 Power max : 32775 Play with the controller. Hit ctrl-c when done. SENT: 010020090100000029 SENT: 010020090100000029 1111101010011111 SENT: 010020090100000029 1111101010011111 SENT: 010020090100000029 1111101010011111 SENT: 010020090100000029 1111101010011111
Timing issues
As I continued to run the code, I would get random results as to the 'Name', 'License' and 'Power' fields... well, it was obvious in the text fields that there were problems, but I had no idea that what the 'Power' fields were meant to read. Either way, this indicated a timing issue somewhere and I guessed that life was about to get difficult. Note that I had always been running the controller at 5v, as that's what WzDD's post said the blue wire should be connected to, but it turns out that the device should have actually been running on 3.3v.
Unfortunately, setting the controller on to 3.3v didn't change anything... the responses were still mildly random. The buttons would be sent though correctly (apart from the B button) but the initial device description would come through jumbled. I took a few samples of the data and realised that the data would always have a minimal length. To me this meant that we weren't missing bytes/bits, but actually reading too many. The analysis showed that there were similar chunks all the way through, but at certain intervals there'd be extra/changed characters. Based on Marcus Comstedt's Maple Bus information, I guessed that we were re-reading bits too quickly and needed to slow down a little... This would mean slowing down the pin reading in WzDD's arduino-maple assembler code.
In the maple_rx_raw: function down near _rx_loop:, the code iterates through the pins hoping to read the data. It initially checks the state of the pins to sense when the controller is about to send data, but this did not have the final check for the second pin going low.
4: IN rport2, _SFR_IO_ADDR(PINB) BST rport2, bitmaple5 ; maple5 BRTS 4b ; must be low now
The above code was added around line 305 to ensure this check was in. I then also 'spaced' out the store/read calls by placing a delay in. WzDD had already written the delayquarter macro and I simply re-used this.
... _rx_store rport bitmaple5 5 _rx_read bitmaple5 delayquarter _rx_store rport bitmaple1 4 _rx_read bitmaple1 ...
After these two changes, the text from the device information call worked flawlessly. But my B button still didn't work. I decided the B button wasn't important at this stage and went on to decoding the controller to work out how the levers functioned.
Densha-De-Go controller workings
So, after having used the standard Dreamcast controller to play hours-upon-hours of Shenmue, Shenmue II and Chu chu rocket, I would have expected at least one of the levers on the Densha-De-Go controller to use the analog joystick and the other to also use some form of analog control. After a few minutes decoding the controls, it became apparent that they simply used the buttons available (up, down, left, right, x, y, z) in a binary-value style configuration.
Throttle Position | X | Y | Z |
---|---|---|---|
T0 | [x] | [x] | |
T1 | [x] | [x] | |
T2 | [x] | ||
T3 | [x] | [x] | |
T4 | [x] | ||
T5 | [x] |
Other Buttons | Mapping |
---|---|
SELECT | D |
START | START |
A | A |
B | ?? |
C | C |
Brake Position | UP | DOWN | LEFT | RIGHT |
---|---|---|---|---|
B0 | [x] | [x] | [x] | |
B1 | [x] | [x] | [x] | |
B2 | [x] | [x] | ||
B3 | [x] | [x] | [x] | |
B4 | [x] | [x] | ||
B5 | [x] | [x] | ||
B6 | [x] | |||
B7 | [x] | [x] | [x] | |
B8 | [x] | [x] | ||
EM0 | [x] | [x] | ||
EM1 | [x] | |||
EM2 | [x] | [x] | ||
EM3 | [x] | |||
EM4 | [x] | |||
EM5 | - | - | - | - |
In between the B's there is a slight overlap of the buttons, where the current and next 'combination' is combined, but this doesn't seem to last more than one cycle.
In between the EM's the controller reads UP-DOWN-LEFT-RIGHT. This area exists between all EM's and B8-EM0 and seems to be about 3mm wide.
Controlling trains
Now it was time to get this incorporated into my original train throttle. I didn't want to have to use the Python code, so instead I 'crafted' the packets into the Arduino code.
//here is a quick packet to request device information from controller 'one'. //i.e. the only controller connected. packet.header[0] = 0; // Number of additional words in frame packet.header[1] = 0; // Sender address = Dreamcast packet.header[2] = (1 << 5); //(1 << 5); // Recipient address = main peripheral on port 0 packet.header[3] = 1; // Command = request device information packet.data[0] = 0x21; //checksum packet.data_len = 5; //send the above packet to initiate comms with the controller. maple_transact();
I'm going to gloss over this part pretty quickly, as this post was more about getting the Dreamcast controller usable rather than another lesson in physics and model railway throttles. For the code, I ended up just deciphering the packet that comes back from the controller, working out what the throttle position is and then adjusting the target speed. The main program loop then makes then increment/decrements the current speed to eventually match the target speed. This provides a very simple form of acceleration.
void control_throttle(void) { //quick hack, should actually do a binary 'and' //packet data[6] contains the throttle position, so use this to gauge //voltage output to pin 7 (or speed) switch (packet.data[6]) { case 0xF9: target_speed = 0; t_pos = 0; break; case 0xFA: target_speed = 88; t_pos = 1; break; case 0xFB: target_speed = 96; t_pos = 2; break; case 0xFC: target_speed = 140; t_pos = 3; break; case 0xFD: target_speed = 190; t_pos = 4; break; case 0xFE: target_speed = 250; t_pos = 5; break; } }
The changing of pin 13 below lights the on-board Arduino LED to show once the loop has made the speed match the target speed.
digitalWrite(13, LOW); if (target_speed > speed) { //accel speed += t_pos / 2; } else if (target_speed < speed) { //speed += abs(target_speed - speed); //decel speed--; } else { digitalWrite(13, HIGH); } //send the speed to the pin/railway analogWrite(7, speed);
And then... it just worked :)
Note that this does not include the Python code; nor will my code correctly interact with the python code anymore. The goal was always to have the Arduino talk to the Dreamcast controller directly.
As you can see, I've only implemented the throttle on the controller... I need to now bring in the brake lever as well, but this is where the physics lesson comes in. I'll be posting again soon enough with source code for acceleration and braking using this controller.
I've got a few ideas as to how to semi-realistically control the train with both levers, but I will need to do a little more reading before I get something going. I do know that in the actual Densha-De-Go game, the game complains when you have both levers on at the same time... and it seems wrong to be doing so... but then again, it'd be like doing a hill-start :) Maybe for freight trains?
If only our model railway trains had gears and could free roll!
Canberra to Queensland
I'd been invlted to the Gold Coast for NYE 2010 and so I thought I'd make an adventure of it and go by rail. Google Maps indicated that, via the Pacific Highway, the distance is 1,130km and, by car, it would have taken around 14 hours. I wasn't going for a land-speed record (and this isn't Japan) so I decided to take a relaxed path via Country Link (which does happen to be the only regional rail transport that travels north nationally.) This trip was to go via Sydney, Maitland (the start of the Hunter Valley) and then the north coast (overnight) to Brisbane. I could have chosen to switch to a bus at Grafton/Casino, but I didn't feel like changing transport at some gawd-awful time in the morning and a bus didn't appeal to me. After arriving at Brisbane early in the morning, I was to change to QR and travel south to the Gold Coast, arriving around 8:00am.
Canberra
This trip started early at Kingston Railway Station in Canberra, ACT on Wednesday the 29th of December. This station (note that we are in Australia's capital) sees no more than 3 passenger train departures per day and 3 arrivals. These are even staggered so that every second day you can leave in the morning and afternoon, alternately with morning and evening on other days. Randomly inconvenient and it gets worse; the trip to Sydney (Central Station) takes around 4.5 hours. Meanwhile, if you are wanting to buy tickets for Country Link trains, I can only recommend to purchase them at Queanbeyan Station as it's run by the staff of the ARHS ACT and they get a commission.
Either way, we got off on time and stopped at Queanbeyan 10 minutes after leaving Canberra.
We then arrived at Bungendore around 30minutes later. As I had worked on the ARHS ACT trains, I knew I had enough time to grab a few photos as the whole line from Canberra to Goulburn still uses the 'staff' system. This meant that the driver had to exchange staffs in each of the signal boxes along the way.
At Tarago, the same thing had to happen and so I checked out the station. This was the final station on the Goulburn-Canberra branch before the train was to enter the "Main South". After this there were not going to be many other photo opportunities.
Sydney (aka. CityRail)
We arrived at Strathfield Station at some time after 10:00am after leaving Canberra at 6:43am. I then had about 6 minutes to change platforms and get onto a northbound express service. This service was to be run by CityRail which is the Sydney electric train network operator. They also run DMU services on non-electrified track.
This northbound train was to terminate at Wyong, but that was good enough, as I knew that there were freight services running over the "Main North" to keep me entertained there. I'd stopped by Wyong around 3 years ago and had seen a nice couple of RLs carrying freight southbound... unfortunately, we were well short of Wyong when the freighter stormed past, doing a great speed up the Cowan bank.
The CityRail fleet consists of all sorts of electric trains, but the northbound long-distance routes are covered by "V" sets (I believe) and they are ancient... Fortunately they are extremely comfortable and are even decked out with toilets and mildly-functioning air-conditioning. Really quite retro!
I therefore got off at Wyong and waited for the next service to Newcastle. I would only travel as far as Hamilton which is three stops before Newcastle and is the first station which intersects with the Hunter Line. Here I would transfer and then travel on the diesel service to Victoria Street where I was to stay overnight.
The DMUs used on the Hunter Line are two-car and I think nearly everyone of them had a flat-spot on one wheel somewhere.
Maitland and surrounds
Now, once in the heart of coal-country, it wasn't going to be too long until a coal train was to come hurtling past; it ended up being three, straight after each other. From what I gathered, the trains gave around 10 minutes minimum between each other when travelling in the same direction; but the paths were already clear well before.
After realising I could see coal trains all day, I packed up the camera and checked in to my hotel. Once settled, I then headed back to Warabrook Station and checked out the action. This station is located between Islington Junction and the other triangle (Koogarang Junction?)... although the double-triangle is probably known as Islington Junction. Either way, coal trains would be entering from all directions and I wasn't disappointed.
So, random light engine movements, but no coal trains... it turns out I could see them, but none were coming from the Newcastle direction. I therefore jumped on the next westbound train and got off at the next station past the triangle: Sandgate.
Day two
I was to catch the 6:65pm XPT from Maitland Station to Brisbane and therefore had the whole day to check out what was happening around the Hunter. I dumped my bags at Maitland Station and then proceeded to loiter at random points between Maitland and Newcastle. Fortunately, as soon as I'd sorted out my luggage, an 81 class + 2 48s rolled in with a grain consist. It turns out they were not going anywhere until the next DMU was through (thanks for that information from the drivers!) and therefore I took a few photos at Maitland Station and then waited for it at Sandgate.
At Sandgate, the main line is elevated over the coal lines to Koogarang Island. I was told by the grain train drivers that they were to change onto the main line and proceed through to Broadmeadow yard. This meant that they would come over the hump... of course, I didn't make it to the platform end to get the 'perfect shot'... but it worked out OK anyway...
I loitered at Sandgate and was lucky to see QRs new liveried 50 class.
The rest of the afternoon...
It was too hot by 11:00am to be hanging around in the sun and so I travelled on to Newcastle and swam at the main beach. Afterwards I ventured back to Broadmeadow Station to see if there was anything interesting going on. Broadmeadow is at the mouth of a maintenance/storage yard for locomotives and wagons. Unfortunately I only got to see a coal train passing through.
Back to Warabrook Station
I had been on to a good thing the day before, and so I though I would return to see what else was moving around.
Overnight on the XPT
I'd done this once before, back in 2000 or so, and I can only imagine that I'd forgotten how difficult it was to sleep upright. We ran on-time all the way, but the track wasn't as smooth as it could've been.
Meanwhile, the view as the sun was setting north of Maitland was beautiful. Rolling green pastures and lots of stock roaming around or running from our train. Unfortunately, the sun set pretty quickly and the reflective tint on the outside of the windows meant that there was next to zero visibility.
Lights were out at 10:00pm and most people tried to sleep (some with very loud music in their earphones.) Sleeping wasn't too easy though, as there were stations all throughout the night and people were getting on and off the train, dragging their luggage and making enough noise to wake all the light sleepers up. Even better was the fact that the guy next to me wasn't meant to be there, so at 11pm we all had to shuffle around when the actual passenger arrived.
After a random amount of sleep, then sun started rising at 5:30am and the view from the train was undeniably suburban Brisbane. A lot of the houses we passed backed on to the railway line and didn't care much for fences. We finally arrived at Roma Street Station and then I transferred to the Gold Coast Line to Nerang.
Final words...
Until Australia cares for passenger trains... CountryLink will be the only option for east coast travel. The line has been primarily built for freight trains and therefore there is no regard for speed or smooth travel. They have done a lot of improvement work over the years, but again, population and demand is lacking to make any more of it.
I would recommend this trip be done during daylight as opposed to overnight. The view is spectactular and having had the sun up during the entire route would have been great. The only other way to do it would be via a sleeper compartment, but the cost will be quite prohibitive for the foreseeable future.