Setting up Turnouts in JMRI

brendanf Jan 9, 2017

  1. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Hello all,

    I have some questions about setting up turnouts in JMRI with DCC++

    I am using servos for mine, I am also using the Adafruit 16 channel PWM board to control them.

    I have successfully written code that handles multiple Adafruit boards (I have over 60 turnouts on my layout), and I am using a seperate Arduino Uno as my I2C master.

    I use a Mega for my base station and just pass any turnout commands to the Serial1 port which drives the serial port on the Uno, any responses work their way back the same way.

    Anyway my questions are what is the order for setting up turnouts in JMRI?

    I see if I go under DCC++ >> Configure Sensors & Turnouts and then select Turnouts, there is an index, an address, and a sub address.

    I also have gone to Tables >> Turnouts and created turnouts there.

    My issue lays mainly with the 'FEEDBACK' settings. What is the difference.. By monitoring the packet stream it seems one is for DCC enabled turnouts.

    I just need JMRI to send out <T # 1/0> where # is the turnout number and 1 for throw it or a 0 to close it.

    I have seen this in the packet monitor, I've also seen it send <Z # 1/0> but JMRI doesn't seem to like the responses it is getting back which are formatted correctly. So when I click on the turnout to close it, it sends the command, gets a response that confirms it was closed, but the button for throwing/closing quickly will show CLOSED, then go back to THROWN.

    Any tips? Also if anyone is interested in the code I wrote for controlling the servos let me know. I'll be happy to share.
     
    Scott Eric Catalano likes this.
  2. Scott Eric Catalano

    Scott Eric Catalano TrainBoard Member

    205
    57
    6
    TwinDad was working on implementing DCC++ into JMRI he did so on a limited basis. See if you can contact him and he maybe able to help you out.
     
  3. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Yeah I PM'd him already, still waiting to hear back

    If I can't solve it, I'll have to generate some feedback for this, which most likely I'd have to do anyway for the track signals.
     
    Scott Eric Catalano likes this.
  4. Atani

    Atani TrainBoard Member

    1,466
    1,736
    37
    have you tried setting the feedback mode to direct? I haven't used jmri for turnouts (yet!) but I believe that was the mode that was used previously to make jmri happy with a dcc++ base station. More details on turnout feedback settings can be found here: http://jmri.org/help/en/html/doc/Technical/TurnoutFeedback.shtml
     
    Scott Eric Catalano likes this.
  5. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Yeah I tried that too. Direct feedback changes the way it addresses the turnout. It creates a DCC packet.

    It's a weird thing. I'm sure I'll get it licked eventually.
     
    Scott Eric Catalano likes this.
  6. Atani

    Atani TrainBoard Member

    1,466
    1,736
    37
    Very odd. I will do some tinkering this morning with jmri and dcc++ and see if I can find anything else. I will also dig through the code if I can.
     
    Scott Eric Catalano likes this.
  7. Atani

    Atani TrainBoard Member

    1,466
    1,736
    37
    Ok, Using JMRI 4.6-R81496dc (latest released version) it looks like it only supports DCC decoders for turnout control, everything is treated as an accessory. It does not appear that DCC++'s support for <T [ID] [STATE]> is implemented. There also seems to be a bit of confusion of how DCC++ turnouts are supposed to be implemented in JMRI: https://github.com/JMRI/JMRI/issues/2641

    What I was able to verify is that JMRI will send <a [addr] [subaddr] [state]> packets when throwing/closing a turnout via the JMRI UI. I couldn't find an easy way to have JMRI send <T [ID] [STATE]> from the UI other than packet injection. Additionally, once you define a turnout via UI it doesn't seem to allow you to clear it (other than packet inject <e> which is bad).
     
    Scott Eric Catalano likes this.
  8. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Yeah I can get it to send the <T [ID] [STATE] if you set the MODE to monitoring, and watch the DCC++ Traffic Monitor, it will send the command as needed. The issue seems to be JMRI is ignoring the response, it processes it on the packet monitor, but it won't update the buttons.

    Whats more interesting too is if you play with the automation setting for the turnout. With it set to OFF or 'USE GLOBAL DEFINITIONS' it will send the packet ONCE, but if you set it to 'NO FEEDBACK', it will send the appropriate command in this case I want it to CLOSE, so it sent the close, got the response, and then immediately, it sends a THROW command, and gets a THROWN response..

    The code you look at it, I'm guessing was the JMRI.. What is it written in? I may have to tackle this myself to correct as I don't think TwinDad is currently active. I'm guessing life is taking up most of his time.
     
    Scott Eric Catalano likes this.
  9. Atani

    Atani TrainBoard Member

    1,466
    1,736
    37
    I didn't see it doing that when I was trying it, I must have missed an option somewhere. It sounds a lot like it is not waiting long enough for DCC++ to respond.

    The NO FEEDBACK option is supposed to mean that JMRI will send the packet and assume that the device did what it told it to do. If you configure the feedback you might be able to use a single sensor to indicate the turnout position. I am not sure if this is wired up with DCC++ sensors but hopefully it is. In this case you could use a SPDT that toggles with the switch machine (servo or otherwise).

    The code is in java, I work with java quite often as part of my non-trains job. It is not the easiest to follow since it is only implementing portions of the abstract base classes: https://github.com/JMRI/JMRI/tree/master/java/src/jmri/jmrix/dccpp There are a lot of comments in the code that are like "DCC++ doesn't support this but we will keep it anyway" so it likely is just needing some limited support on the DCC++ base station side possibly.

    Just saw this, can you share what you are using today? I am working on building a few stationary decoders with servos and relays using an Arduino Pro Mini and am always interested in how others are doing similar projects. I was looking at https://sites.google.com/site/sidloweb/elektrika/16-dekoder-pro-15-serv as a basis for the decoder since it will remember the positions through a restart.
     
    Scott Eric Catalano likes this.
  10. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Yeah I was planning to try this tonight or tomorrow to add a SPDT switch and configure one of the un-used PINS for a sensor input, and then set that up as the Feedback. It is going to take some tinkering for sure.

    Sure thing. Just to give you background on my setup, I use the Mega for the BaseStation with the v1.2.1 code on it and I have a seperate Uno for driving the Adafruit 16 channel servo boards (https://www.adafruit.com/products/1411). The servo boards communicate via I2C and they have solder pads on them for setting their addresses. Quite easy to do really, and there are 62 possible combinations of addresses so you can have ALOT of servos. I decided to use the Uno, because I already had it, and I didn't want the Base Station trying to keep up with I2C since it is already so interrupt driven for generating the DCC packets. The servos are pretty cheap too, the only downside really is, I won't be able to use the header pins provided, the servos come with fairly short leads, so I will have to run some small gauge 3 conductor to each one and just solder that to the Adafruit board. I just have to get some taller wire wrap headers to space the boards out some more, or I can just make jumpers for the SCA & SCL pins and a ground, and lay the baords side by side, but I worry with long wires it might introduce too much noise on the I2C bus.

    I connect the TX & RX on the Uno to the RX1 & TX1 respectively on the Mega, plus add a wire for GND.

    In the base station code, under SerialCommand.cpp, I modified the parse() function. I located the Case 'T' from the switch statement and removed everything an added this instead:

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

    break;

    This way it would just take anything that had the T command to it and pass it along via the Serial1 port (minus the T).

    I also added in the DCCpp_Uno tab (not the .h one) in the loop() function:

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


    This is to capture anything being set back by the Uno.

    Also required under the setup() function to add:

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

    That was all that was really required to get stuff to pass along.

    I think I have attached the code for the Uno correctly, if not let me know.
     

    Attached Files:

  11. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    I forgot to mention, I didn't bother with trying to remember the turnout positions. For me it didn't matter, I'd rather write some Logix to align switches how I want them, also for creating a stand alone decoder to me seem unnecessary, only because, why create a packet, only to have to try and de-crypt it.. It was easier just to use another serial port which was already available.

    It wouldn't be terribly hard to modify the code I posted to have it save the buffer to EEPROM and on startup load it and refresh the servos.

    Let me know what you think. The code is HEAVILY commented to make it easy for people to understand.
     
    Scott Eric Catalano likes this.
  12. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    So yeah I have tested the 'Sensor' idea, and it doesn't work..

    I had a chance to peruse the source code and I see what you mean about needing some cleaning up and updating. It does appear that it is a bug in the code. I have never written a single line of Java, it does appear to be a little like C.

    I may have to try sensors a different way, I really don't want to abandon the work on using the servos.
     
    Scott Eric Catalano likes this.
  13. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Actually I'll change the BaseStation code.. It will be easier to move the code that sends stuff out Serial1 to the 'a' switch case statement. JMRI seems to work with it..
     
    Scott Eric Catalano and Atani like this.
  14. Pieter

    Pieter TrainBoard Member

    152
    46
    10
    Scott Eric Catalano likes this.
  15. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    So to add to the screwdness, JMRI automatically assumes the Address and sub-address of each turnout based on the turnout#. So Turnout number 1 is Address 1 Sub 0, Turnout 2 is Address 1 Sub 1, Turnout 3 is address 1 Sub2, but for Turnout 5 it is Address 2 Sub 0. I think they did this to match some particular decoder brand standard, but to me that is nuts, a person should be able to configure all this on their own to match their equipment. This doesn't even match up with the Configure DCC+ Turnouts & Sensors.. Which I have finally figured out why is populated all on its own with doubles of everything.

    When selecting Configure Turnouts & Sensors, JMRI sends out a <T> to poll all the Turnouts, it does it twice, and self populates the list.. What a PITA.. The DCC++ implementation needs some serious over hauling.

    I'll have to further modify my code to match this. Grrr
     
    Scott Eric Catalano likes this.
  16. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Okay so I have completed the modifications and it works perfectly. I'll polish off the updates to my code and re-upload it for those that are interested.
     
    Scott Eric Catalano likes this.
  17. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    So here is my update.

    The only change to the base station code was under SerialCommand.cpp, I modified the parse() function again. Under the Case 'a' from the switch statement and removed everything an added this aswell, just like the 'T' before

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

    break;


    This way it would just take anything that had the 'a' command to it and pass it along via the Serial1 port (minus the a).

    The code for the Uno has been modified to handle both the 'T' commands and the 'a' commands. I have also added storing the turnouts positions in the EEPROM.
     

    Attached Files:

    Mike 354 and Scott Eric Catalano like this.
  18. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    OK, I'm still parsing out this thread trying to figure out what may be going on here...

    In the meantime, here are a few things...

    In the BaseStation code, the <T> commands are intended to send DCC throw/close packets to trigger turnouts connected to (for example) a DS51 decoder. The <Z> commands are for toggling Arduino outputs to (more or less) directly drive turnouts.

    The JMRI turnout "mode" selects whether a <T> command (MONITORING mode) or a <Z> command (EXACT mode) will be sent from JMRI.

    on the Configuring Sensors/Turnouts/Outputs dialog. If you want to control a DCC turnout using the <T> base station command, set it up in the Turnouts tab. If you want to control a turnout connected directly to an output pin on the base station using the <Z> command, set it up in the Outputs tab.

    In both cases the Index # should be the "hardware address" used in the JRMI Turnouts Table. Then, in the JMRI Turnouts table configure the JMRI turnout as either "MONITORING" mode for <T> commands and EXACT mode for <Z> commands.

    If I understand what you're doing between the Mega and the Uno, i think you probably want to hijack the Z command, not the T.

    There may yet be a bug in the response handling to the Z command... I'll keep looking.
     
    Scott Eric Catalano likes this.
  19. brendanf

    brendanf TrainBoard Member

    62
    54
    8
    Yeah I have actually had more success with the 'a' command.

    The 'T' command problem is strange in that the proper response (feedback) is sent to JMRI which is ideal, but JMRI then sends another command to undo the first.

    So if the turnout status is THROWN and we want to CLOSE it, it will send CLOSE, get the correct response, and then immediately send a THROW so it always stays thrown.
     
    Scott Eric Catalano likes this.
  20. TwinDad

    TwinDad TrainBoard Member

    1,844
    551
    34
    I'm still looking into how to handle this stuff better. I hope to have some kind of improvement in 4.7.2 or 4.7.3 depending on my available working time. Part of the problem is dealing with translating between JMRI's "larger view of the world" and DCC++'s way of doing things... JMRI at the higher levels doesn't really have a way of handling two different kinds of turnouts/outputs with THREE different ways of addressing them, as DCC++ has. So I'm trying to provide a relatively flexible way to map ONE way of looking at things ("Everything is a Turnout with an Address") to THREE different ways of accessing them ("a" commands -- direct DCC packets -- vs. "T" commands -- indexes into a table of DCC addresses -- vs. "Z" commands -- direct control of Arduino pins). This is where the "Configure Sensors/Turnouts/Ouptuts" table comes in. I'm hoping that redoing that a bit with some better, more descriptive terminology will help there.

    That, plus the bugs in handling feedback into JMRI, inversions, etc. I'll probably try to tackle the bugs first, then the structural issues.

    BTW, the Address/Subaddress mess is being driven by the DCC++ Base Station protocol*, not by JMRI. JMRI just has a prefix and an index number. I could map that to almost anything, but the format of the "a" and "T" commands require an address and a subaddress. So I do what I must to keep the Base Station happy.

    * I suspect that DCC++'s implementation was driven by mimicking Digitrax... can't say for sure.
     
    Scott Eric Catalano likes this.

Share This Page