Setting up Turnouts in JMRI

brendanf Jan 9, 2017

  1. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    Yeah where to start is the tricky bit.

    Perhaps it is time to work on an updated version of the Base Station code as well...

    Keep us posted..
     
    Scott Eric Catalano likes this.
  2. TwinDad

    TwinDad TrainBoard Member

    1,844
    550
    34
    Update: I've found and fixed a few bugs in the basic handling of Turnouts... should be included in 4.7.2 when that comes out (it's too late to insert changes this big into 4.7.1). I'm still looking into the strangeness that is the "Configure Sensors & Turnouts" too. I've made a cosmetic change to that, which I hope will clarify what purpose it serves... it's now (when 4.7.2 comes out) called "Configure Base Station". That should help clear up its role vs. the JMRI Turnout/Sensor tables.

    As for making it work, well, I have much more work to do.

    But at least the bug with the turnout auto-flipping itself back to Thrown is fixed, as well as the problems with checking the "Invert" box in the JMRI Turnouts table.

    I've also written two new Help pages to clarify how to configure Sensors, Turnouts and Outputs. Not sure how soon those will show up on the site...
     
  3. TwinDad

    TwinDad TrainBoard Member

    1,844
    550
    34
    I would LOVE it if someone would fix Base Station so that it handles allocation and management of the Registers by itself, instead of having the client/throttle/JMRI know which Register number to use. Or at least a mechanism for requesting a Register number. I had to write a whole management tool within JMRI to handle that, and JMRI has no idea what other throttles/etc. might be grabbing Registers out from under it.
     
    Scott Eric Catalano and sboyer2 like this.
  4. Atani

    Atani TrainBoard Member

    1,337
    1,047
    28
    I was hoping to have something similar and if you add an ER on github I can submit a pull req for it. We can then allocate/release "registers" in a similar manner to other systems.
     
    Scott Eric Catalano and sboyer2 like this.
  5. TwinDad

    TwinDad TrainBoard Member

    1,844
    550
    34
    OK, I'm looking at the programming messaging/replies. I'm not handling them right at all. Shouldn't be hard to fix, but will take a bit of time. I'll try to gt this done before 4.7.1 is cut, but no guarantees...

    ETA: I think the brokenness is mainly if not entirely in the Monitor window, not the functioning code. Still, it should work.
     
    Scott Eric Catalano likes this.
  6. KC Smith

    KC Smith TrainBoard Member

    102
    102
    10
    Mark

    Did you get a chance to look at (haba) Harald Barth's work on registers in his BaseStation-20160907.tar file where he edited the code to increase max registers and enhances packet register memory management?

    haba said:
    I tinkered a bit with the code. Made some parts which are not essential for me to only compile conditional (#define EESTORE #define NOSHOWCONFIG). Then I reduced the RAM footprint of the refresh register by 5 bytes per register. So now with more than 500 bytes free, I could set MAX_MAIN_REGISTERS to approx 40 on the UNO. That will give me the possibility to refresh functions well in the future. The speedTable and regMap will probably be the next "big" data structures that will have to go in the slimming process. A snapshot is at

    http://www.stacken.kth.se/~haba/slamra/dcc/dcc++/BaseStation-20160907.tar.gz

    Forgive me that I'm not doing the GIT dance yet, but if this is of interest, I could convert this to separate pull requests and so on.
    Harald.

    I'm hopeful that his work in DCCPP_Uno.h, PacketResisters.ccp & .h and his addition of MemoryFree.ccp & Memory.h files may help you in this area.

    It is a linux compressed DCCpp_Uno folder and can be extracted with 7zip.
    Regards,
    Kevin
     
    Last edited: Feb 25, 2017
    Scott Eric Catalano and sboyer2 like this.
  7. TwinDad

    TwinDad TrainBoard Member

    1,844
    550
    34
    I will look at that once I take care of some of the other "irons in the fire" I have. JMRI/DCC++ being tops at the moment
     
  8. Deltic

    Deltic New Member

    4
    6
    5
    Hi Brendanf - I have been studying your set up for controlling servos and I am very impressed. I am following you lead with a mega for the main DCC++ controller connected to an UNO R3 for servo operation. My lack of knowledge on the coding side leads me to ask for help.

    I have connected a PCA9685 16channel 12-bit PWM driver to the UNO R3:
    • +5v -> VCC (this is power for the BREAKOUT only, NOT the servo power!)
    • GND -> GND
    • SDA -> SDA
    • SCL -> SCL
    • external 5v power to v+ / GND
    see https://learn.adafruit.com/16-channel-pwm-servo-driver/hooking-it-up

    I have uploaded the sketch TurnoutController2.2 to the UNO. Next I have tried to update the DCCpp_Uno, looking at the quoted text, I am struggling to understand the changes required. Are the alterations I have marked below within SerialCommand.cpp from the correct section/are these all that needs to be changed?;

    /***** CREATE/EDIT/REMOVE/SHOW & OPERATE A TURN-OUT ****/
    case 'T': // <T ID THROW>
    /*
    * <T ID THROW>: sets turnout ID to either the "thrown" or "unthrown" position
    *
    * ID: the numeric ID (0-32767) of the turnout to control
    * THROW: 0 (unthrown) or 1 (thrown)
    *
    * returns: <H ID THROW> or <X> if turnout ID does not exist
    *
    * *** SEE ACCESSORIES.CPP FOR COMPLETE INFO ON THE DIFFERENT VARIATIONS OF THE "T" COMMAND
    * USED TO CREATE/EDIT/REMOVE/SHOW TURNOUT DEFINITIONS
    */
    Turnout:: parse(com+1);
    break;


    case 'a': // <a ID THROW>

    Serial1.print("<");
    Serial1.write(com+1);
    Serial1.print(">");

    break;

    One last question, how do you then set up the address, limits, speed and rotation of each servo so these can be operated from JMRI.

    Cheers
    Phil
     
    Scott Eric Catalano likes this.
  9. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    I had to re download my Turnout Controller and the Base Station code to try and remember what I did LOL.

    Anyway so you are pretty close. With the case 'T': do the same as you did with the case 'a' . The turnout controller still supports the T statements.

    Don't forget to add in the first tab under the setup() function just after Serial.flush() add in:

    Serial1.begin(115200);
    Serial1.flush();

    And also add under the loop() function right at the top of it:

    while(Serial1.available()>0)
    {
    INTERFACE.write(Serial1.read());
    }

    When wiring the MEGA to the UNO, TX from the UNO goes to the RX1 on the MEGA and the RX on the UNO to the TX1 on the MEGA. Also a wire to connect the GNDs from the UNO to the MEGA

    I will do my best to answer your other questions;

    The ADDRESS of each turnout is set using JMRI.

    If you set the MODE to Monitoring JMRI will send out a '<T [ID] [STATE]> where ID is the tunout

    1 will be the first channel (0) on the board and 16 being the last (15).

    If you set the mode to DIRECT with NoFeedback JMRI will pump out <a [ADDR] [SUBADDR] [STATE]>

    JMRI will automatically calculate the ADDR and SUBADDR based on the ID number. But basically it is the same as above. ID 1 will be channel 0 and ID 16 will be channel 15.

    You can read more about this in the source code for the Uno at the very top of the code.

    As for limits, speed, and rotation, these are not set through JMRI.

    The limits are set by adjusting

    #define SERVOMIN 150 //Minimum pulse width for 0 degrees movement
    #define SERVOMAX 400 //Maximum pulse width for 180 degrees movement

    You will have to play with a turnout manually and figure out what works for you. The reason being is that the arm/linkage of your servo adds a certain amount of sweep depending on how far from the center of the turnout your mechanical connection is.

    I never considered SPEED when writing this. It is something I can look into later when I have time (still have't bought a new PC yet!).

    For the rotation, my plan based on whether it is a LEFT or RIGHT turnout was just to put the arm physically 180 degrees out of rotation. So if your holding your servo narrow straight up and down, the pivot arm (depending on which type you have) can be straight up for righthands and straight down for left hands provided the servo is always mounted consistently on one side of the turnouts. So for example always keep it on the right even if it is a left hand turnout, you'd just have to put the linkage 180 out. I hope that makes sense. A diagram would make it easier I'm sure.

    Also be sure to configure these other lines to match your setup.

    #define ARRAYSIZE 4 //Size of the array for the turnoutstatus array -(#Turnouts/8 rounded UP). Be sure to adjust this to your needs too. So if your only running 1 board set it to 2.

    #define num_servo_boards 2 //How many 16 channel servo boards do we have. Each board controls 16 turnouts, so divide how many turnouts you have by 16 and round UP to the next whole number. I have 70 turnouts, so 70 / 16 = 4.375 so round up to 5. I have 2 there for my testing purposes. So if your only running 1 board change this to a 1

    uint8_t SERVOADDRS[num_servo_boards]={0x40, 0x41}; //Set your addresses for the servo boards. The default is 0x40 if your only using 1 board.
     
    Scott Eric Catalano and Deltic like this.
  10. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    I forgot to mention one other thing, if you have MORE that 16 servos and need another board like me, the numbering for the servos just continues, so turnout ID#17 would be Channel 0 on the second address in uint8_t SERVOADDRS[num_servo_boards]={0x40, 0x41} and it would just continue up from there.

    If you have any other questions don't hesitate to ask.

    One more thing, after you have uploaded the sketch to the UNO you can launch the serial monitor and just type in your own correctly formated commands like <1 1> (ID#1 THROW) for testing purposes. You'll most likely have to do this anyway to setup the correct limits for your particular layout.
     
    Scott Eric Catalano and Deltic like this.
  11. Deltic

    Deltic New Member

    4
    6
    5
    I wanted to share the success / progress of using PCA9685 16channel 12-bit PWM driver to allow multiple servos to be operated. The set up is idea for layout with lots of turnouts to operate. It is possible to link up to 62 PCA9685 boards to control up to 992 servos - all with the same 2 pins from the mega! What I like about this system, is that the PCA9685 boards can be positioned close to the turnouts around the layout to keep the wiring to the minimum.


    DCC++servos_bb.jpg The DCC++ sketch must be modified as per brendanf post above and the sketch for the UNO uploaded. JMRI is being used to send the commands to operate the servos from the turnout table, next task is to generate a panel for a graphical interface.

    What I would like to explore is whether it is possible to also drive LED signals from the same PCA9685 boards. I have seen info on line that suggests that LEDs can be controlled by the PWM and GND outputs on the PCA9685 boards as shown on the above diagram. Before I head of and reinvent something that has already been done, is this a sensible way of operating LEDs for signals?

    Cheers
    Phil
     
  12. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    Considering the PCA9685 was originally intended for LEDs I think it is a good idea.

    You'd have to do more of the same modifications to the Base station code to intercept output commands and either direct them to the Uno and likewise add code to the Uno to process them. There would have to be some extra tweaks to the Uno code so it can tell the difference between a turnout command and an output. The 'T' and 'a' get chopped off and not sent to it.

    Shouldn't be too hard to update.
     
    Scott Eric Catalano and Deltic like this.
  13. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    You know you've really got me thinking about your idea, but with a twist.

    There is another way and it is a bit cheaper and involves a little know-how.

    Most Atmel AVR processors (what is used for the Arduino lines) support I2C. And it is easy to get ones with a lot more IO for only a few dollars. It would be very easy to program one to do exactly this. Just listen for commands on the bus and turn on the associated output.
     
    Scott Eric Catalano and Deltic like this.
  14. Alexander Kaaling

    Alexander Kaaling New Member

    2
    3
    1
    I´m trying to get my cobalt IP turnout motors to run with dcc++ and Jmri. I can add them to panel pros Tools/Tables/turnout but when I operate them I get "inconsistent" as state. Then if I try to operate them in Decoder pros turnout control, nothing happens and I got get any dcc traffic either.
    Ivé been trying a bit with Rocrail and while the loco runs nice there too, I get the same result, nothing happens with the switches.
    That makes me suspect that theres something in dcc++, I suppose something with the feedback?
    wIt doesn't help in what way I set the feedback, as direct or delayed , the turnouts still show inconsistent, till I click them one more time.
     
    Scott Eric Catalano and RCMan like this.
  15. Alexander Kaaling

    Alexander Kaaling New Member

    2
    3
    1
    Ok, I´m back after a couple of weeks of steep learning curve. So far I managed to download the right version of the software that Twindad developed, took me sometime to figure how the forks worked but now I´m on it. I´ve come to realize that dcc++ sees my cobalt tips as accessories and if I want o close and then throw it:
    [TX: a 0 0 1] Accessory Decoder Cmd:
    Address: 0
    Subaddr: 0
    State: ON
    [TX: a 0 0 0] Accessory Decoder Cmd:
    Address: 0
    Subaddr: 0
    State: OFF
    If I try to add an turnout with <T 0 0 0> for example it gets added but I can't throw it with <T0 Throw>, so I´m wondering if anyone else has had the same observations or if its the Cobalts acting up?
     
    Scott Eric Catalano likes this.
  16. RCMan

    RCMan TrainBoard Member

    256
    112
    10
    I just put this on the JMRI site as a problem.

    Seems the first four turnouts are numbered Address 0 sub-address 0-3, the next four are Address 1 sub-address 0-3, etc.

    So if your turnout is programmed as #1 then setup JMRI as turnout #4 (DCC++ 1,0,x), if you have a turnout as #4 then in JMRI it will be #8 (DCC++ 1,3,x), turnout #5 will be JMRI #9 (DCC++ 2,0,x) x= 0 or 1 which is the on/off command sent to the turnout.

    So for now you need to start at turnout 4 and go up from there.

    Turn on the DCC++ monitor in JMRI and you will see the commands being sent.

    Hope that helps
     
    Scott Eric Catalano likes this.
  17. Shdwdrgn

    Shdwdrgn TrainBoard Member

    250
    182
    11
    Sorry to resurrect an old thread but I've been searching for a solution to using a PCA9685 with an arduino pro micro board as a stand-alone device reading the DCC commands through the rails. The TurnoutController sketch above is the first thing I've been able to find that actually uses this servo board rather than attempting to direct-drive all the servos from the arduino, but it appears to rely on a second arduino just to receive the commands and pipe them out to the Uno through the serial port.

    So my first question is whether anyone knows of a similar project that works with the PCA9685 but just uses a single arduino and the standard optical isolator setup to manage the whole task? I've been digging through Google for the past two days and this is the only DCC project I've found so far that even attempts to use this driver board.

    If there's not an existing project for this, could someone tell me where to find the code that was used on the Mega above? Maybe I can pull out just the portions I need for the turnouts and get something up and running. My ultimate goal is to actually use an ATtiny85 but that will require further work on the libraries and for now I'm just trying to get something functional.
     
    Scott Eric Catalano likes this.
  18. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    I used a second Arduino only because the main code is very interrupt driven and relies on accurate timing to generate the DCC signal. Greg (the original author of DCC++) attempted to use I2C to communicate with other Arduinos to create a multinode system of sorts, but the timing constraints clashed and he abandoned it. That was the only reason why I decided to use a seperate Arduino.

    There are some simple sketches and circuits online for using an Arduino as a decoder, you'd just have to combine them with the code above, and have it listen for multiple addresses to trigger the appropriate servo.

    The only reason I didn't bother doing that, was I saw no point encoding a signal only to decipher it later, which would still require a second Arduino/Atmel AVR/PIC anyway. A couple of jumper wires from my Mega to an old Uno I had laying around and a tiny bit of code to pipe it over and done.
     
    Scott Eric Catalano likes this.
  19. Shdwdrgn

    Shdwdrgn TrainBoard Member

    250
    182
    11
    Hmm thanks for the info, I hadn't thought about the timing issues. That could certainly be a real problem for trying to move this code to an ATtiny later on, but since my arduino micro has dedicated SDA/SCL pins I had just assumed there was also appropriate internal hardware to back that up.

    All right, I'll keep playing with it then. I started a new sketch using your code and loading up NmraDcc.h, I think I need to get it attached to the tracks so I can see exactly what information is returned by these routines. It would be nice if they just included a bare-minimum example, but at this point I can't tell if there's a way to return a simple string like you see on the commands reference page, or if I need to interpret some other information. That's why I was asking exactly what code you had loaded on your second arduino (the one that picks up the commands from the rails) because you obviously were getting back a simple string that you passed over the serial port to arduino that drives the servos.
     
    Scott Eric Catalano likes this.
  20. brendanf

    brendanf TrainBoard Member

    62
    54
    7
    My second Arduino isn't connected to the rails. It listens on its RX line which is connected to the TX1 of my Mega.

    As for feedback or response, that is where JMRI has/had issues. The code and UNO provide the proper response that the base code would normally pass along, but for whatever reason JMRI ignores it. I am not sure if the latest version has that repaired or not, I haven't been testing it in a long time as I have been busy with other parts of the design of my layout. My plan was to use a micro switch along with the servo that activates to confirm the movement of the switch and have that give a definitive signal to JMRI as a sensor.

    You can probably still use your ATTiny (depending on the periphials) for the I2C. I wouldn't count on using it for generating the DCC signals too.
     
    Scott Eric Catalano likes this.

Share This Page