DCC++ Throttle Design - Ideas to finished product.

UK Steve Nov 9, 2017

  1. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hey Guys,

    So the postman dropped by yesterday with the joystick delivery I was expecting, along with another parcel from China. Wow, only 10 days from placing my order, that was quite a surprise :) I now have 3 joysticks, one of which is a low profile version some of you may have seen.

    So straight down to some code testing, and after a tweak here and there I think I have the beginnings of the core to operate the throttle as my original idea.

    Here's a first draft of some code for you guys to play with. Initially most of the development will be done on Arduino Uno. We'll try to work through things at a pace to give everyone a change to thoroughly understand how this project works. There will be many alterations along the way. My coding style is to generally throw something together in quite short order, get it working as I want then look to tidy up and optimise things later. I've also found it best to start with the basic core of what I want to do, then add things in a modular fashion.

    The humble 328P is cheap and has it's place in amateur electronics, however it has to be said in more recent times it just can't compete with the new kids on the block. The Teensy series running ARM Cortex processors and Espressifs ESP's are notable here. The great thing is these new chip's are very affordable, and best of all, have been added as alternatives you can program in the familiar Arduino IDE.

    I will be exploring the capabilities of the latest ESP32 in this series and hope some of you will too. This is mainly to do with getting a seriously fast output to a cheap colour display, and running all the WiFi stuff on one amazing device, trust me on this, and you have nothing to fear, it's Uno on steroids :)

    Here's a side by side demo of what modern 32 bit MCU's (Teensy 3.6 - 180 MHz ARM Cortex-M4 with Floating Point Unit) can do with the 2.4" display I will be featuring in this project...



    So here's the code, it will start in Select mode and all you need do for now, is connect the joystick to 5V, GND with x and y outputs to analog pins A0 and A1. Depending how you have the joystick physically orientated, you may have to swap the analog pin connections. I had the device with wires at the Southern pole if you like and had to do just that. Open the serial monitor and hopefully figure my basic instructions.

    After a short time testing last night, I soon got used to this, what at first feels a rather odd method of control.
    I hope you can see some mileage in it. It might not be for everyone, but hey ho. This core function is essentially a fully operational 10 channel throttle. Strip out all but the command prints and it would work on a Base Station, not bad for about a hundred lines of code.

    Please don't hesitate to ask questions. In the meantime I'll get down to writing the next part, which should be the function set's, have fun :)

    Code:
    /*
      Sketch uses 5,938 bytes (18%) of program storage space. Maximum is 32,256 bytes.
      Global variables use 348 bytes (16%) of dynamic memory, leaving 1,700 bytes for local variables. Maximum is 2,048 bytes.
    */
    
    uint8_t yPin = 0;
    uint8_t xPin = 1;
    uint16_t xVal;
    uint16_t yVal;
    uint16_t interval;
    uint32_t startTime = 0;
    uint8_t lastCount = 127;
    uint8_t count = 0;
    uint8_t lastOut;
    int8_t tReg = 0;
    uint16_t loco [11] = {0, 123, 777, 4371, 17 , 2820, 613, 3, 401, 992, 6545};
    uint8_t speed [11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    uint8_t dir [11] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
    bool throttleMode = false;
    bool selectMode = true;
    
    
    void printList() {
    
      char throttleCmd [22];
      Serial.print(F("Current Settings...\n"));
    
      for (uint8_t i = 1; i < 11; i++) {
        if (i == tReg) sprintf(throttleCmd, "\x09*<t%d %d %d %d>*", i, loco[i], speed[i], dir[i]);
        else sprintf(throttleCmd, "\x09 <t%d %d %d %d>", i, loco[i], speed[i], dir[i]);
        Serial.println(throttleCmd);
      }
    }
    
    void printInfo() {
    
      char info [50];
      sprintf(info, "tReg# %d selected, Loco# %d, Speed %d, Dir %d\n", tReg, loco[tReg], speed[tReg], dir[tReg]);
      Serial.print(info);
    
    }
    
    void sendCmd() {
    
      char throttle [16];
      sprintf(throttle, "<t%d %d %d %d>", tReg, loco[tReg], speed[tReg], dir[tReg]);
      Serial.println(throttle);
    
    }
    
    
    void setup() {
    
      Serial.begin(115200);
      Serial.print(F("Select Mode...\n"));
      Serial.print(F("Please select a Loco with Up or Down\n"));
      Serial.print(F("Go to Throttle Mode with >>>Stick Right\n"));
    
    }
    
    
    
    void loop() {
    
      xVal = analogRead(xPin);
      yVal = analogRead(yPin);
    
    
    
      if (throttleMode) {
    
        if (xVal < 100) {
          throttleMode = false;
          selectMode = true;
          Serial.println(F("Select mode..."));
        }
    
        if (xVal > 924 && millis() - startTime > 500) {
          startTime = millis();
          dir[tReg] = !dir[tReg];
          speed[tReg] = 0;
          count = 0;
          Serial.print(F("Dir change, throttle to 0 "));
          sendCmd();
        }
    
        if (yVal > 622) {
    
          interval = map(yVal, 623, 1023, 500, 20);
          if (lastCount != count) {
            Serial.println(count);
            lastCount = count;
            speed[tReg] = count;
          }
    
          if (millis() - startTime > interval) {
            if (count < 126) count ++;
            startTime = millis();
          }
        }
    
        if (yVal < 401) {
    
          interval = map(yVal, 0, 400, 20, 500);
          if (lastCount != count) {
            Serial.println(count);
            lastCount = count;
            speed[tReg] = count;
          }
          if (millis() - startTime > interval) {
            if (count > 0) count --;
            startTime = millis();
          }
        }
    
        if (yVal > 400 && yVal < 623) {
          if (count != lastOut) {
            lastOut = count;
            sendCmd();
          }
        }
      }
    
      if (selectMode) {
    
        if (millis() - startTime > 300) {
          if (yVal > 922 ) {
            if (++tReg > 10) tReg = 1;
            count = speed[tReg];
            startTime = millis();
            printInfo();
    
          }
    
          if (yVal < 100 ) {
            if (--tReg < 1) tReg = 10;
            count = speed[tReg];
            startTime = millis();
            printInfo();
    
          }
        }
        if (xVal > 922) {
          startTime = millis();
          selectMode = false;
          throttleMode = true;
          lastCount = 127;
          Serial.println(F("Throttle mode..."));
          Serial.print(F("You can return to Select Mode with <<<Stick Left\n"));
          printList();
        }
      }
    }
     
    Last edited: Nov 9, 2017
  2. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Tinkering tip....

    If the max count speed - which is coded at 20 milliseconds or 50 count's per second - is way too fast for you, then have a tinker with these 2 lines of code...

    interval = map(yVal, 623, 1023, 500, 20);

    interval = map(yVal, 0, 400, 20, 500);

    Just change the 20's to something a bit more sedate, say 50 which is 20 counts per second. You should have noticed this speed applies at the extreme ends of stick travel, whereas the start speed - just off the central zone - is, you guessed it 500 milliseconds or 2 counts per second :)

    The downside of going slower of course, is that it will take a bit longer to count through the full range of 0 -126, but a least there's some flexibility here.
     
    Scott Eric Catalano likes this.
  3. esfeld

    esfeld TrainBoard Member

    442
    382
    17
    Steve
    New code works like a dream ...... I, for one, prefer the slower acceleration with the interval change. I also noticed that you are, once again, returning throttle speed to zero on direction change ... as you know I prefer maintaining speed on direction change and would also love a "loco full stop" function .... but once again well done on the coding. I think the little bugger has great potential ...... but then again anything other than a rotary encoder brings a smile to my face :)
    Steve F
     
    Scott Eric Catalano and UK Steve like this.
  4. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hi Steve

    Thanks for the thumbs up :)

    There's nothing to stop you commenting out the throttle to zero on direction change, it would then be just as you like it :)

    Code:
        if (xVal > 924 && millis() - startTime > 500) {
          startTime = millis();
          dir[tReg] = !dir[tReg];
          //speed[tReg] = 0;
          //count = 0;
          if(dir[tReg] == 0) Serial.print(F("Dir change, Reverse));
          else Serial.print(F("Dir change, Forward"));
          sendCmd();
        }
    
     
    Scott Eric Catalano, esfeld and Atani like this.
  5. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Steve, I do have to say this looks like a great step in the right direction! I can't wait for my parts to get here, all of them are in transit with the ESP32s leading the way (left China 4 days ago per tracking, no updates since though)

    If I could make one recommendation for the final code... move these magic numbers into a #define... It will save people a lot of headaches if they could go do one file that has all of the configurable parameters in it with comments. Similar to Config.h in DCC++ etc...
     
  6. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hey Mike,

    Yeah will do all the #define stuff as we move along, like I say I just write ad hoc 'till it works :)

    And yeah I was real surprised when all my stuff arrived on Wednesday, don't know what to tinker with first, will post pictures later :)
     
    Scott Eric Catalano, esfeld and Atani like this.
  7. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Great! I do similarly, I usually have about two dozen permutations on things before I am satisfied with it and start cleanup for publishing. Some things though end up slipping through and get cleaned up eventually though.
     
  8. Keith Ledbetter

    Keith Ledbetter TrainBoard Member

    279
    195
    12
    Yep got it loaded and certainly see the potential here! I'll play with it a little more on weekend but like it so far!

    That display demo is an amazing difference for sure. Looks like more stuff to buy just after I was learning a little about the Nextion :)
     
    Last edited: Nov 11, 2017
  9. esfeld

    esfeld TrainBoard Member

    442
    382
    17
    Keith
    Correct me if I'm wrong but isn't that a Nextion 2.4" just being driven by a Teensy?
    Steve F
     
    Scott Eric Catalano likes this.
  10. Keith Ledbetter

    Keith Ledbetter TrainBoard Member

    279
    195
    12
    So yes you may very well be correct. Some kind of 4 pin TFT for sure so yes nextion should work for whatever SteveUK is cooking up.
     
    Scott Eric Catalano likes this.
  11. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hey Guys

    Just to clear up any confusion, the tft in the video is not a Nextion.
    It is very similar to one of these... https://www.ebay.co.uk/itm/3-3V-240x320-2-4-SPI-TFT-LCD-Touch-Panel-Serial-Port-Module-with-PBC-ILI9341/272861721750?ssPageName=STRK:MEBIDX:IT&_trksid=p2057872.m2749.l2649

    The 4 pins at the top edge of the panel are the SD card interface, the lower edge row is the TFT SPI interface which will have 9 to 14 pins, depending on touch or plain capability.

    For folks who have not bought a Nextion, I recommend getting a panel similar to the one in the listing above. Reason is, Nextion is now looking rather expensive. The price of displays in general has fallen these last few years, but Itead are not reducing their prices to match. As for what can be used in this project, then I will try to cover both options. One more thing, do not buy the even cheaper Uno shield version of these displays as the shield then prevents access to the uno's spare pins, not that there are many left in that case either.

    This is the type of shield I'm talking about, and yes I can see they would appeal on price :)
    https://www.ebay.co.uk/itm/Hot-2-4-...847707?hash=item4d6343779b:g:DDkAAOSwx6FZuORs
     
    Last edited: Nov 11, 2017
    Scott Eric Catalano, esfeld and Atani like this.
  12. esfeld

    esfeld TrainBoard Member

    442
    382
    17
    Steve
    Thank you for the clarification ..... while the Nextion editor is a plus, what would be used with these new TFTs?
    Steve F
     
    Scott Eric Catalano likes this.
  13. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    Hi Steve

    Nextion editor is a plus, but I'll bet not many folks want to spend the time (several months) learning how to use it.
    So with the cheaper alternatives it's back to good old C/C++ in the IDE, and with the modern MCU's all the code is in one place.
    Fortunately for us, a lot of effort has very recently been put in by some smart folks, to give some excellent new libraries for these displays.
    Which is just what I've been tinkering with over the weekend :)
     
    Scott Eric Catalano and Atani like this.
  14. esfeld

    esfeld TrainBoard Member

    442
    382
    17
    OH swell! While I was an adjunct prof teaching C/C++ at the post graduate level back around 1996 I'm understandably a bit rusty ..... but I will endure! :) :)
    Steve F
     
    Scott Eric Catalano likes this.
  15. esfeld

    esfeld TrainBoard Member

    442
    382
    17
    Steve UK and guys
    Got my first ESP 32 yesterday and have been playing around. Have been able to successfully load both a Hello World and a simple WIFI server to the module using the Arduino IDE. Takes a bit of configuration as Arduino does not have a board manager set up yet but looks good for further development.
    Steve F
     
    Scott Eric Catalano and Atani like this.
  16. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Awesome! I should have my handful of ESP32 boards in the next day or two. As for Arduino IDE, the git hub based instructions are pretty decent but I found that PlatformIO is a lot easier to setup and use for the ESP32. With PlatformIO you just set the platform and board type and it figures out the rest for you automatically :)
     
    wvgca likes this.
  17. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    @Steve F

    That's great news, and well done!
    Yeah, as Atani says above, the github instructions are easy and installation in Windows is a breaze.
    Link here... https://github.com/espressif/arduino-esp32/blob/master/docs/arduino-ide/windows.md
    I'd go as far to say it's somewhat easier than it's predecessor the ESP8266 was, if you wanted the latest github core.
    Links to other platforms on the main page here...
    https://github.com/espressif/arduino-esp32
    PlatformIO is another great option if you're comfortable enough to try it out:)

    So what have I been up to?

    Well I did the Arduino installation as above, then after confirming my new board works with the Blinky sketch, moved straight on to attaching a display.
    After some initial difficulties I got things working, and I'm currently playing around with a Keyboard sketch derived from the Adafruit Arduino-O-Phone
    Here... https://learn.adafruit.com/arduin-o-phone-arduino-powered-diy-cellphone/arduin-o-phone-sketch
    Bodmer includes it as an example in his excellent new port of the Adafruit_GFX library for ESP32 here...
    https://github.com/Bodmer/TFT_eSPI/blob/master/TFT_eSPI.h

    Basically a bunch of interactive number keys, which is just the sort of thing we need. Next I'm going to do a few modifications of my own for the touch response (this evenings endeavour), then move on to perhaps the most challenging part of the interface, which will be the function keys. I'll need some pointers from you guys on this, as I try to make sense of latching and non-latching keys. Is there a standard format out there? Or does it all need to be user configurable?
     
    Scott Eric Catalano likes this.
  18. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Steve (and others), a word of caution on the esp 32 and i2c.. The esp 32 is not the most graceful at it. There is a bug logged and it is being worked on. I will be testing the updates as they are ready. So if you see i2c timeouts as part of your testing there is a fix coming, I will share the details after I get a chance to test the fix.

    Sent from my ONE E1005 using Tapatalk
     
    Scott Eric Catalano likes this.
  19. UK Steve

    UK Steve TrainBoard Member

    453
    683
    12
    @Atani

    Not using i2c, SPI(which is new to me) and no issues so far:)
     
    Scott Eric Catalano and Atani like this.
  20. Atani

    Atani TrainBoard Member

    1,460
    1,697
    36
    Scott Eric Catalano likes this.

Share This Page