Initial report by Lia Martinez, 13 April 2012

Introduction

The eTape Liquid Level Sensor is a solid-state sensor with a resistive output that varies with the level of the fluid. It is like an electronic tape measure that, once submerged in a fluid or powder, emits a signal. It is an innovative in that makes use of printed electronics instead of moving mechanical floats. The e-Tape’s envelope is compressed by the hydrostatic pressure of the fluid in which it is immersed, which results in the change in resistance.

http://itp.nyu.edu/physcomp/sensors/uploads/etape_pic1

The eTape sensor provides a resistive output that is inversely proportional to the level of the fluid. The lower the liquid level, the higher the output resistance.

The eTape is one of a new generation of printed electronics. It is made of PET, which is the same material that water bottles are made from, making it less susceptible to corrosion. Additionally, because it is a solid state sensor and has no moving parts, it is not affected by salt creep, etc, making it ideal for salt water/ marine environments. Uses also include the medical field, where there is a need for sensors that are affordable and disposable.

This report was based on the PN-6573P-12 and the PN-6573P-8.

When to use it

There are a number of different kinds of fluid-level sensors. Whether the fluid is housed in a neat and compact container, or has a substantial area to be measured, there are many application-specific criteria to consider in selecting the proper sensor for the job. Digikey suggests these criterias for selecting a liquid level sensor:

Which kind of fluid will be measured? The data sheet specifies that it be used for non-corrosive liquids. Milone additionally stated that the sensor will work fine in household sewage, dilute ethanol, and salt water/marine environments. They are currently developing a chemical sensor for use in fuels, solvents, strong acids/bases, etc.

Can the level sensor be inserted into the tank or should it be external? Can the sensor come in contact with the process fluid? (Meaning physical contact between the device and the liquid; non-contact methods measure without touching the media.) The eTape sensor has to be submerged in the liquid. If you need to be external, a pressure sensor might do.

Should the sensor detect the level continuously or will a point sensor be adequate? (point sensing involves taking measurements at certain instances) The eTape sensor detects levels continuously. This is an example of a point sensor, as used in a washing machine. A float sensor, as a toilet bowl, is also a switch.

Is direct measurement of the level needed? (Direct measurement includes methods that directly sense position and level. Indirect measurement involves the sensing of other factors such as pressure head, which can then be translated to height or level.) The eTape sensor provides direct measurement.

Is process shut-down acceptable when sensor removal or maintenance is required? The eTape is easily stopped and restarted, and interfaces easily with ADC controllers like the Arduino.

There are many physical and application variables that affect the selection of the optimal level monitoring method for industrial and commercial processes. The laundry list of factors may include temperature, pressure, vibration, density (specific gravity) of the medium, and environmental conditions particular to a given application.

Sources

I got mine as a free sample from Milone Technologies. Chris Milone, the owner and developer, answered the phone and sent me 4 free samples within 3 days. The company seems to be very accommodating when it comes to answering questions, and frequently replies on the Sparkfun forum.

8” is available from the manufacturer website for $34.99 and Sparkfun/ Adafruit for $39.99. 12” and 24” also available.

According to Chris Milone, in a letter to me from 05/13/2012: FYI, the 3-pin sensor will be discontinued once stock is depleted and will be replaced with the 4-pin sensor. We've simplified the design which gives better resolution and linearity.

Applications

Liquid Level Sensors are commonly used in any commercial or industrial process involving the filling or storing a liquid in a tank or vessel. They can also be found in soda machines, hydroponics, aquarium, fountain or pool controller, or perhaps measuring a rain tube.

Closer to home, it was used in the ITP Project Digi Drench.

Electrical Characteristics

The product operates at a maximum of 5V.

The eTape can be modeled as a variable resistor. The 8” outputs 385 ohms empty, 60 ohms full, ± 10%, while the 12” outputs 600 ohms empty, 80 ohms full, ± 10%. The resistance gradient is standard at 40 /inch (16 /cm), ± 10%

 8” eTape Data Sheet
 12 “eTape Data Sheet

Here are the technical specs for the 12”:

	•	Sensor Length: 14.1" (358 mm)
	•	Width: 1.0" (25.4mm)
	•	Thickness: 0.015" (0.208 mm)
	•	Resistance Gradient: 55Ω / inch (22Ω / cm), ± 15%
	•	Active Sensor Length: 12.6" (320.7 mm)
	•	Substrate: Polyethylene Terephthalate (PET)
	•	Sensor Output: 600 empty, 80Ω full, ± 10%
	•	Actuation Depth: Nominal 1 inch (25.4 mm)
	•	Resolution: 1/32 inch (0.794 mm)
	•	Temperature Range: 15°F - 140°F (-9°C - 60°C)

Pin Descriptions

http://itp.nyu.edu/physcomp/sensors/uploads/etape_pins

The eTape PN-6573P has 3 pins. the outers pins are the sensor output, the middle pin is inactive.

The eTape PN-12110215TC has 4 pins, the inner two being the sensor outputs, and the outer two being reference resistors which can be used for temperature compensation. This model was not tested here.

Microcontroller Connections

Since the eTape is a variable resistor, you can use it in a simple voltage divider circuit.

http://itp.nyu.edu/physcomp/sensors/uploads/etape_circuit

As in this Adafruit tutorial, connect one pin of the sensor to ground, then the other pin to a 470 ohm resistor. The other side of the 470 ohm resistor to VCC (3.3V or 5V for example) to create a resistor divider. The ADC pin connects to the point between the resistor and sensor.

You can also use an op-amp circuit, as shown in the datasheet.

Code Sample

This is code from the Adafruit tutorial, modified to add a voltage measurement.

// the value of the 'other' resistor
#define SERIESRESISTOR 465    

// What pin to connect the sensor to
#define SENSORPIN A0

void setup(void) {
  Serial.begin(9600);
}

void loop(void) {
  float reading;

  reading = analogRead(SENSORPIN);

  float voltage = (reading *  5.0) / 1024.0;  
  Serial.print("Voltage ");
  Serial.println(voltage);

  Serial.print("Analog reading ");
  Serial.println(reading);

  // convert the value to resistance
  reading = (1024 / reading)  - 1;
  reading = SERIESRESISTOR / reading;
  Serial.print("Sensor resistance ");
  Serial.println(reading);

  delay(1000);
}

In the voltage divider circuit, the voltage is directly proportional to the resistance of the eTape sensor.

    V at Pin 2 = [Vdd  x R eTape] / [ 2KΩ + R  eTape]

Where the fixed resistor is 2kΩ .

The eTape sensor has lower resistance at higher liquid levels and higher resistance at lower liquid levels. Therefore the maximum digital Voltage reading corresponds to an empty tank and minimum digital Voltage reading corresponds to a full tank.

http://itp.nyu.edu/physcomp/sensors/uploads/etape_circuit

As the diagram says, you can use this to get percentage full:

	(A/D max - A/D measurement) / (A/d max - A/D min) = % full.

You could also get liquid level by mapping the values, for instance:

	liquidLevel = map (sensorResistance, minValue, maxValue, maxHeight, minHeight); 

Remember to subtract the Actuation Depth (Nominal 1 inch (25.4mm)) from the minimum height, because you won’t get sensor values past that point. So instead of being 0in, your minHeight should be 1in.

Here is a Processing sketch that I wrote because I wanted to see a history of the sensor's values (the code could be cleaned up):

/* graphing serial data + getting a history
 Lia Martinez
 */


import processing.serial.*;
int sensorMin;
int sensorMax;
int sensorHeight;

Serial myPort;  

int[] numbers = new int[1001];
ArrayList history;

int boxSize = 10;
int gridBottom;
int gridTop;
int value;

boolean pouring;

//Timer
int timer;
int dur = 1000;

void setup() {
  size(numbers.length, 800);
  println(Serial.list());
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
  myPort.bufferUntil('\n');

  value = 0;
  gridTop = 400;
  gridBottom = gridTop + 400;
  history = new ArrayList();

  timer = millis();
  textFont(createFont("Georgia", 15));

  //get your sensor min/ max ready for mapping.
  sensorMin = 80; //80
  sensorMax = 550; //600
  sensorHeight = 12;

  pouring = false;
}

void draw() {
  background(255);

  textAlign (LEFT);
  textSize (20);
  text ("Current Voltage: " + nf(getVoltage(value), 1, 2), 70, 400);  
  text ("Sensor Resistance: " + nf(getSensorResistance(value), 1, 0), 70, 430);  
  text ("Liquid Level: " + map (getSensorResistance(value), (float)sensorMin, (float)sensorMax, 12.0, 1.0), 70, 460);

  //real-time Graph (initial value min, inital value max, mapped min, mapped max)
  drawRealTime(sensorMin, sensorMax, 30, 300);

  //enter the new value
  numbers[numbers.length-1]= int(getSensorResistance(value));

  //push it along
  for (int i = 1; i<numbers.length;i++) {
    numbers[i-1] = numbers[i];
  }

  //every few seconds, drop the value into the history array
  if (millis() - timer > dur) {  
    timer = millis();
    history.add(new History(int(getSensorResistance(value))));
  }

  //graph the history
  drawHistory(sensorMax, sensorMin, 0, 400);
}


void serialEvent (Serial myPort) {
  String myString = myPort.readStringUntil('\n');
  myString = trim(myString);
  value = int (myString);
  println ("VALUE " + value);
}

float getVoltage(int value) {
  float voltage = (value *  5.0) / 1024.0;  
  return voltage;
}

float getSensorResistance(int value) {
  float reading = (float)value;

  reading = (1024 / reading)  - 1;
  reading = 465 / reading;  
  return reading;
}

void drawGraphPaper(int top_, int bot_, int left_, int right_, boolean moving_) {
  int topp = top_;
  int bot = bot_;
  int leftSide = left_;
  int rightSide = right_;
  boolean moving = moving_;

  stroke(100, 200, 100, 100);

  //vertical lines
  for (int i = leftSide/boxSize ;i<=rightSide/boxSize;i++) {      
    if (moving) {
      line((-frameCount%boxSize)+i*boxSize, topp, (-frameCount%boxSize)+i*boxSize, bot);
    }
    else {
      line(i*boxSize, topp, i*boxSize, bot);
    }
  }
  //horizontal lines
  for (int i = topp/boxSize ;i<=bot/boxSize;i++) {
    line(leftSide, i*boxSize, rightSide, i*boxSize);
  }
}

void drawRealTime(int numMin_, int numMax_, int mapMin_, int mapMax_ ) {
  int numMax = numMax_;
  int numMin = numMin_;
  int mapMax = mapMax_;
  int mapMin = mapMin_;

  drawGraphPaper (mapMin, mapMax, 0, numbers.length, true);

  noFill();
  stroke(0);
  beginShape();
  for (int i = 0; i<numbers.length;i++) {
    float mappedNumbers = map (numbers[i], numMin, numMax, mapMin, mapMax);
    vertex(i, (mapMax-mappedNumbers) + mapMin);
  }
  endShape();
}

void drawHistory(int numMin_, int numMax_, int mapMin_, int mapMax_ ) {
  int numMax = numMax_;
  int numMin = numMin_;
  int mapMax = mapMax_;
  int mapMin = mapMin_;
  int startTop = 330;
  int startBot = height - 100;
  int startLeft = width/2;
  int startRight = width-100;

  fill(0);
  textAlign (LEFT);
  text ("resistance", startLeft - 120, height - (startBot - startTop) + 100);
  textAlign (CENTER);
  text ("water level", width - (startRight - startLeft) + 100, startBot + 30);

  drawGraphPaper (startTop, startBot, startLeft, startRight, false);  

  noFill();
  stroke (0);
  beginShape();
 for (int i = 0; i<history.size()-1;i++) {

    History hist = (History) history.get(i);

    //map it to scale
    float mappedHistory = map (hist.hisValue, numMin, numMax, startBot - startTop, 0 );
    if (pouring) {
      vertex(i+startLeft, startBot - mappedHistory);
    } else {
      vertex(startRight - i, startBot - mappedHistory);
    }
  }
  endShape();
}

class History {

  int hisValue;

  History(int historyValue){
    hisValue = historyValue;  
  }
}
 

Typical Behavior

This is the graph from the data sheet: http://itp.nyu.edu/physcomp/sensors/uploads/etape_typ

Application Notes

The Digi Drench group reported some "jumpiness" in the readings, for example: if the water was steadily emptying, the readings wouldn't say: 5, 4, 3, 2, 1, empty, it would say: 5, 4, 4, 4, 1, empty. I was able to reproduce this in 2 out of 5 tests.

Digi Drench also said that when the water level went above a certain point, the readings would return to 0. I have been unable to reproduce this.

For my part, I noticed that if I left the water level sensor submerged and returned to it a few hours later, the values would be different from what I had previously recorded with similar water levels.

When I asked Chris Milone about these issues, he responded:

I do believe that this is an issue with how the sensor was mounted. The sensor should be mounted in a fashion to allow the liquid to interact with both sides of the tape. Otherwise sensitivity and response time is reduced. As you can see in our video, the sensor is hanging freely in a graduated cylinder and we get a very linear steady response. The sensor can be installed in a 1.25" diameter perforated/slotted PVC pipe instead of using double sided tape. We are working on a mounting bracket that is open in the middle which will hold the sensor rigid and allow the liquid to interact with both sides of the sensor.

References/Bibliography

 Demo video from Milone

references:

 Manufacturer website

An interview with Chris Milone

Keywords

List any useful tags or keywords that will make this report more searchable.