Sign in to follow this  
Toastie

LEGO Train control using RCX1.0 PBricks

Recommended Posts

Dear All,

I have uploaded a video on YouTube showing some LEGO trains equipped with RCX PBricks running on one larger stretch of track:

Control is via IR messaging from a PC program talking/listening to the LEGO IR tower traffic. A simple ID/databyte message exchange protocol adresses individual trains on the track (or all). The track is powered with 9 ... 18V DC, as one sees fit. The PBricks are all RCX1.0, pick up power from the tracks via modified 9V trains motors and deliver power back to the motors. The RailBrick Journal Issue 3 (Page 44 and up) has some more information. The program running on the RCX and some other details are also available on the RailBricks website (see building instruction section, Diesels, GP40_RCX).

It's up to you what the trains do, just program that into the RCX. I am simple minded, so power level setting 0 ... +/-7 (compatible with the 9V speed regulator, I love compatibility), some power level ramping (internally on the RCX, which allows 25 power level settings for each direction, looks more realistic when going from 0 to 5), head light on/off, some sound generation, and PID speed control (that IS fun!) is what I came up with.

I am working on getting the NXT PBrick to be of any value here ...

Rock on,

Thorsten

Share this post


Link to post
Share on other sites

How would you use PID control on a LEGO train then?! It is kind of strange for a train to use PID, it is more suitable for robots isn't it?!

Update: after seeing the nice video, I understand what you mean, but that is not PID, it is more like the servo principal. I like the idea very much however.

Share this post


Link to post
Share on other sites

How would you use PID control on a LEGO train then?! It is kind of strange for a train to use PID, it is more suitable for robots isn't it?!

Update: after seeing the nice video, I understand what you mean, but that is not PID, it is more like the servo principal. I like the idea very much however.

Hi JopieK,

this is a good question and comment!

Well as far as I understand PID loops and servos (I may be quite wrong here!):

The 9 V train motor alone is just that: A simple DC motor. Many people call a closed-loop system that does not use a stepper motor a servo system or "servo". So a simple DC motor that is connected to any kind of velocity controller may be called a servo motor.

In this regard you are absolutely right: The combination rotation sensor + RCX + 9 V train motor (with both motor and sensor on the rails = closed loop) is representing a servo system. There are many different kinds of control loops; for servos quite often PID is implemented. So I guess you are right: The closed loop installed on my trains is representing a servo system. And this system uses the PID algorithm for control (so my statement may be right as well ...). I have programmed the PID algorithm into the RCX as one task. It just monitors the rotation sensor reading every 60 ms and then calculates the deviation form the set point (desired speed) and the other errors you need for PID to adjust the motor power output level.

I hope that this makes sense.

Regards,

Thorsten

How would you use PID control on a LEGO train then?! It is kind of strange for a train to use PID, it is more suitable for robots isn't it?!

Update: after seeing the nice video, I understand what you mean, but that is not PID, it is more like the servo principal. I like the idea very much however.

Hi JopieK,

I forgot: This is the code for the PID loop running on the RCX. Just in case. The entire program can be donwloaded on the RailBricks website, section build instructions, diesels, gp40_RCX.

Regards,

Thorsten

//---------------------------------------------------------------------------------------------------------------------
task PIDSpeedControl()
{
 /*
 PID loop. The algorithm is adapted from the eBook "The PID Control Algorithm - How it works, how to tune it, and
 how to use it" by John A. Shaw (2nd edition, 2005).

 Some data on the LEGO RCX rotoation sensor used for train speed measurement:
 - 16 ticks per 360 deg rotation.
 - 5.5 cm travel path per 360 deg rotation using the RC trainwheels = 3.4 mm per tick.
 */

 //Local constants
 const int cnSpeedCalFactor = 320;                   //Calibration factor for rotation sensor reading/time[T2] =>
                                                     //speed conversion [% scale].

 //Local variables                                   //Variables used in referenced BASIC code.
 //--------------------------------------------------//---------------------------------------------------------------
 float fActualSpeed;                                 //Input [%].
 float fActualSpeedD;                                //InputD.
 float fActualSpeedLast = 0;                         //InputLast; needs to be initialized for first PID loop.
 float fPIDError;                                    //Err.
 float fPIDFeedBack = 0;                             //Feedback; needs to be initialized for first PID loop.
 float fOutputPower;                                 //OutP.
 //PID_ROT_SENSOR_DIR                                //Action.
 //bFlagPIDSpeedControl                              //Mode.
 //not required (?)                                  //OutPutTemp.
 //nPIDSpeedSetpoint                                 //SetP.


 ClearTimer(TMR_SPEED);                              //Reset speed measurement timer 2 for initial PID loop access.
 SensorValue[ROT_SENSOR_IN_1] = 0;                   //Reset any accumulated rotation sensor ticks on log. input 1
                                                     //for initial PID loop access.


 //--- PID loop ------------------------------------------------------------------------------------------------------
 while (true)
 {
   while (time1[TMR_SPEED] < nPIDLoopWaitTime);      //Note: 0 ms loop time delay is too short to accumulate
                                                     //meaningful rotation sensor tick readings at low speeds.
   fActualSpeed = SensorValue[ROT_SENSOR_IN_1] * cnSpeedCalFactor * PID_ROT_SENSOR_DIR / time1[TMR_SPEED];
                                                     //Speed calculation.
   ClearTimer(TMR_SPEED);                            //Reset speed measurent timer.
   SensorValue[ROT_SENSOR_IN_1] = 0;                 //Reset accumulated rotation sensor data.


   if (bFlagPIDSpeedControl) //PID algorithm -------------------------------------------------------------------------
   {
     fActualSpeedD = fActualSpeed + (fActualSpeed - fActualSpeedLast) * fPIDDerivTime;
     fActualSpeedLast = fActualSpeed;                //Store current speed value.
     fPIDError = nPIDSpeedSetpoint - fActualSpeedD;  //nPIDSpeedSetpoint is calculated from nRampedPower.
     fOutputPower = (fPIDError * fPIDGain) + fPIDFeedBack;

     if (fOutputPower > 100) fOutputPower = 100;     //Restrict nOutputPower to firmware power range.
     if (fOutputPower < -100) fOutputPower = -100;

     fPIDFeedBack += (fOutputPower - fPIDFeedBack) * fPIDResetRate;

     if ((nRampedPower == 0) && (fActualSpeed == 0)){//Required to fully remove power from the motors; at low output
       fOutputPower = 0;                             //power levels the train stops with zero PID loop error but
       fPIDFeedBack = 0;                             //power is still around 20 with no torque and speed = 0.
       fActualSpeedLast = 0;
     }
   }
   else //Manual speed control ---------------------------------------------------------------------------------------
   {
     fOutputPower = nRampedPower;                    //Set output power to ramped power as calcualted in task
                                                     //ramp_power [% scale].
     fPIDFeedBack = fOutputPower;                    //Store PIDFeedback and current speed for bumpless transfer from
     fActualSpeedLast = fActualSpeed;                //manual into PID mode.
   }

   motor[OUT_1] = fOutputPower * DIR_1;              //Set motor power, recognize motor wiring direction.
#if MOTORS == 2                                       //motor[] accepts floats (rounded >down< to integers).
   motor[OUT_2] = fOutputPower * DIR_2;
#endif

 }//while (true)

}//task PID_speed_control

Share this post


Link to post
Share on other sites

hi

i tryed to make a post for building a standard RCX train controller, and your way of work is very impressive.

a second member has made train reading track information in order of making interactions, and i hope a mix should be created ;)

can you help me ?

Standard RCX Train controler

Share this post


Link to post
Share on other sites

Elicend, again please do not bump old topics without good reason. If you need help, try reaching the original poster by PM (personal messenger).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.