Changing DCC++ to use true current in mA instead of pin reading?

FlightRisk Feb 7, 2020

  1. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    I added a post here and thought maybe giving the question its own thread would be better. The exact details of my code are in that post, but I was hoping someone more intimate with the code might point out if I did not think things through. Since people can use boards with current sense like the motor shield that has 1.65V per Amp factor, but also boards like the MAX471 that reports 1V per Amp, it would be nice to modify just one line of code in config.h to automatically setup for the correct current sensing and to read and write in actual milliamps instead of meaningless numbers coming out of an analog pin that are different for every board. The link above shows all 5 of the places where small code modifications would need to be done, but the key is that a 1.65v/A board would have a conversion factor or 2.96 and a 1:1 board would have one of 4.88. In the config where you set 1, 2, and now (for me 3 with a MAX471 current sense board) to select your motor control board, the constants for each MOTOR_SHIELD_TYPE just adds this line:

    #define CONVERSION_FACTOR 4.88 // 2.96 for the Arduino, Deek-Robot, etc.

    Then set CURRENT_SAMPLE_MAX to 880 for 880mA, instead of having to know what value the pin reports (300) that corresponds to that cut-out current.

    This is the key piece of changed code. Just wondering if I missed anything or not thinking of nuances that would cause me not to read the correct current or that my slight change (one line of code that does a multiplication) would throw off timing.

    Code:
    void CurrentMonitor::check(){
      current_raw=analogRead(pin)*CURRENT_SAMPLE_SMOOTHING+current_raw*(1.0-CURRENT_SAMPLE_SMOOTHING);    // compute new exponentially-smoothed current
      current_milliamps=current_raw*CONVERSION_FACTOR;
      if(current_milliamps>CURRENT_SAMPLE_MAX && digitalRead(SIGNAL_ENABLE_PIN_PROG)==HIGH){          // current overload and Prog Signal is on (or could have checked Main Signal, since both are always on or off together)
        digitalWrite(SIGNAL_ENABLE_PIN_PROG,LOW);                                                     // disable both Motor Shield Channels
        digitalWrite(SIGNAL_ENABLE_PIN_MAIN,LOW);                                                     // regardless of which caused current overload
        INTERFACE.print(msg);                                                                         // print corresponding error message
      }
    } // CurrentMonitor::check
     
  2. haba

    haba TrainBoard Member

    78
    32
    10
    To report the pin reading to JMRI is broken.

    Progress: https://github.com/habazut/dcc-ardu/tree/testpin_amp-volt-measure

    I did hook up the scope and looked at voltages over known / measured resistances and compared with what was reported by my motor shield: Everything was off by a factor 3, so my motorshield seems to be connected so that everything was off by a factor 3. So I have started to rewrite the current checking code. So far only valid for a Rev3 motor shield and hardcoded in CurrentMonitor (that will change).

    Changes so far:

    * Make CurrentMonitor a class (I don't get why the code does not use proper classes but structs. Now classes are implemented as strutcs but C++ is supposed to _hide_ that fact) In the future more structs should be converetd to proper classes.

    * Decide that the unit is mA. The analogRead gives values between 0 and 1024 which is with the board I have is obvisouly 0 to 3.072A With an unsigned int you can represent up to 65.536A which should be enough for all model railroads even in garden scales.

    * Removed floating point arithmentics

    Todo:

    * Different current limits for main and prog track

    * Use the CurrentManager read method to replace all the analogRead in the ackdetect code

    * Make more structs proper classes

    * Start with work on VoltageMonitor

    Please measure what your motor shields do.

    I have:
    Supply voltage: 14.5V DC
    DCC voltage: 13.5V (You can count approx 1V loss in the H-bridge if you don't have a scope)
    Measured resistance: 181 Ohms
    Calculated current: 75mA
    Reading from current pin: approx 24 to 26
    -> Factor = 3

    Regards,
    Harald.
     
  3. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
  4. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    What do you mean? Based on the changes to report current in milliamps? Or because it was broken before? It was broken a while back, but JMRI issued an update. Also, we could still report the raw pin reading to JMRI for now if we don't want to break it.

    What motor board are you using? And what did you mean by "measured resistance"?
     
  5. haba

    haba TrainBoard Member

    78
    32
    10
    I think to report an internal number which only makes sense in the Arduino is broken. So yes we should report mA.

    I don't know if there is space to support multiple motor shields in _runtime_ as the Uno is a bit small ;-)
    I think it's OK to compile for a specific motor shield.

    Question: What is the use case for multiple motor shields? I guess that's probably only useful on the Mega as the Uno has only 6 pins to read analog values anyway.

    > What motor board are you using?

    I have the one you have as ARDUINO_SHIELD with a conversion factor of 3 (or 2.96).

    > And what did you mean by "measured resistance"?

    I did put a known resistance on the output so that I could calibrate my current readings.

    Regards,
    Harald.
     
  6. haba

    haba TrainBoard Member

    78
    32
    10
    If you now take https://github.com/habazut/dcc-ardu/tree/testpin_amp-volt-measure (git version 671584c) then you can set a 1:10 voltage divider between main track and A2 and then read voltages with the <v> command.

    <2><p1 MAIN>
    <v><v14.54>
    <c><a4>
    add load of 180 Ohms
    <c><a78>
    <v><v13.94>
    <0>
    <c><a3>
    <v><v0.40>

    Regards,
    Harald.
     
  7. Travis Farmer

    Travis Farmer TrainBoard Member

    352
    320
    14
    spotted this and thought i would throw in some input.
    the reason, as i understand it, that the current is reported as the raw ADC value is due to the wide range of supply voltages, and differences (errors?) in the current sensing of each individual board.
    JMRI handles this by reporting a rough percentage, last i recall (perhaps my version is older), rather than the exact amps.
    i would use a display attached to DCC++, like a 16x02, or 20x04 LCD, and let JMRI take what it is used to. personally, i only check the current for utility reasons, so i don't mind the LCD.
    also, the Atmel ADC can vary a bit, so i like to use a reference on an unused ADC channel. the 3v3 pin is good enough for my needs. knowing that whatever value that ADC channel reads, is 3v3, makes the conversion process a little better. something else, checking the actual values of the current sense shunt resistors with a reasonably accurate DMM will improve conversion math. and sensing the DCC++ supply volts, through a voltage divider, with resistor values checked with a DMM, will also help.
    i made a function a while back that was pretty good, but sadly it was lost during a mental-breakdown file deletion fiasco.
    in short, having hard coded values for things that may be in error, like exact supply volts, will throw the whole thing off.

    Just my 2 cents. ;)

    ~Travis
     
    FlightRisk likes this.
  8. Ash

    Ash TrainBoard Member

    106
    67
    8
    A few observations from installing Pololu ACHS-7121 Current Sensor
    Current range / sensitivity: ±10 A / 185 mV/A

    The sensor was placed on the positive lead between power supply and motor board. With track off and no load, the pin value is 512. ( 2.5 volts. Vcc/2. )

    -- for DCCppEX --
    Pin A0 used for both CURRENT_MONITOR_PIN_MAIN and CURRENT_MONITOR_PIN_PROG

    Current conversion factor: ((5/1024)/0.185)*1000 = 26.4
    No load 26.4 * 512 = 13,517 mA zero base
    Add . . . 26.4 * 228 = 6,019 mA desired trip current
    tripCurrentMilliAmps = 19536
    maxCurrentMilliamps = 23496 . . . equivalent to the 2.5 base plus 1.85 volts resulting from +10 Amps.

    And, for the programming track:
    tripCurrentMilliAmps = 15000 . . . but perhaps should be zero base plus 250 = 13,767

    -- or perhaps I will have to get everything installed and the layout finished; it seems that the programming track might require further calibration if 250 mA is critical. I'm new to this. I don't understand if the power is shut off to the main tracks when the programming track is active -- and with one current sensor, it is detecting the load on the track as well as the load of the motor board and the load from occupancy detectors, etc.​

    Once I allowed for the zero base amount, it turns track power on/off. Also tested to see that it provided short protection -- the JMRI power monitor showed 72% when it tripped.

    This is with a 15 volt 10 amp power supply and dual motor board H-bridge MOSFET IRF3205 15A. And not yet tested to determine that it will send the DCC commands to the decoders. It is probably this board: https://model-railroad-hobbyist.com/node/35753

    ACHS-7121 and ACHS-7122 current sensors were mentioned on the Locoduino site. It seems there may be other choices if more sensitivity is needed or where no adjustment is needed for zero base.
    https://www.pololu.com/category/118/current-sensors

    Appreciate the info from FlightRisk posts:
    1. with Locoduino links:
    https://www.trainboard.com/highball/index.php?threads/motor-shield-question.130561/#post-1135502

    2. on some diagnostics:
    https://www.trainboard.com/highball/index.php?threads/dcc-noob.131358/#post-1134040

    This link was also quite useful in determining how to use the LED on Pin 13, etc.
    https://github.com/DccPlusPlus/BaseStation/wiki/Diagnostics---D---Command

    Questions: While this seems to work for short protection, is another change that is needed so that the zero base would not need to be considered? Will the programming track be usable?

    I partly understand where the current conversion factor is used, but it seems that zero base and sensitivity in mV/A would be less confusing.
     

    Attached Files:

    Erik84750 likes this.
  9. FlightRisk

    FlightRisk TrainBoard Member

    548
    237
    14
    Thank you for doing all this. We are still discussing all the design considerations for current sense over on our Discord chat. First, you are measuring the DC input on the low side instead of the varying current on the high side. You would be better off with a uni-directional current sense board. You bring up an interesting issue in that the formula is all wrong for a board centered at 2.5V going going down towards zero for negative current and up towards 5V for positive current. I am not sure how to fix this at the moment because this throws everything off internally in the software. The correct formula would have to include an offset. So we are losing half our precision. Since we we are only using from 512 to 1024 to represent the entire range of positive current we are trying to sense.

    So current conversion factor formula must change since we are only using half the scale:

    ((5/1024)/.185) = .0264 Amps per increment

    That means that instead of 10Amp negative and positive, this has a swing of -13.3A to +13.3A

    So we need this formula:

    CurrentMilliamps = CURRENT_CONVERSION_FACTOR * (pinReading - 512) and then check for Current MilliAmps less than zero and make it zero.


    No load = 26.4(512-512) = 0 mA
    50% = 26.4(768-512) = 6758 mA
    75% = 26.4(896-512) = 10138 mA (over 10A!!)
    100%= 26.4(1024-512)= 13,517 mA

    26.4(9.47) = 250 mA

    But all this is theoretical since you are measuring on the input and these current sense boards don't even measure until around 100mA or more. The datasheet show current vs. voltage begin at .5V and go to 4.5V. If you compute 4/1024/.185, you get .0211. So using a factor of 21.1 actually comes close to -10 to +10. So I guess we are going to have to do some tests with resistors on the track and a meter and see what we actually get.

    Fred
     

Share This Page