Subscribe via RSS
4Sep/100

Plans to visit Private Freight Railways in Japan

I'm heading back to Japan for a wedding in September on Monday and have decided to seek out and photograph the private freight railways that exist around the Kansai area. From a few Google searches (and a very large thanks to the data found on this site), I've come up with the following list:

Railway Name Year Started Operating Area Freight Carried
Mizushima Rinkai Railway 1943 South of Kurashiki/Okayama Chemicals, Container
Wikipedia: Mizushima Rinkai Railway
Wikimedia: Stations of the Mizushima Rinkai Railway
Kitayama Rail Pages: Mizushima Rinkai Railway
Sangi Railway 1931 West of Nagoya Flyash, Cement and Potash
Wikipedia: Sangi Railway
Wikimedia: Sangi Railway
Hisakyu @ Japan: Photos of all stations on the Sangi Railway
Sangi Railway, Official Site
Kitayama Rail Pages: Sangi Railway
Seino Railway 1928 Tokaido Line, near Ogaki station Limestone
Wikipedia: Seino Railway
flickr - wamu8 : Limestone at Seino Railway
Information on SL 2109, which lived at Seino Railway, but now at Oigawa Railway
Fan-site: Kinshozan Line Club
Fan-site: Seino Railway
Nagoya Rinkai Tetsudo 1965 South of Nagoya Chemicals, Container and Limestone
Wikipedia: Nagoya Rinkai Railway
Kitayama Rail Pages: Nagoya Rinkai Railway
Official website, via Wayback Machine
Kazuhiko's travelog: Nagoya Rinkai Railway
Japanese Railway Society mentions Nagoya Rinkai Railway
Kinuura Rinkai Tetsudo 1975 South of Nagoya Container, Limestone and Potash
Wikipedia: Kinuura Rinkai Railway
Tekkadon unofficial fan-site
Chita Rail Gallery - unofficial fan-site

So, after discovering all these railways, I scoured the internet for timetables... this was always going to be impossible. I then stumbled across the Railfreight Association of Japan who actually collate freight timetables and produce a single annual freight timetable of Japan. After getting a Japanese friend to talk to them, it was discovered that they did not like the idea of posting their products internationally! Fortunately my friend found a copy at Shosen Book Store in Akihabara. They sent it immediately and it arrived within 4 business days.

Note that there seems to be a monthly newsletter on their site... I haven't been able to check it out yet!

The title of the timetable is "2010 JR Kamotsu Jikokuhyou" ("2010 JR Freight Timetable", "貨物 時刻表", "かもつ じこくひょう") and it's valid from March 2010. It contains a thorough coverage of freight operations in Japan, starting with a Map of the country, a breakdown of services, a listing of locomotives (and the depots they belong to), a description of the types of freight, station diagrams and a lot more. The best part of this timetable is that they cover all of the private railways still operating and provide intricate timing details.

The sorting of the trains for each of the railways is a little confusing, and so I have reproduced the times of the railways above for my own benefit; but hopefully for that of others too. You'll find the timetables on my
Japan Freight Railway Timetables
page.

The Daytrip

Since I now had an idea of what to see, I created a plan to visit all of these railways in one day. The only exception was the Mizushima Rinkai Railway as it is in the opposite direction from Osaka to all the others.
After a little bit of creative planning on Hyperdia (clockwise vs. counter-clockwise was a big decision) I decided on the following plan:

Depart Arrive Movements
Noda(JR)
Osaka
Shinosaka
Maibara
Ogaki
0535
0546
0608
0706
0743
Osaka
Shinosaka
Maibara
Ogaki
Minoakasaka
0539
0550
0643
0741
0749
0833-0914 Limestone (#1022/#5780)
Minoakasaka
Ogaki
Nagoya
Meitetsu Nagoya
Jingumae
0931
0941
1013
1018
1029
Ogaki
Nagoya
Meitetsu Nagoya
Jingumae
Oe(Aichi)
0938
1013
1017
1024
1035
All below travel through Higashiko Freight Station.
This will involve loitering between Oe and Higashiko.
1034 Container (#307)
1050 No Idea (#6)
1130 Limestone (#7)
1134 Container (#308)
1140 Container (#8)
1143 Limestone (#321)
1210 No Idea (#9)
Oe(Aichi)
Jingumae
Meitetsu Nagoya
Kintetsu Nagoya
1217
1221
1228
1241
Jingumae
Meitetsu Nagoya
Kintetsu Nagoya
Kintetsu Tomida
1221
1228
1232
1309
1314 Tanker (#3088)
1317 Other (#0502)
1347 Cement (#5364)
1352 Tanker (#5284)
1402 Cement (#3715)
1413 Cement (#3716)
1422 Tanker (#5380)
1434 Cement (#5367)
Kintetsu Tomida 1512 Hobo 1528 1554-1609 Cement (#3718)
Hobo 1604 Oyachi 1616 1621** Cement (#3718)
1630** Cement (#3717)
Walk to Tomida, watch cement shunt
Tomida
Kameyama(Mie)
Kamo(Kyoto)
Shinimamiya
1729
1838
2006
2113
Kameyama(Mie)
Kamo(Kyoto)
Shinimamiya
Noda
1804
1955
2100
2116
Find the Super Rail Cargo

As per usual, I've left myself no time to scratch my balls; but as per usual I will also rely on the ever-trustworthy JR.

This plan is currently to be executed on Monday the 13th of September; we'll see what happens.

17Aug/102

Adding LEDs to a Japanese Shop

Pictures speak louder than words, so below is a quick tutorial on how to get an off-the-shelf TomyTec Japanese Shop Building lit with LED lighting. In total, this building received 6 LEDs; lantern, side-door, top floor (x2), bottom floor (x2).

Interior Lighting + Side Door

Model Railway Model Railway Model Railway

The trickiest part of this installation was the lantern that hangs out the front. I actually sliced it in half and bored out the middle to fit an LED inside. I also trimmed down the LED with a file to get it to fit a little more easily. This was done with my pocket-knife and I stopped when I felt it grinding metal. :)

Note that I borrowed ideas from this blog and I strongly recommend you check out the work the author has done on their layout!

Front Lantern

Model Railway Model Railway Model Railway
Model Railway Model Railway

And finally, everything is wired up. You can see the huge hole I accidently drilled in the side of the shop... luckily the lantern covers it over pretty well.

Finished Product

Model Railway Model Railway Model Railway

9Aug/106

Cheap and easy Streetlights

I'd previously bulk purchased a large amount of LEDs from LED-Switch with the intent to light up my entire model railway. I'd already bought a few of the MAX7219 ICs, which control up to 64 LEDs each, and knew how to control these via the Arduino. My article on the IC and using it was here.

Anyway, streetlights were high on the agenda, as they exist in every town in Japan and, based on a very simple idea, weren't going to be too hard to make. Following are the steps involved with creating the street lights that have been visible in my prior articles.

Ingredients

  • 0.25mm Copper winding wire (or as thin as possible.)
  • 1.6mm LEDs White/Yellow (as available here)
  • Metal tubing for the main pole. (I used '3/64 x .006' brass tubing)
  • Soldering iron
  • Paint

Model Railway Model Railway Model Railway

Construction

Firstly, cut the pole to your desired length. I have to admit here that I never once measured any of the poles and just prototyped one against a reference (in this case it was a standard Greenmax building) and then made them all the same size.

Model Railway Model Railway Model Railway

Make sure you take in to account where you will bend the pole and how much extra length will be required. Use a file to smoothen out the ends so that you don't damage the winding wire when fed through.

Model Railway Model Railway Model Railway

Once you have the poles made, simply cut the leads of the LED right down and solder one end to the pole itself. Finally, if you haven't already, feed the wire through the pole and tin one end (melt it with a little bit of solder to strip away the insulation.) Once done, trim away any excess tinned lead and then solder it to the other lead of the LED.

Model Railway Model Railway Model Railway

Note that the final version there was the best I'd made. I'd trimmed the LEDs right down after folding one leg over the top and used a very small amount of solder.

Finished Product

Better night shots of the taller version in action...

Testing of streetlights

More testing

The only thing these really require now is some form of cover/compartment/housing for the bulb to live in. Currently, with a big enough blob of paint, I can get the ends to look round-ish enough to look acceptable and I'm happy with this. But any comments/suggestions for an off-the-shelf product that might have the right shape to cover the ends are welcome!

I'd also bought red, yellow and green LEDs and found that they had fit into the Greenmax Signals. I haven't gotten around to finishing them, but I will post another article once done.

Meanwhile, in my previous post, I also added both a red and blue LED to a Bachmann N-Scale Signal. I actually cut it off its usual pole/base and mounted them as shunting signals. See the pictures. I'll post a more detailed explanation along with the other signals once finished.

8Aug/106

Latest on the Model Railway

So, something that was just meant to turn into a test layout has now become one of my greatest creations... It's not much as yet, but the scenery and electronics involved is a lot more complex than I thought I would ever create and I'm really glad as to how it's coming along.

Here's a gallery of the initial track plan I intended on using and then 3 evolutions of it. The final layout is not actually listed there. You can see that it started as a single level basic loop, with options for expansion. As I realised the time required for building just this module, I decided to do away with the extension options (although things can always change) and then added a second level. This was just to be a ridge down the middle of the board, but it now has transformed into 1/4 of the overall surface area. A town has now grown on top and a nice siding for single-car vehicles.

Underneath the board is a birds-nest of wiring for all the tricks I've tried with the Arduino (see all the previous posts...) and I'll show you this in a later post.

For now, just check out the photos and I'll get back with more information as I create it. I'm currently working on street lights for the top town and also automation of the points. I've been through around 5 iterations for the control circuit for the points and damaged quite a few TomyTec FineTrack Points in the process. Not fun.

Here's a link to the whole album.

Isometric

Top-down Town taking shape Top station

Top station

Bottom station The town The town

Update: The streetlights are painted and in... I still need to work on the light end, they need some sort of cover/compartment.

Night time at the station

Top Platform Night time At night

Meanwhile, I also need to learn nighttime photography :)
More to come as I light up all of the houses; although one is already lit!

16Jun/106

Ugh… Taiwanese Components…

PLEASE be careful when you buy cheap and nasty electronic components from eBay... This is a public service announcement.

Check the photos below and tell me what's wrong:

DSC04285

DSC04294

Yes, that's right, the legs are different on both items (the Anode and Cathode are REVERSED)... they came from the same packet and I, prior to using macro on my camera, thought they were a lot more similar than they actually are. Either way, you have been warned.

This all came about whilst wiring up these sensors and receiving zero readings.... bastards....

12May/105

Multiplexing ‘Photodetectors’ to detect train occupancy.

Right, I wasn't impressed whilst using the Sharp distance detectors and so went back to the age-old method of light-detection between the sleepers. As this is N Scale, I didn't want the standard, large and bulky Light Dependent Resistors and went for these smaller 'Photodetectors' found on eBay from a Taiwanese reseller.

Single detector

These were chosen based on the fact that they have a flat lens/front and are clear. They fit nicely between sleepers of Tomix FineTrack and, since I'd already laid and ballasted my main loop, could be retrofitted by drilling up and through the base.

Track wired up Rear of detector Detectors between sleepers

Detector between sleepers

Now, since I bought these in bulk, I started going crazy and sticking them everywhere I could. The goal was to put one everywhere that would become a good trigger-point for automation. I started with all of my stabling areas and put one at the start, middle and end of the sidings. I would use the 'trigger' from these to know when to slow to an engine to 50% throttle, 25% throttle and then stop. I then also put some in the tunnel entrances, station/platforms and also where signals should probably be (around points.)

Detector installed and ballasted

Another installed detector

It started dawning on me that I would require one analog input pin on my Arduino per photodetector. This would've gotten very expensive very quickly, but then I remembered that there was a simple tutorial on multiplexing analog inputs on the Arduino Playground (based on the 4051 IC). This IC would save me a lot of time and resources: with a little more wiring it could potentially give me 64 analog inputs for a total of 6 digital pins and one analog.

Here's the basic idea of wiring up a single 4051.

Basic Multiplexer with Photodetectors

Here's how you can use multiple 4051s and reduce pin consumption:

Advanced Multiplexer with Photodetectors

Notes on the options in the above image:

  • Option 1: Take the wires in the first rectangle and wire them to one analog pin and three digital. This will give you a total of 8 detector inputs.
  • Option 2: Take the 8 analog wires and put them into analog input pins. You then also need to connect up the 3 digital pins. For all inputs you'll only ever need 3 digital pins. But for the analog pins you'll need 1 pin for each 8 inputs. (i.e. 8:1, 16:2, 24:3, 32:4, etc... there is no upper limit, as long as you have the analog inputs.)
  • Option 3: Take the single analog pin and then the 6 digital pins. This will give you a total of 64 inputs and will use more digital than analog pins.

As you can see, you can interface with a lot of analog detectors, based on what pins you have available. As you may be aware, analog inputs are more 'expensive' on the Arduino than digital outputs as there are less available.

The process to control the above circuit is to set the digital pins to the desired address and then read the analog pin(s). You then need to set the next address and read the same pin (depending on your setup.) As changing through a lot of inputs and reading can take time, you need to be careful how many detectors you end up implementing. I have no exact numbers; but reading 64 inputs can easily be done in under a second. The goal is to make sure that a train does not pass a detector before it has been read!

So we have our detectors installed and circuitry built; we could now write software to manage it all. The basic idea was to read the value, adjust the min/max of that single detector and then check if it exceeded a threshold. Since these detectors required light to function, they would be effected by the amount of ambient light in the room and therefore the code would need to be smart enough to work out what was 'covered' (i.e. vehicle blocking light) and what was 'open'.

This code was also noted in my previous post where I used the Sharp detectors. These detectors produced a lot of noise and had to be filtered so that my code wouldn't simply trigger when a high/low value broke a threshold.

Here is the basic idea for reading one detector:

 read value of detector 
 if (detector value is greater than recorded maximum) then record new maximum value
 if (detector value is lower than recorded minimum) then record new minimum value
 if (either min or max has changed)
  then update range of this detector [max - min]
  adjust threshold [max - (range*0.25)]
 end if
 if (detector value is greater than threshold) then
  report that this detector is 'active'
 else
  report that this detector is 'inactive'
 end if

Right, so the above concept uses a 25% threshold below the maximum-read-value to see if the value read from the detector is 'active'. It is also constantly updating it's valid reading range so that it can adapt to the environmental changes. The main issue with this concept is that if the environment drastically changes (lights are turned on/off, curtains opened/closed, etc...) then this code would not adapt, as it never has a chance to 'retract' the limits. Therefore the following adjustment needs to be made:

 store the last 32 values of detector in circular array
 read value of detector and push last into array, popping off the first value
 find the lowest value in the array and store as the minimum extremity
 find the highest value in the array and store as the maximum extremity
 if (either min or max has changed)
  then update range of this detector [max - min]
  calculate the average from the last 32 read values
  adjust threshold [average + (max-min*0.10)]
 end if
 if (detector value is greater than this threshold) then
  report that this detector is 'active'
 else
  report that this detector is 'inactive'
 end if

Here you can now see that we only care about the last 32 read values (instead of the max and min since the code was running.) We are also using a new threshold calculation: 10% above the average of the last 32 values. This therefore means that we will receive an active notification if the value increases 10% above the 'stable' value of which we have been observing.

Of course, we are always able to introduce new issues; the above code, if run at processor-speed will read 32 values in under a second and, dependent on environment changes, may well not be able to cope. We therefore need to only test the detector at a specific interval (your mileage (kilometre'age) may vary!) of say, 100ms. This then means that the 32 values are taken over the course of 3.2 seconds. If this doesn't suit, then you can also increase the buffer size or decrease the polling delay.

But I bet you haven't seen the main issue? If a vehicle is stationary on the detector for too long then the range will/should drop to zero and therefore the detector will always be 'active'.
Wait, that would be correct? Wouldn't it?
It would, but it would also then report active for a certain time span until the range had expanded again once the vehicle had moved on. Note this can also be simulated by a long train traversing the detector and blocking the light (even with intermittent gaps of light) for a long period of time.

To prevent this? Adjust the polling delay and the buffer size...

Another good trick for limiting environmental effects is to add lights/LEDs to your layout around the detectors to ensure they always have a good source of UV. That way, when those curtains close, the ranges of your detectors wont drop too low.

What's next... well, what do you want to do with all this new information? You need to read it, pass it to the methods we've described above to filter the data and then act on it. Since we're multiplexing, we need to first tell our 4051 IC(s) which input we want to read and then read it. The following classes operate the multiplexers and detectors:

class DetectorCollection {
	private:
		struct Detector {
			int dValues[32];
			int dMax;
			int dMin;
			int dRange;
			int dAverageValue;
			int dCurrentValue;
			int dThreshold;
			int dCurrentIndex;
			bool dFullArray;
			int dAnalogPin;
			int dBitIndex;
			bool dIsActive;
		} detectors[32];
		int numDetectors;
		int digPins[3];
	public:
        DetectorCollection(int _digPin1, int _digPin2, int _digPin3);
        bool AddDetector(int _aPin, int _bit);
        void UpdateDetector(int detector);
        void UpdateAllDetectors();
        bool IsActive(int detector);
        void DebugInformation(int detector);
        int GetCurrentValue(int detector);
};

DetectorCollection::DetectorCollection(int _digPin1, int _digPin2, int _digPin3) {
	numDetectors = 0;
	digPins[0] = _digPin1;
	digPins[1] = _digPin2;
	digPins[2] = _digPin3;
}

bool DetectorCollection::AddDetector(int _aPin, int _bit) {
	//initialise a detector. the array contains "zero'd" detectors
	//by default
	if (numDetectors < 32) {
		detectors[numDetectors].dAnalogPin = _aPin;
		detectors[numDetectors].dBitIndex = _bit;
		for (int idx = 0; idx < 32; idx++)
			detectors[numDetectors].dValues[idx] = 0;
		detectors[numDetectors].dMax = 0;
		detectors[numDetectors].dMin = 999;
		detectors[numDetectors].dRange = 0;
		detectors[numDetectors].dAverageValue = 0;
		detectors[numDetectors].dThreshold = 0;
		detectors[numDetectors].dCurrentIndex = 0;
		detectors[numDetectors].dFullArray = false;
		detectors[numDetectors].dIsActive = false;
		numDetectors++;
		return true;
	} else return false;
}

void DetectorCollection::UpdateDetector(int detector) {
	//set digital pins      
    for (int pin = 0; pin < 3; pin++)
      digitalWrite(digPins[pin], 
        ((detectors[detector].dBitIndex >> abs(pin-2)) & 0x01) == true ? HIGH : LOW);


	//read analog pin.
	detectors[detector].dCurrentValue = 
        analogRead(detectors[detector].dAnalogPin);
	detectors[detector].dValues[detectors[detector].dCurrentIndex] =
        detectors[detector].dCurrentValue;
		

	//find the lowest and highest values in the array and store as
	//the minimum and maximum extremities.
	int tempVal, newValue = 0;
	bool extremitiesChanged = false;
	for (int idx = 0; idx < 32; idx++) {
		tempVal = detectors[detector].dValues[idx];
		if (tempVal < detectors[detector].dMin || detectors[detector].dMin == 0) {
			detectors[detector].dMin = tempVal;
			extremitiesChanged = true;
		}
		if (tempVal > detectors[detector].dMax) {
			detectors[detector].dMax = tempVal;
			extremitiesChanged = true;
		}
		//used for average calculated below.
		newValue += tempVal;
	}

		//update range of this detector [max - min]
		detectors[detector].dRange =
		    detectors[detector].dMax - detectors[detector].dMin;
		if (newValue > 0) {
			if (detectors[detector].dFullArray) 
                          detectors[detector].dAverageValue = newValue / 32;
			else detectors[detector].dAverageValue = 
                          newValue / (detectors[detector].dCurrentIndex + 1);
			//adjust threshold [average + (max-min*0.10)]
			detectors[detector].dThreshold =
                          detectors[detector].dAverageValue + 
                          (detectors[detector].dRange * 0.35);
			//adjust active flag:
			detectors[detector].dIsActive = 
                          (detectors[detector].dCurrentValue > 
                           detectors[detector].dThreshold);
		}

	//finally update the next location to store the next incoming value...
	//we're using a circular buffer, so just point to the start of the
	//array instead of shifting everything along.
	detectors[detector].dCurrentIndex++;
	if (detectors[detector].dCurrentIndex >= 32) {
		detectors[detector].dCurrentIndex = 0;
		//for calculating the average, we need to know once 
                //we have a full buffer. Once it's full we will always 
                //have a full set of NUM_READINGS values, otherwise
		//we only have as many as dCurrentIndex
		detectors[detector].dFullArray = true;
	}
}

void DetectorCollection::UpdateAllDetectors() {
  for (int d = 0; d < numDetectors; d++) UpdateDetector(d); 
}

bool DetectorCollection::IsActive(int detector) {
  return detectors[detector].dIsActive;
}

int DetectorCollection::GetCurrentValue(int detector) {
  return detectors[detector].dCurrentValue;
}

void DetectorCollection::DebugInformation(int detector) {
  Serial.print("Detector: "); 
  Serial.print(detector);  
  Serial.print(", APin: ");
  Serial.print(detectors[detector].dAnalogPin);
  Serial.print(", DBit: ");
  Serial.print(detectors[detector].dBitIndex);
  Serial.print(", Min: ");
  Serial.print(detectors[detector].dMin);  
  Serial.print(", Max: ");
  Serial.print(detectors[detector].dMax);  
  Serial.print(", Range: ");
  Serial.print(detectors[detector].dRange);  
  Serial.print(", Threshold: ");
  Serial.print(detectors[detector].dThreshold);  
  Serial.print(", Average: ");
  Serial.print(detectors[detector].dAverageValue);  
  Serial.print(", Current: ");
  Serial.print(detectors[detector].dCurrentValue);  
  Serial.print(", FullArray: ");
  Serial.print(detectors[detector].dFullArray);
  Serial.print(", CurrentIndex: ");
  Serial.println(detectors[detector].dCurrentIndex);
  /*for (int idx = 0; idx < 32; idx++) {
    Serial.print("|");
    if (idx == detectors[detector].dCurrentIndex) Serial.print("*");
    Serial.print(detectors[detector].dValues[idx]);
  }
  Serial.println("|");*/
}

And now, use it in your main program. Note I've created custom characters for the Arduino Liquid Crystal library via this website.

#define multiplexerPinBitA  40
#define multiplexerPinBitB  41
#define multiplexerPinBitC  42

#define pwmPin  			2
#define dirPin1 			3
#define dirPin2 			4

#define lcdRSPin			30
#define lcdENPin			31
#define lcdD4Pin			32
#define lcdD5Pin			33
#define lcdD6Pin			34
#define lcdD7Pin			35

#include <LiquidCrystal.h>
LiquidCrystal lcd(lcdRSPin, lcdENPin, lcdD4Pin, lcdD5Pin, lcdD6Pin, lcdD7Pin);

//cool hack! create characters for the LiquidCrystal Library!
//see here: http://icontexto.com/charactercreator/
byte trainCharFrontOn[8] = 
{B11111,B10001,B10001,B11111,B10101,B11111,B01010,B11111};
byte emptyChar[8] = 
{B00000,B00000,B00000,B00000,B00000,B00000,B11111,B10101};

DetectorCollection dCol = DetectorCollection(multiplexerPinBitA, 
    multiplexerPinBitB, multiplexerPinBitC);

void setup() {
  Serial.begin(9600);
  pinMode(multiplexerPinBitA, OUTPUT);
  pinMode(multiplexerPinBitB, OUTPUT);
  pinMode(multiplexerPinBitC, OUTPUT);

  for (int d = 0; d < 24; d++) {
    //analogpin is 0, 1, 2 [so DIV 8].
    //(where 0 is detectors 1-8, 1 is 9-16 and 2 is 17-24)
    //bit is the 0-7 on that analog pin [so MOD 8].
    dCol.AddDetector(d/8, d%8);
  }

  //start a train: direction
  digitalWrite(dirPin2, HIGH);
  digitalWrite(dirPin1, LOW);
  //speed (out of 255 [where ~50 is stopped])
  analogWrite(pwmPin, 85);

  lcd.createChar(0, emptyChar);
  lcd.createChar(1, trainCharFrontOn);
  lcd.begin(16, 2);
}

void loop() {
  //output to the LCD (16x2) the status of all the detectors:
  lcd.clear();
  lcd.setCursor(0, 0);	//top left

  for (int d = 0; d < 16; d++) {
    dCol.UpdateDetector(d);
    lcd.write(dCol.IsActive(d) ? 1 : 0);
  }
  lcd.setCursor(8, 0);
  for (int d = 16; d < 25; d++) {
    dCol.UpdateDetector(d);
    lcd.write(dCol.IsActive(d) ? 1 : 0);
  }
  
  //we still have 8 characters to draw other stuff... no idea what yet though.
  delay(333);
}

And then the detectors in action. Note it was at night time and I'm surprised the result was this good!

LCD showing train location

4May/102

Properly reading values from a Sharp GP2D12

Right, my efforts to read an IR Voltage until now have been flawed. It seems that my method of just plugging analogue inputs into my Arduino and expecting a clean reading was pointless. 'Noise' is a huge factor when reading analogue inputs (let alone correct pull-up/down resistors and grounding!) and dirty power supplies + PWM generation circuits really do kill any analogue data floating around.

Before I go into the actual sensors, read the Analogue Input Pin tutorial for the Arduino and also some sample code to read range of Sharp sensor.

So, how do you sort all these noise issues this out? Capacitors!
Based on the references below... you're either to put a ~22uf Capacitor between Vcc and GND or a 4.7uf Capacitor between Vout and GND. Firstly, here's the references:

Arduino + Sharp Sensors:

Other links on the Sharp sensors:

From all this information above I tinkered further with the sensors; but then proceeded to give up. The readings were much more stable, but I simply couldn't get them to do what I wanted as their values would drop off when the distance between the vehicle and sensor was less than 10cm.

Following is the code I used. Note that it does some trickery with caching the last 20 values and averaging them... I'll explain this all further in my next post.

//LIBRARY
#define NUM_INDEXES 20
 
class DistanceDetector {
 private:
  int min_valid;
  int max_valid;
  int analogPinNumber;
  int latest_max_value;
  int latest_min_value;
  int latest_time_updated;Here is the code I used anyway
  int lastIndex;
  bool full;
  void CalcAverage();
  
 public: 
  int lastReadValues[NUM_INDEXES];
  int sensorValue;
  DistanceDetector(int _analogPinNumber);
  void UpdateDetector();
};
  
  
DistanceDetector::DistanceDetector(int _analogPinNumber) {
 min_valid = 100;
 max_valid = 600;
 lastIndex = 0;
 analogPinNumber = _analogPinNumber;
 full = false;
 for (int idx = 0; idx < NUM_INDEXES; idx++) lastReadValues[idx] = 0;
}
 
void DistanceDetector::UpdateDetector()
{
 int latest_value = analogRead(analogPinNumber);
 if (latest_value >= min_valid && latest_value <= max_valid) {
  lastReadValues[lastIndex] = latest_value;
  CalcAverage();
  lastIndex++;
  if (lastIndex > NUM_INDEXES) {
   lastIndex = 0;
   full = true;
  }
 }
}
 
void DistanceDetector::CalcAverage() {
 sensorValue = 0;
 for (int idx = 0; idx < NUM_INDEXES; idx++) sensorValue += lastReadValues[idx];
 if (sensorValue > 0) {
  if (full) {
   sensorValue /= NUM_INDEXES;
  } else {
   sensorValue /= (lastIndex+1);
  }
 }
}
 
 
//USAGE:
DistanceDetector d1(SENSOR_PIN);
 
void setup() {
 //nothing required, as the constructor takes the pin number.
}
void loop() {
 d1.UpdateDetector(); //update the sensor.
 Serial.println(d1.sensorValue); //print out the value.
}

Conclusion

I still should have bought the GP2D120! But either way, I've decided to go with standard LDR/IR optics in the track base. Sadly, I'm over attempting the distance detection. My next post will cover a less-visible method for occupancy detection in the sleepers.

24Apr/109

Kato Amtrak 13002 (Seibu E851?)

So, I was browsing eBay and saw advertised a Kato Amtrak 4+4+4 Electric Locomotive... For all I'd known Amtrak America had never had any such an engine and therefore clicked the item to investigate... In front of me appeared (what looked like) an EF81 in Amtrak livery!

Kato Amtrak 13002 Kato Amtrak 13002 Kato Amtrak 13002
Kato Amtrak 13002 Kato Amtrak 13002 Kato Amtrak 13002

It seems that, back in the day, Kato didn't want to put money in to actually designing the models for America and therefore just repainted a (very slightly) remodeled EF81. Of course, it could be an exact copy of another Japanese electric locomotive, but I haven't had the time yet to do further research.

Update:
Toni Babelony of the JNS Forum posted a message in the thread I created on this locomotive that indicated that this is much closer to a Seibu E851. Thanks for pointing this out! Here is the Kato page on the Seibu E851. You'll notice that the Seibu has port holes, and other differences, but is obviously what Kato used as a base for this Amtrak locomotive.

Kato Seibu E851 Seibu E851 in Japan Kato Seibu E851
The real E851 in Japan

Meanwhile, here are some photos I've taken of EF81s in Japan:

Nihonkai heads to Osaka Nihonkai heads to Shinosaka Ex-Nihonkai EF81
DE10 and EF81 EF81 Nihonkai at Osaka
Twilight Express EF81 104 joins (passing Thunderbird) EF81 28 running light in Umeda EF81 28 running light in Umeda_001
Nihonkai paused Hokutosei at Fukushima NihonKai pauses at ShinOsaka
The Twilight Express at Shin Osaka The Twilight Express pulls into ShinOsaka

And, of course, if this locomotive really does exist, then please comment and tell me!

7Apr/102

March in Melbourne: Oil Burners

Ok, so calling a diesel an oil-burner is a bit rich... but at least the J Class below actually does burn it.

Photos are either taken around Dynon Yards in Melbourne or somewhere between Castlemaine and Maldon in country Victoria.

Full gallery here

BL shunting steel West Melbourne Yard N class on Flyover
5x NR light-engine El Zorro on Rail Work Indian Pacific, The Ghan and The Southern Spirit lashed up
Southern Spirit Spirit and 81 Dynon Yards
81 shunting containers Steamrail back to Newport V/Line
Bee at St.Kilda J Class at Castlemaine Back to Melbourne

And then the videos of the Victorian Goldfields Railway from Castlemaine to Maldon and return.

31Mar/102

InfraRed + Arduino revisited

Ok, after failing (more-or-less miserably) with the previous attempt at IR distance detection, I went out and purchased 4 of the Sharp GP2D12 from an eBay Store and put them to work. Finally I had a detection system working, but before this I had also attempted another method using larger IR emitter/detectors that I'd bought from Dip Micro.

Attempt 1: QRD1114, and other smaller IR detectors

See the previous blog post here

Attempt 2: IR Emitter/Detector pairing

Since my previous attempt had failed, I'd decided that if the smaller emitters could not produce enough light to avoid sunlight/roomlight interference, then boosting both the emitter and detector should help. I'd accidently purchased a collection of 10x emitter/collector pairs of IR diodes and so I put these to work in the typical setup and tested them out. These were both 3mm in diameter and, depending on the resistors used, could emit a lot more light (tested via my digital camera.)




The setup was the same as per usual... mounted horizontally at the end of the tracks to ensure that the light would reflect (as much as possible) off the approaching train.

Working with IR at night-time has it's benefits. Your room is usually lit under artificial light and so the amount of IR in the 'air' is low. I therefore had some pretty good results with this setup, but of course, come daylight, everything went out the window (or in the window, as the case may be.) Since this detector was to be in the back of an engine shed, I'd thought that I could block out the windows and make a little dark room, but my detectors were still too unreliable.

This experiment was, in the end, functional, but not to the degree that I'd wanted and so I therefore opted for the off-the-shelf Sharp detector.

Note: The goal here was to use the pair at the end of the track to sense distance. It now seems that the best method will be to detect 'occupation' and I will again test this method with a series of emitter/detector pairs along the track to sense when a train is approaching.

Attempt 3: Sharp GP2D12

After being concerned about sizing and the minimum distance that these detectors would work from, I decided I'd just bite the bullet and try them out.



I ended up purchasing 4 quite cheaply on eBay and they arrived from the UK in a short amount of time. I then realised that the versions I'd bought were optimised for detection between 10cm and 70cm. This really sucks, as I'd want the range to be much closer to the detector, as 10cm is a long way for a no-detection zone. I then looked at the graphs showing the voltage compared to distance:

It turns out that this datasheet shows you the comparison of the various detectors that Sharp makes. There seems to be one detector better suited for my project, but.. as they say... hindsight is a bitch. Even worse is that Toys Downunder currently has them in stock!

Although the 'optimum' detecting distance for unit is around 10cm, the detector still gives valid voltage results right down to around 3cm. The only issue here is that the voltage difference is not always increasing! I therefore have to take the value and use it in different scenarios (i.e. when cruising, braking, stopped, etc...)

The setup was the same as usual:

So, to deal with this, I needed to work on the voltage change... in steps of around 0.25v. If you happen to implement this yourself, you'll notice straight away that the voltage returned by this unit is not constant when the vehicle is stopped or approaching... it's perpetually flitting around +-0.5v and this can be a real nightmare. Due to this I only choose to detect larger changes which means only reading the sensor if it is +-25 of the current read value.

The basic idea is to determine the deceleration of the vehicle dependent on it's distance from the wall. The final testing code is listed next. Note that this also contains my multiplexer, thottle and also an off-the-shelf LCD for which you can find tutorials here.

#define MIN_SPEED 50
#define CRAWL_SPEED 85
#define MAX_SPEED 125
 
#include <LiquidCrystal.h>
LiquidCrystal lcd(30, 31, 40, 41, 42, 43);
 
#define STROBE_PIN 50
#define INHIBIT_PIN 51
 
#define BIT1_PIN 21
#define BIT2_PIN 23
#define BIT3_PIN 25
#define BIT4_PIN 27
 
#define DIRECTION1_PIN 52
#define DIRECTION2_PIN 53
 
void initMultiplexer() {
  //set the output mode.
  pinMode(INHIBIT_PIN,OUTPUT);
  pinMode(STROBE_PIN,OUTPUT);
  pinMode(BIT1_PIN,OUTPUT);
  pinMode(BIT2_PIN,OUTPUT);
  pinMode(BIT3_PIN,OUTPUT);
  pinMode(BIT4_PIN,OUTPUT);
  pinMode(DIRECTION1_PIN,OUTPUT);
  pinMode(DIRECTION2_PIN,OUTPUT);
  //initial state
  digitalWrite(INHIBIT_PIN, HIGH); //high = off.
  digitalWrite(STROBE_PIN, LOW); //toggle low -> high -> low to set output.
  digitalWrite(BIT1_PIN, LOW);
  digitalWrite(BIT2_PIN, LOW);
  digitalWrite(BIT3_PIN, LOW);
  digitalWrite(BIT4_PIN, LOW);
}
 
void change(int out) {
  //work out bits
  Serial.print((out >> 3) & 0x01);
  if ((out >> 3) & 0x01) digitalWrite(BIT4_PIN, HIGH);
  else digitalWrite(BIT4_PIN, LOW);
  if ((out >> 2) & 0x01) digitalWrite(BIT3_PIN, HIGH);
  else digitalWrite(BIT3_PIN, LOW);
  Serial.print((out >> 2) & 0x01);
  if ((out >> 1) & 0x01) digitalWrite(BIT2_PIN, HIGH);
  else digitalWrite(BIT2_PIN, LOW);
  Serial.print((out >> 1) & 0x01);
  if ((out) & 0x01) digitalWrite(BIT1_PIN, HIGH);
  else digitalWrite(BIT1_PIN, LOW);
  Serial.println((out >> 0) & 0x01);
  //toggle strobe
  digitalWrite(STROBE_PIN, HIGH);
  delay(50);
  digitalWrite(STROBE_PIN, LOW);
}
 
void setup() {
  initMultiplexer();
  Serial.begin(9600);
  lcd.begin(16, 2);
}
 
void updateSensorValue(int& tgt, int latest)
{
   int threshold = 25;
   if ((latest < (tgt - threshold)) || (latest > (tgt + threshold))) tgt = latest;
}
 
void pulseMultiplexer() {
  //toggle inhibit to low to actually output power
  digitalWrite(INHIBIT_PIN,LOW); 
  delay(125); //25ms is long enough.
  digitalWrite(INHIBIT_PIN,HIGH); 
  delay(1500); //now delay before going to next point.
}
 
int thresholds[4] = {9999,0,9999,0};
 
int t = millis();
int oldT = millis(), dirT = oldT;
int a1;
int a2;
int spd = 0;
int dir = 0;
 
int train_status = 0;
int sensor = 0;
int point = 0;
 
void loop() {
  t = millis();
  
  if ((t - oldT) > 50) {
    updateSensorValue(a1, analogRead(0));
    updateSensorValue(a2, analogRead(1));
    
    sensor = a1;
    if (point == 1) sensor = a2;
 
    switch(train_status) {
      case 0: //accelerating
        if (spd < MIN_SPEED) spd = MIN_SPEED;
        spd += 2;
        if (spd > MAX_SPEED) {
          train_status = 1;
          spd = MAX_SPEED;
        }
        break; 
      case 1: //travelling
        break;
      case 2: //braking
        spd -= 10;
        if (spd < CRAWL_SPEED) spd = CRAWL_SPEED;
        break;
      case 3: //paused
        spd = 0;
        break; 
    }
    
    if (dir == 1) {
      if ((t - dirT > 1250) && (train_status == 0 || train_status == 1)) {
        train_status = 2;
        dirT = t;
      }
      else if ((t - dirT > 2000) && train_status == 2 && spd == CRAWL_SPEED) {
        train_status = 3;
        dirT = t;        
      }
      else if ((t - dirT > 500) && train_status == 3)
      {
        train_status = 0;
        dir = !dir;
        dirT = t;
        //switch point
        change(3);
        if (point == 0) {
          digitalWrite(DIRECTION1_PIN, HIGH);
          digitalWrite(DIRECTION2_PIN, LOW);
          Serial.println(0);
        } else if (point == 1) {
          digitalWrite(DIRECTION1_PIN, LOW);
          digitalWrite(DIRECTION2_PIN, HIGH);      
          Serial.println(1);
        }
        pulseMultiplexer();
        point = !point;
      }
    } 
    else if (dir == 0) 
    {    
      //we should be checking which point we're about to hit first?
      /*if (a1 > 400 && dir == 0) {
        spd = 0;
        dir = !dir;
        train_status = 0;
      } else if (a1 > 300 && dir == 0) spd = 70;
      else if (a1 > 200 && dir == 0) spd = 90;
      else if (a1 > 150 && dir == 0) spd = 110;
      else spd = 125;*/
      if (train_status != 3) {
        if (sensor > 400) {
          train_status = 3;
          dirT = t; 
        } else if (sensor > 300) {
          train_status = 2;
        }
      } else if (t - dirT > 500 && train_status == 3) {
        train_status = 0;
        dir = !dir;
        dirT = t;
      }
    }
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("");
    lcd.setCursor(0, 0);
    lcd.print(a1);
    lcd.setCursor(0, 1);
    lcd.print("");  
    lcd.setCursor(0, 1);
    lcd.print(a2);
 
    lcd.setCursor(5, 0);
    lcd.print(thresholds[0]);
    lcd.setCursor(7, 0);
    lcd.print(thresholds[1]);
  
    lcd.setCursor(5, 1);
    lcd.print(thresholds[2]);
    lcd.setCursor(7, 1);
    lcd.print(thresholds[3]);
  
    lcd.setCursor(11, 0);
    lcd.print(spd);
    lcd.setCursor(11, 1);
    lcd.print(dir);
    lcd.setCursor(15, 1);
    lcd.print(train_status);
 
    oldT = t;
  }
 
  if (a1 < thresholds[0]) thresholds[0] = a1;
  if (a1 > thresholds[1]) thresholds[1] = a1;
  if (a2 < thresholds[2]) thresholds[2] = a2;
  if (a2 > thresholds[3]) thresholds[3] = a2;
  
  if (dir == 0) {
    digitalWrite(3, HIGH);
    digitalWrite(4, LOW);
  } else {
    digitalWrite(4, HIGH);
    digitalWrite(3, LOW);
  }  
  
  analogWrite(2, spd);
}

From the above, we get the following action... note that the whole process here is automated (throttle, detection, point switching):

Conclusion

This sensor worked much better than the previous attempts... but it's still not the best. I think I might now just grab one of the GP2D120s (as it would simply be plug-and-play) and see what happens. Also lighting plays an affect here too, it might just be easier in the end to have a strip of LDRs to work out where the train is... but everything has it's good and bad side!

The other option will be to have a spaced strip of detectors down one side of the track and emitters on the other. This will be like your tandy/radio-shack store that beep-beeps when you trip the beam... we'll see how well it works.