2-wire 4-20ma transducer setup [SOLVED]

I have a cable-extension position transducer (more info here: transducer manual). I would like to read off the inches or mm that the cable extends. The question I have is more about the way that you connect a 2 wire 4-20ma and read it off through the photon. Specifically the place for reading an analog signal from the circuit. This page is helpful but I haven’t been able to implement it yet.

The main problem I see is the device runs on 8-40 Vdc on the red wire, so I guess the photon isn’t able to power this application. Which means untill I take care of that this may not work. Although I’m new to the photon so maybe i’m wrong there.

Picture of the important wiring info:

If anyone knows of a good example for this type of project I would greatly appreciate that.

This is the code I have been using so far to tinker with this, although there are probably many missing or wrong things here due to my novice writing ability.

int PositionTransducerPin = A0;
int PositionReading = 0;
int LiftPosition = 0;



void setup()
{
    Particle.variable("Position", &PositionReading, INT);

}

void loop()
{
    PositionReading = analogRead(PositionTransducerPin);

    LiftPosition = map(PositionReading, 0, 4095, 0, 255);

    Particle.publish("Position", String(LiftPosition));

    delay(1500);
}

Personally, I would opt for using a pre-made solution like one of the boards from ControlEverything. They’ve already done the work of setting up a 16V boost converter and calibrating the current shunt. I haven’t used that particular board, but I’ve been happy with other boards I’ve gotten from them.

2 Likes

@bvolzmfg, the first part of solving this problem is to supply the transducer with the required 8-40v at 20ma (according to the specs). The Photon can provide this voltage through a step-up (boost) switching regulator like this one from Pololu. It will convert the voltage from the Photon’s Vin pin (if powered by USB) and convert it to 12V with which you can power the transducer via the RED and BLACK wires. The BLACK wire is also tied to the Photon’s GND wire to provide a common ground.

For the current to voltage part, you need to use Ohm’s law to calculate the ideal resistance through which the 4-20ma current will be passed to produce a voltage not exceeding 3.3v for the Photon’s analog input. The resistor is connected between the GREEN transducer wire and GND. The Photon’s ADC input is connected to the GREEN wire as well. Therefore:

R = V/I, where I = 20ma max, V = 3.3v max (to be safe, 3.2v max will be used)
R = 3.2/0.02 = 160 ohms.

The power rating for the resistors is set by P=VI or P=3.3*0.02 = 66mW. So a 1/4W resistor (250mw) will do the job.

Finally, to calculate the expected voltage range on the Photon ADC input along with the expected ADC readings, we know the current will range from 4ma to 20ma, therefore, using Ohm’s law again:

Vadc @ 4ma: V = IR = 0.004 * 160 = 0.64v or 640mv
Vadc @ 20ma = 3.2v or 3200mv (as calculated above)

The corresponding ADC values can be calculated using this formula:
ADC = (Vadc/3300) * 4095

ADC @ 4ma = 640/3300 * 4095 = 794
ADC @ 20ma = 3200/3300 * 4095 = 3970

To map these values to a 0-255 range, the code line needs to be:
LiftPosition = map(PositionReading, 794, 3970, 0, 255);

Of course, the accuracy of the values is dependent on the tolerance and final value of the selected resistor.

Hope that helps! :smiley:

3 Likes

@bvolzmfg, OR, you could just follow @rickkas7’s advice which he posted before me! :confused:

2 Likes

I appreciate the help guys! @rickkas7 That is a solid option that I am looking into for a more final setup, appreciate the advice. For now I want to just test some things before investing to much into it, so I will give your method a try @peekay123. The map function was the part I was seeming to misunderstand since i’m a rookie on the code stuff. I will give this a go and see where it gets me. @peekay123 Is there anything for protection of the transducer or photon that I should look into when using the step-up voltage regulator?

@peekay123 When you say

do you mean RED transducer wire? or BLACK?

I’m of the assumtion of BLACK but wanted to check

@bvolzmfg, I just realized that I was reading the 3-wire configuration! The wiring should be:

Transducer      Power (step-up)     Resistor     Photon
---------------------------------------------------------
RED (8-40Vdc)     Vout (12V)
BLACK (4-20ma)                         x          ADC input
                     Vin                          Vin (USB powered)
                     GND               x          GND

This is called a “low side shunt” as per:

The current coming out of the transducer will flow through the resistor, creating a voltage across it that can be measured between V- and V+ on the diagram.

2 Likes

@bvolzmfg, as for protection, DON’T connect the 12V from the step-up to ANY of the Photon pins. The transducer can handle 8-40V so 12V is well within that. Take your time, take voltage measurements along the way. Ideally, measure the voltage across the resistor before you connect the Photon ADC pin.

2 Likes

Will do, main thing is the transducer isn’t mine so I don’t want to ruin it. Will pulling 4-4.5 volts from the photon to the step up cause any problems long term or short? I’ve seen that max is like ~5V so I didn’t know how close is to close.

@bvolzmfg, connecting the step-up to the Vin of the Photon is not “pulling” from it. The Vin pin is Vusb minus a (protection) diode voltage drop or about 4.8v. The Photon’s own step-down regulator draws from Vin to generate 3.3v.

Since the transducer draws a max of 20ma and Vin can handle 1A easily (limited by the USB power adapter), there is no risk to the Photon.

The only risk remains putting a voltage greater than 3.3v to the ADC pin of the Photon. This is why I recommend using a multimeter for checking your voltages prior to connecting to the ADC pin.

1 Like

ahh makes sense. Thank you!

1 Like

I’m finally getting back around to working with this and am now going to surely find struggles in how I publish the results I want to see.

Updates: I am using a wall plug that converts to 9Vdc for my outside DC power source for now. It falls just above the transducers 8-40 Vdc requirements. (I’ll likely get a step-up regulator for my DC source later because this plug set-up is kinda inconvenient) I didn’t have any 160Ω resistors around, so I used a 120 and recalculated the values for the map function for the 120Ω. I read all values on my multimeter before hoking up and all seems good and below 3.3V. The voltage drop corresponded with my calculated max(20mA) and min(4mA) Vadc values. (Cheap DMM so accuracy of these readings were sub-par) The reading for 255 comes out as 267/266 and the 0 value comes out as 2. Can I attribute that to the compiling of non precise values such as the resistor and my measuring equipment? Also, does riding at 9 Vdc, only 1 volt from the min operating needs of the transducer, effect the output accuracy or anything else?

Now the idea is to associate the signal with the inches the transducer wire has traveled in. In my case it has 20 inches of travel. The way the transducer would be mounted would make its highest point (outputting 255~267 wire all the way in) with 20 inches and the lowest (outputting 0~2 wire extended to full length) with 0 inches.

***** Maybe the off reading was something to do with being just started, because now it is giving me consistent 250 and 0 readings at max and min.*** which is still off by 5 but thats better

The point i’m stuck at is coding the photon to read on the cloud the distance the wire is at. I am unsure if there is a way to just map out the values as a function of analog reading to inch reading and get essentially infinite values between the high and low limit, which would be cool. Although I really only need values reading about an inch of change. Maybe I could assign 1-20 inch values with 0-255 readout values at each inch traveled? That sounds tedious and error prone, so let me know your ideas.

Thanks for the help!

The current code:

int PositionTransducerPin = A0; // connected to analog pin 0
int PositionReading = 0;
int LiftPosition = 0;



void setup()
{
    Particle.variable("Position", &PositionReading, INT);

}

void loop()
{
    PositionReading = analogRead(PositionTransducerPin);

    LiftPosition = map(PositionReading, 596, 2979, 0, 255); // values for 120 Ω resistor

    Particle.publish("Position", String(LiftPosition));

    delay(1500);
}

@bvolzmfg, the 120 ohm resistor is fine since it will simply produce a small voltage at the max 20ma current (2.4 volts). Have you checked that your 9 Vdc source can supply enough current and that the output stays at 9 volts when “loaded” by the transducer?

One thing to remember is that while you are reading a 12-bit value from the ADC, you are mapping it to an 8-bit value, reducing the accuracy. The min/max values of the map() function will need to be changed to the min and max values the ADC produces with the 120 ohm resistor. Is there any reason you are not using the full 12-bit range of the ADC?

If I were you, I would publish the “raw” ADC value and create a table of raw ADC values vs distance for a set of distances. Ideally, the relationship between the two is linear. Then, you can create an equation in the form d = ax + b (d = distance, a = slope of xy line, b = zero offset, x = ADC value) which you can then code instead of the map function.

1 Like

It is rated at .67 A @ 9 V. From a quick test it looks like it is dropping from 9V to anywhere around 6.8-7 V, so that may be a problem.

None besides being a noob and not recognizing it. Is String the thing that I need to change for that?

I just tried it where I changed the code to LiftPosition = map(PositionReading, 596, 2979, 0, 20); and it works alright for giving decent inch by inch readouts. Although I would also like to try the linear function method. Appreciated!

Also I am a little unsure on how to type up or format a line of code for the photon to read a linear function. I completely understand the whole getting slope/off-sets/ect… and making the equation, just not how to make the photon read it.

@bvolzmfg, one thing at a time! To get the “raw” ADC values published, simply use Particle.publish("Position", PositionReading); which will publish the integer ADC value. Use those to create your distance vs ADC value table. One you get the table for say 10 distances (or more if you want), post them here.

The equation is easy enough to extrapolate from the data you will gather. Once the slope and the offset are calculated, the code then literally becomes an equation in the form I outlined earlier. Post the data and then we will get to the equation afterwards. :wink:

BTW, what is the range of distanc that you need to measure?

1 Like

@peekay123 Haha sorry I get carried away sometimes. I’ll start to go through this and get some data. The range this transducer goes from is 0-20 inches, and i’ll use most of that range.

@bvolzmfg, depending on the accuracy of the transducer, you could easily get one hundredth to a tenth of an inch accuracy from the ADC readings :wink:

1 Like

I’m getting NULL values with this:

LiftPosition = map(PositionReading, 596, 2979, 0, 255); // values for 120 Ω resistor

Particle.publish("Position", PositionReading);

Does there appear to be any problems here?

@bvolzmfg, I just realized that PositionReading is a Particle.variable(). Also, the publish I proposed is incorrect (I mixed publish with variable!). The code for loop should read:

void loop()
{
    int rawADC;

    //PositionReading = analogRead(PositionTransducerPin);
    rawADC = analogRead(PositionTransducerPin);

    // LiftPosition = map(PositionReading, 596, 2979, 0, 255); // values for 120 Ω resistor

    Particle.publish("Position", String(rawADC));

    delay(1500);
}
1 Like