// LIMITATION: the first and last wheels in your train must NOT be 9v train // motor bogies. See below. // tune DARK_HIGHWATER by placing a wheel in front of the sensor and adding // about 5. LIGHT_LOWATER can be just under your no-train light reading, // but the closer you can get it to DARK_HIGHWATER (without false readings) // the faster you can run a train and still properly detect standard bogies. #define DARK_HIGHWATER 35 #define LIGHT_LOWATER 40 // connect the sensor described at: // http://www.ben.com/LEGO/rcx/train-sensor.html #define TRAIN_SENSOR SENSOR_2 // assumes the powered bogie plate is in the back #define ENGINE_FORWARD 1 #define ENGINE_REVERSE 0 // Called just after a complete engine passes (assumes 1 real motor bogie // in the front and one "fake" one in the front. Examples: // // engine from the #4564 Freight Rail Runner, MOTOR IN BACK // engine from the #4565 Freight & Crane Railway, MOTOR IN BACK // engine from the #4558 Metroliner, MOTOR IN BACK // // NOT the engine from the #3224 Classic Train or the #4561 Railway Express. // Both use only the motor bogie in the engine. To allow for only these // engines would be possible, but they could not pass the sensor first // without redesigning the detection algorithm. // void Engine(const int &dir) { // example: play a tone PlayTone(2000, 10 + dir * 10); } // Called just after any car with two fixed axles passes. Examples: // // any freight car in #4564 Freight Rail Runner // the Octan Tanker // void Boxcar() { // example: play a tone PlayTone(500, 10); } // Called just after any car with two standard bogie plates passes. Examples: // // 4557 Club Car // any freight car in #4565 Freight & Crane Railway // *maybe* the coaches from the #4558 Metroliner, but I don't know if the // descender in the middle would block the light sensor. // void Double() { // example play a tone PlayTone(1000, 10); // example: stop after first long car SetPower(OUT_A, 7); // stop hard Toggle(OUT_A); Wait(30); Off(OUT_A); StopAllTasks(); } int in_long, light, dark, axle, single; #define countlight() light = 0; until(TRAIN_SENSOR < DARK_HIGHWATER) light +=1; #define countdark() dark = 0; until(TRAIN_SENSOR > LIGHT_LOWATER) dark +=1; task main() { SetSensor(TRAIN_SENSOR, SENSOR_LIGHT); SelectDisplay(DISPLAY_SENSOR_2); // example: stop after first long car SetPower(OUT_A, 6); OnFwd(OUT_A); single = 0; while (true) { countlight(); // you might have to make this larger if you have huge // and drive them really slowly. keep it as small as // possible to ensure it is always reset by a new train. if (light > single * 10) { // new train. insist that this is a SINGLE axle, // not a motor plate countdark(); single = dark; axle = 0; continue; } else { countdark(); } // motor plates block light all the way across, not just // at the wheels if (dark > single * 3) { if (in_long == 0) { in_long = 1; // start } else { in_long = 0; Engine(ENGINE_FORWARD); } continue; } // adapt to new train speed single = (single * 2 + dark) / 3; if (axle == 1) { // axles come in pairs, either cars or bogies. // we want the distance between pairs axle = 0; continue; } else { axle = 1; } // the gap between two wheels on a normal bogie plate is // less than one wheel across. if (light < single) { if (in_long == 0) { in_long = 1; } else { in_long = 0; Double(); } } else if (light > single * 2) { Boxcar(); in_long = 0; } else { if (in_long == 0) { in_long = 1; // this is a fake power bogie } else { in_long = 0; Engine(ENGINE_REVERSE); } } } }