Locomotive Controller Conundrum

Howdy gang. Quick little background: my "day" job is that as a locomotive engineer (or engine driver if you're in other parts of the world). I've had an interest in railroads all my life, passed down from my father.

Years ago, a friend of ours had a controller unit out of a scrapped locomotive he wanted to turn into a throttle for controlling his model trains. As far as I know, he never did anything with it. Fast forward to now, and I find myself in the same position.

A locomotive throttle has a total of 10 positions, STOP, IDLE, and "Notch" or Run" 1-8. There are 6 roller switches inside of the control stand that are activated as you move the throttle around, in different combinations. The locomotive's governor responds to these switches and increases (or decreases) engine RPM's appropriately.

I figure I can hook these 6 switches up to the digital pins, setup as inputs, and have my Uno read their HIGH and LOW states, however, my concern is with the looping code that's required:

The roller switches are NOT push-buttons, so when one is closed, it would be read as LOW - so, if the Arduino keeps getting a LOW result as it goes through the loop, it'll keep sending whatever command, right? Is it possible to code the Arduino to only send a command once, for roughly quarter to half a second?

If that's not clear enough:
Engine throttles normally start in IDLE. When I advance to Run 1, I want the Arduino to send a command for 250ms, then stop commanding until the throttle position is changed again while still checking the states of the switches. I figure it will probably need an integer value to reference what position I'm in and maybe a sneaky one to have it only run the output command once? My C skills are old - I haven't messed with it much since senior year in high school (15 years ago).

I haven't worked out how I will get the Arduino to interface with my Digital Command Control system (yet) but the manufacturer of it is generally friendly to the users, so I hope they will be able to assist me, but I want to get this sorted first. One step at a time.....

I'll be happy to answer any questions that you guys may have, and thank you in advance for looking over my post.

it possible to code the Arduino to only send a command once, for roughly quarter to half a second?

Yes that sort of thing is done all the time.
It is known as a state change, you look at the state of the switch and compare it to the state you want AND the state it was last time. Just before the end of the loop you make the last time state equal to the state you just read. You use a compound if statement like this

if(currentSwitch == LOW && lastState == HIGH) {
// do stuff
}
lastState = currentSwitch;

There is a state change example in the IDE but I don't think it is a very clear one.

I think G_M means "if(currentState ==" not "if(currentSwitch ==" to match the "currentState" in the last line.

csxt6573:
I want the Arduino to send a command for 250ms, then stop commanding until the throttle position is changed again

It would be useful if you explain what sort of command you want to send and what you want to send it to.

An understanding of the overall project helps us to give better advice.

For example, if the command is just something like digitalWrite() or analogWrite() it would not really matter if it was repeated.

If you need to manage the timing of things (for example to have something happen for 250msecs) have a look at how millis() is used in Several Things at a Time

If you are short of Arduino I/O pins you could, perhaps, wire the control switches to a resistor ladder and read the value with analogRead() on a single pin.

...R

JimboZA:
I think G_M means "if(currentState ==" not "if(currentSwitch ==" to match the "currentState" in the last line.

Thanks - now corrected.
It is what comes of writing code at 5:00 in e morning. :slight_smile:

G_M and Jimbo - thanks. My C skills are a bit rusty, but I am sure I can hammer it out.

Robin2: The command I want to send is basically that of a push-button keypress. The DCC system's controllers have potentiometers and buttons that allow you to increase or decrease the speed of your train, and this is what i want the levers to replicate. If the software keeps sending the keypress over and over (like in a simple if loop), I feel like that will cause the train to "run away" simply by being in Run 1...and that would be bad :slight_smile: Probably not so much of an issue with the state change implementation.

Thanks again for your time!

The state change idea will take care of emulating the key press yep. You can leave the lever parked in any position for the whole journey, but it will only "do" one press. Then when you move on to the next detent it will activate there once only.

(Can also do the 250ms thing if you really need to, there's mechanisms for that. So if the switch has just "gone low" using G_M's method, start a timer, start doing the thing, and each time through the program's loop check to see if 250ms has gone by. If not, keep on doing the thing. If it has, stop doing the thing.)

csxt6573:
G_M and Jimbo - thanks. My C skills are a bit rusty, but I am sure I can hammer it out.

Robin2: The command I want to send is basically that of a push-button keypress. The DCC system's controllers have potentiometers and buttons that allow you to increase or decrease the speed of your train, and this is what i want the levers to replicate. If the software keeps sending the keypress over and over (like in a simple if loop), I feel like that will cause the train to "run away" simply by being in Run 1...and that would be bad :slight_smile: Probably not so much of an issue with the state change implementation.

Thanks again for your time!

Ideally, you should implement some form of 'absolute' control with the DCC pots, or implement some form of 'closed-loop' feedback, so the Arduino knows the DCC is at the same setting as your control panel.
Anything less, and you can easily get into situations where the locos are 'out of control' until you reset the whole system to synchronise the panel and DCC controller.

And then there are people who think that last post is totally unnecessary and that in the majority of cases open loop control is fine. Your case being one of them.

Grumpy_Mike:
And then there are people who think that last post is totally unnecessary and that in the majority of cases open loop control is fine. Your case being one of them.

Hey grumpy_mike, I see that our friendship is growing nicely.
Open loop is never preferable to closed-loop control, except during development, or where you really 'don't care' if the system works reliably.

csxt6573:
The DCC system's controllers have potentiometers and buttons that allow you to increase or decrease the speed of your train, and this is what i want the levers to replicate.

Can your DCC system take an XPressnet input (or equivalent). The Arduino could generate Xpressnet messages. I think this would be more effective than getting an Arduino to provide "physical" inputs to the DCC hardware.

You can also generate DCC signals with an Arduino so that no other controller is required.

...R

DCC packet format

The major fault of this system is that it does not provide closed-loop control. This prevents the development of several desirable features:

  • Command acknowledgement.
  • Location feedback.
  • Motor load (for modifying sound on grades)
  • MU performance matching.

Getting rid the the rheostat control would be great. I'd replace your switches with a single rotary switch to emulate the throttle lever in early locomotives.
Adding an "air" rotary switch would be great for controlled breaking.

lastchancename:
Hey grumpy_mike, I see that our friendship is growing nicely.

Yes I always have trouble with people who think they know a lot more than they actual do. Not technically wrong, but hopelessly impractical seems to sum up a lot of your advice.

Open loop is never preferable to closed-loop control,

I never said it was. I also dislike people who deliberately distort what others say in order to make themselves look good.

What I said was

in the majority of cases open loop control is fine.

There is a price to pay for a closed loop system as well as all the well known advantages it gives, and sometimes that price is not worth paying. That is a judgment call which you might learn to make if you stick at this game for long enough.

boolrules:
DCC packet format
The major fault of this system is that it does not provide closed-loop control.

See the designers of that system disagreed with you as well. They made the call and came to their own decision.

The majority of people who give advice here do so honestly and in a spirit of wanting to help. However, we get the occasional know it all who lets down the standards here. You are just the latest in this tradition. If past performance of this personality type is anything to go by you will be gone in six months and we will have another vacancy for village idiot.

I'm not sure why this seems to have become personal - both parties could usefully take a cold shower.

I wrote a Ruby program to generate Xpressnet commands for a Hornby Elite DCC system from input from a browser and it worked very well without any need for feedback. I just trusted that if I sent a command it would be acted on - and it was.

...R

You are probably more interested in this rather that the link I gave earlier.

There are some DCC command stations that will accept serial input. That could simplify the interface between the Arduino and the track command system.