Troubleshooting help.

Massey Jun 25, 2020

  1. Massey

    Massey TrainBoard Member

    297
    436
    9
    Good morning everyone... or evening... or afternoon... eh, you get the idea.


    So I have been working on an automated tram set up. It is pretty simple really just a Kato Unitram that will go around a loop of track making 2 stops, over and over again until I power off the unit. I have had nothing but trouble with this thing from almost the beginning. My original plan was to use an Arduino Nano (I have/had generic FTDI units) with a LN298 motor control that would power the tracks. The stations would use IR sensors to halt the tram and a random stop time of 2 to 6 seconds would allow for "passengers" to load and unload from the tram. Sounds simple, I know it isn't hard but coding is my weakness. I can read code well enough to usually adapt something to my needs but I am not very good at writing the code from scratch. I do have some coding background from back in the 80's with Apple BASIC, to my time in the Navy with ATLAS. I only know the basics of "C".


    I started with this project on the Arduino forums and got some help, but no one there to help debug my code. One guy tired but when I loaded his code and ran it on my setup it didn't work what so ever.


    So my main issues I have with my setup is the #2 stop would not always stop when it was supposed to. Usually the tram would roll past the station then stop, next time around stop even further away and so on 3 or 4 laps until it somehow resets and I get 1 stop where it is supposed to, the next a bit further away and then rinse and repeat.


    I got no help with this flaw, but on my own I added a “phantom” stop in the code that was basically a 3rd stop that didn’t have a sensor with it. This seemed to cure the stop #2 issue but I don’t feel right about how it was done. I may eventually want to build a larger tram setup with multiple trams and multiple stops, all automated, this is just a stepping stone to that end.


    My last major issue with this was my Nanos. I did most of this work on a breadboard setup and it worked great. I decided to make it permanent and soldered my Nano to a board, with headers and get it ready to have a life as a tram controller. After this I made a change to the software and when I went to load it to the Nano the Nano was tanked. Windows would not recognize it nor would my Apple. So the next time I ran this route I soldered a socket to the board then plugged in the Nano. Software already loaded and it worked well for a few hours. Then I again made a change to the software and when I went to upload it… again not recognized, and after I tried to connect to the computer what I had wouldn’t even work right any more. During all of this I was testing the new software on an authentic Uno with no issues. At the end of the day I now have 5 Nanos that will not talk to a computer any more (yes I tried reloading the bootloader through the 6 pin header… no joy).


    Now I have a working unit with my Uno but I am still not comfortable with my code. If I were to post my code and setup here would someone be able to evaluate it and help me make things better?

    Thank you all in advance.

    Also I am thinking of upgrading this system eventually with some of the Sparkfun robot units but for now this is what I have.
     
  2. Massey

    Massey TrainBoard Member

    297
    436
    9
    Ok since I have the drawing of the setup in my pad and the software on my laptop I will be splitting this up. So here is my setup.

    861062E5-AAEF-4D93-AE44-1AE7026EAB96.png
     
  3. Massey

    Massey TrainBoard Member

    297
    436
    9
    OK here I am on my laptop. This is the version currently running on my setup. It has provisions for a serial monitor so I can monitor what the sensors see and how the Arduino reacts. Every now and then there will be a phantom stop 3 that pops up but not very often, maybe once every couple of hours. This version takes a lap or 3 to stabilize then seems to run fine for hours on end. I have checked voltages into the H-Bridge and also going into the Uno and all is stable. The Unitram barely draws .1 amps when running at full speed. If anyone out there with more Arduino experience than I have wants to help I would appreciate it. Also if you want to use this code for anything feel free.

    // this constant won't change:
    int ena = 3; //Tram Speed
    int mr1 = 4; //motor a = +
    int mr2 = 5; //motor a = -
    int se1 = 7; //IR #1
    int se2 = 8; //IR #2
    int se3 = 6; //IR #3

    // Variables will change:
    int se1State = 1; // current state of sensor 1
    int se1LastState = 1; // previous state of sensor 1
    int se2State = 1; // current state of sensor 2
    int se2LastState = 1; // previous state of sensor 2
    int se3State = 1; // current state of sensor 3
    int se3LastState = 1; // previous state of sensor 3


    void setup() {

    pinMode(mr1, OUTPUT);
    pinMode(mr2, OUTPUT);
    pinMode(ena, OUTPUT);
    pinMode(se1, INPUT);
    pinMode(se2, INPUT);
    pinMode(se3, INPUT);

    analogWrite(ena, 80);
    delay(200);

    // initialize serial communication:
    Serial.begin(9600);
    }


    void loop() {
    // read Sensor 1:
    se1State = digitalRead(se1);
    // read Sensor 2
    se2State = digitalRead(se2);
    // read Sensor 3
    se3State = digitalRead(se3);
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    // compare the se1State to its previous state
    if (se1State != se1LastState)
    {
    Serial.print("Stop #1 = ");
    Serial.print(se1State);
    Serial.print (" @ ");
    Serial.println(millis());

    if (se1State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }
    if (se2State != se2LastState)
    {
    Serial.print("Stop #2 = ");
    Serial.print(se2State);
    Serial.print (" @ ");
    Serial.println(millis());

    if (se2State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }
    if (se3State != se3LastState)
    {
    Serial.print("Why Did I Stop Here = ");
    Serial.print(se3State);
    Serial.print (" @ ");
    Serial.println(millis());

    if (se3State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }
    // save the current state as the last state, for next time through the loop
    se1LastState = se1State;
    se2LastState = se2State;
    se3LastState = se3State;
    }
     
  4. Massey

    Massey TrainBoard Member

    297
    436
    9
    Nobody?

    With the people here that are more savvy with Arduino code than I am, its hard to believe that no one has said anything here.
     
  5. CSX Robert

    CSX Robert TrainBoard Member

    954
    22
    21
    I'll take a look at this this evening and see if I come up with anything. In the mean time, are the IR sensor shield an H-Bridge commercial products or circuits you built? Can you post a circuit diagram for them?
     
  6. Massey

    Massey TrainBoard Member

    297
    436
    9
    Thank you for taking the time to assist me with this.

    They are both commercial products. Here are images of the units I am using. They both seem to be working good. It looks to me like the issue is with the code, granted I'm no expert. When I didn't have the "Phantom stop" in place the only thing I could see as to why stop #1 went perfectly every time and #2 didn't was there was code for a stop after #1 and not after #2. This is why I added the phantom stop, it seemed to solve most of the issues but I get the feeling there is something I am missing and the phantom stop was a poor solution to the problem.

    I will eventually want to make this system more complex with more stops 2 or more trams and a "home" button that will cause the tram(s) to return to a home station and start the whole process over, also an emergency stop feature. I am not adding these to this layout as it's only one tram on a loop and I would not have to worry much about collisions and other trains/trams.




    IR Sensor.jpg H-Bridge.jpg
     
    Last edited: Jun 29, 2020
  7. Massey

    Massey TrainBoard Member

    297
    436
    9
    And if it helps here is the version without the "Phantom" stop that was the really buggy version. Also just a note about the code that also seemed off to me. The lines:

    analogWrite(ena, 80);
    delay(200);

    Without that delay the tram would not move at all. It would jerk and the lights would flicker like it was pulsing on and off really fast. I put the delay in to slow the program down just a bit as it appeared to be going too fast. It has worked and the tram will now run. I believe I got the idea for that from the Arduino forums from another user that was having issues with his H-Bridge when running it in analog mode like I am.


    // this constant won't change:
    int ena = 3; //Tram Speed
    int mr1 = 4; //motor a = +
    int mr2 = 5; //motor a = -
    int se1 = 7; //IR #1
    int se2 = 8; //IR #2


    // Variables will change:
    int se1State = 1; // current state of sensor 1
    int se1LastState = 1; // previous state of sensor 1
    int se2State = 1; // current state of sensor 2
    int se2LastState = 1; // previous state of sensor 2


    void setup() {

    pinMode(mr1, OUTPUT);
    pinMode(mr2, OUTPUT);
    pinMode(ena, OUTPUT);
    pinMode(se1, INPUT);
    pinMode(se2, INPUT);


    analogWrite(ena, 80);
    delay(200);

    // initialize serial communication:
    Serial.begin(9600);
    }


    void loop() {
    // read Sensor 1:
    se1State = digitalRead(se1);
    // read Sensor 2
    se2State = digitalRead(se2);
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    // compare the se1State to its previous state
    if (se1State != se1LastState)
    {

    if (se1State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }
    if (se2State != se2LastState)
    {

    if (se2State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }

    // save the current state as the last state, for next time through the loop
    se1LastState = se1State;
    se2LastState = se2State;

    }
     
  8. CSX Robert

    CSX Robert TrainBoard Member

    954
    22
    21
    I may have I found your problem. Your stopping the tram on a 1-0 transition of the sensor and then delaying, so far good so far, but you are also delaying on the 0-1 transition. After you start the tram back up there is a period of time that you are not looking for a transition and I suspect that the tram is running past stop 2 during that time. If you move the bracket noted below for each stop, the delay will only occur after the 1-0 transition and I think it will fix your problem. You might however need to add back in a short delay after starting the tram back up to make sure it has time to completely clear the sensor to avoid any accidental extra stops.

    if (se1State != se1LastState)
    {
    Serial.print("Stop #1 = ");
    Serial.print(se1State);
    Serial.print (" @ ");
    Serial.println(millis());

    if (se1State == 1) {
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);

    } else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    } <---------- MOVE THIS BRACKET
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    delay(1000); <------------- ADD THIS DELAY TO MAKE SURE THE TRAM HAS CLEARED THE SENSOR
    } <-----------TO HERE
    }
     
  9. Massey

    Massey TrainBoard Member

    297
    436
    9
    I will try this tomorrow, tonight turned out to be pretty busy.
     
  10. Massey

    Massey TrainBoard Member

    297
    436
    9
    Were you thinking that the delay after starting the tram was to prevent it from stopping as it was clearing the sensor? If so that isn't an issue with the way the code is written here. With this code we are waiting on state changes. So once the state of a sensor changes the program will respond accordingly, in this case it will stop the tram for a random time, then start the tram again. The state of the sensor has not changed so the sensor is "ignored" until the state does change. When the state changes back to a "1" (which is un tripped) the program says to turn on the motor (which it is already doing). It isn't until a "0" is read from either sensor that the state again changes to a stop condition, then waits the random time and starts again.

    Is there a way to make one loop instead of 2 or 3? There is only going to be one tram at any given time on this setup and I really only need one condition change from either sensor to cut power. I think that if we can make this in one loop reading both sensors and stop when one or the other is tripped then delay and start again waiting for a tripped sensor that would not only simplify the code (or so I think but writing the code isnt my strong point), but it would allow for one change to effect the whole setup. Just a thought but I don't know how to make it happen.
     
  11. CSX Robert

    CSX Robert TrainBoard Member

    954
    22
    21
    That is the reason for the extra delay that I added. It may not be an issue with the trams, but with locomotives with couplers//walkways/pilots on the ends it is not unusual to get multiple transitions as the loco covers and uncovers the sensor.

    It also delays a random time again at this point, which I think is your problem. How long does it take to get from station 1 to station 2? After the program starts the tram back up, it delays for 2-6 seconds again and if it gets to the next station before the end of the delay it could miss or be late in seeing the 1-0 transition for that station.

    Definitely, I'll take a stab at it when I get a chance.
     
  12. Massey

    Massey TrainBoard Member

    297
    436
    9
    The delay should only happen after the tram stops. It takes 3 or 4 seconds between stops, both ways around they are roughly 180 degrees apart. And also when I would isolate the sensor for stop 1 and only have the tram stop at station 2 it would still act wonky. When I would isolate stop 2 so only #1 was active it all ran good.
     
  13. CSX Robert

    CSX Robert TrainBoard Member

    954
    22
    21
    I'm sure that's what you intended, but that's not what you coded. Here I joined paired brackets to hopefully make it easier to see what's happening. On a change of state the code in the blue bracket executes. If the state equals 1 then the code in the green brackets is executed and the code in the orange brackets is not. Likewise if the state is not 1 then the code in the orange brackets is executed and the code in the green brackets is not. Since the delay code is not within the either the green or orange bracket it will get executed on every state change. By moving the orange bracket like I showed in my previous post, you would move the delay into the orange brackets so that it would not get executed on a 0->1 transition.

    code loop.png

    Are you sure your sensors are responding reliably? If you have not already done so I would write a program that simply outputs the state of the sensors and watch it as I ran the tram around manually to make sure the sensors are responding as expected.
     
  14. Massey

    Massey TrainBoard Member

    297
    436
    9
    The sensors are reliable, and I have moved them between ports on the shield they all function the same.

    So if what you say is the case then why does it only happen with sensor 2 and not sensor 1, and why did adding the phantom sensor make #2 more stable? I’m not trying to argue here, please don’t think that, I’m trying to understand what is happening.
     
    Pastor John likes this.
  15. Massey

    Massey TrainBoard Member

    297
    436
    9
    Ok so I got the tram tracks mounted to the “benchwork” or module. The sensors are mounted in the rails now and I will be able to test new software.

    here are a couple of pics of the setup

    9C176A2E-E712-46D2-BFB9-D0DCD52A6C5A.jpeg 36DCF7C0-B7EC-4102-8FFC-14EFF80205D6.jpeg
     
    Jimbo20 likes this.
  16. Massey

    Massey TrainBoard Member

    297
    436
    9
    OK now that the holiday is over I should be able to get back to my trains. The Tram has actually been running flawlessly for several days. I think in the time I have been monitoring it all only once has it not stopped where it was supposed to. I'm still not happy with the code but I will try to move the brackets and see if that cures the issue without the phantom stop. Maybe tonight or tomorrow.
     
  17. Jimbo20

    Jimbo20 TrainBoard Member

    267
    174
    8
    I think your problem with missing stop 2 might be because you don't have the delay and motor start code within the else brackets. This means that the delay can still still fire even if the sensor is not equal to 0 and because the motor is already running it will over shoot the next sensor (if the delay is longer than the time taken to get to the next sensor.)

    I think if you put the delay and motor on commands within the else brackets, it will work.

    EG

    else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    }
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }

    Change to

    else {
    digitalWrite(mr1, LOW);
    digitalWrite(mr2, LOW);
    // Delay a little bit to load passengers
    delay(random(2000, 6001));
    digitalWrite(mr1, HIGH);
    digitalWrite(mr2, LOW);
    }
    }
     

Share This Page