Need suggestion to improve the technique

Hi
I am working on project to measure area of irregular shape leather sheets. The logic of the system is as follows.
There is a 128 LEDs bar at top and 128 photo sensors at bottom 2 cm apart each, the sheets passes through these and they get on and off basis on the presence of sheet between LED and sensor. Speed of the conveyor is measure by the proximity sensor. which produces one pulse against 1cm movement of sheet.
In program, I am counting number of off sensor at each pulse of proximity and multiply by 2 (as sensors are 2cm apart) and add until get zero.
Now the problem is my algorithm is not producing as good results as the machine I am trying to mimic even though that machine is using same logic.
Could anyone suggest any idea how to improve my algorithm to get better results?

int led = 12;
int latch =  11;
int cloc = 10;
int daata = 9;
const byte interruptPin = 2;
volatile byte state = LOW;
int add = 0, sum = 0;
void sample();
int readData();
// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(led, OUTPUT);
  pinMode(latch, OUTPUT);
  pinMode(cloc,OUTPUT);
  pinMode(daata,INPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), sample, RISING);
  
  Serial.begin(9600);
    digitalWrite(latch, LOW);
      digitalWrite(cloc, LOW);
}

void loop(){
  int c=0;
  if (state == 1)
  {
   c = readData();
   state = LOW;
   if (c!=0)
   {
    add=1;
    sum+=c;
   }
   else if(add == 1)
   {
    Serial.print(sum);
    sum = 0;
    add = 0;
   }
  }

}


int readData(){
   int c=0,d=0;
   int i;
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(2);    
  digitalWrite(latch,HIGH);
  digitalWrite(led,LOW);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
  for(i=127;i>=0;i--)
  {
    c= digitalRead(daata);
    if(c == 0)                // check either c 0 or c 1 if(c!=0)
     d++;
    digitalWrite(cloc, HIGH);
    delayMicroseconds(10);
    digitalWrite(cloc, LOW);
    delayMicroseconds(10);
  }
  digitalWrite(latch,LOW);
  return d;
}
void sample(){
  state = HIGH;
}

A diagram of the machine would help us to visualize what you are trying to do.

Now the problem is my algorithm is not producing as good results as the machine I am trying to mimic even though that machine is using same logic.

Please tell us in detail what it actually does and what you want it to do that is different.

It seems to me that it could be difficult to debug this without access to the hardware for experiments.

...R

Robin2:
Please tell us in detail what it actually does and what you want it to do that is different.

that machine reproduce-ability and accuracy of measurement is better than mine

like a fix area sheet produces slightly different readings in my code. But that machine readings are very precise.
I will upload pics shortly.
there is one strange thing that I observed using oscilloscpe that the at normal speed proximity produces 60 pulses per second so machine should take 60 readings, but that machine take 78 readings( I measured by checking how many time latch signal goes low).

saki003:
that machine reproduce-ability and accuracy of measurement is better than mine

Sorry for not being as clear as I should have been.

I would like you to tell us in as much detail as possible what your program actually does and what you want it to do that is different. That will help us to pinpoint where the problem may be.

...R

First I'd check your program by using a circular shaped object. With such an object the orientation does not matter and your program (finally) must come close to the known size, and/or what the machine outputs.

But leather may have not such a perfect shape, e.g. comes with tiny legs. If your results are too high, compared to the machine output, you may have to ignore narrow stripes. In general I'd determine one border of the piece in question, then find the other border, and calculate the width between both. If the piece is cluttered, narrow stripes may have to be excluded from the total surface, and you only count the widest area or only areas of a minimum width.

How long does each reading take to complete? You don't need to take the readings at 1cm intervals, if the conveyor is constant speed, take more readings at a timed interval, and use the interrupt to measure distance from the first to last non-zero reading.

How are you connecting 128 sensors to the Arduino? How are you reading all 128 sensors? How many linear mm are you trying to achieve between readings? How fast does the conveyor move?

If the conveyor is moving, it may be taking more time to read the sensors than the it takes for the conveyor to move.

We need to know what you external circuitry is to be able to access all of those sensors. My first thought would be use some sort of clock-latched chip to ensure you are reading straight across the workpiece instead of on an angle (angle comes from reading one input at a time while the conveyor is moving). Then you can read all of the sensors and know at what exact point straight across the readings were taken. The chips that first come to mind are a pair 74x373 octal latches connected to a PCF8575 16 I/O expander. You would need 8 of these sets for the 128 sensors.

The sensors that are blocked at the edge don't necessarily represent a full 2 cm^2 of leather. They probably average 1 cm^2 so after doubling the count (WHICH I DON'T SEE IN YOUR SKETCH) subtract 2 to make up for the edges.

If you are getting 78 interrupts when you should be getting 60 then something is wrong with your hardware. Could your sensor input be bouncing? You might want to note the interrupt time (millis()) and throw out interrupts that happen less than 10 milliseconds (1/100th second) since the previous interrupt:

void sample()
{
  unsigned long currentMillis = millis();
  static unsigned long lastMillis = 0;
  if (currentMillis - lastMillis > 10)
      state = HIGH;
  lastMillis = currentMillis;
}

DrDiettrich:
First I'd check your program by using a circular shaped object. With such an object the orientation does not matter and your program (finally) must come close to the known size, and/or what the machine outputs.

I checked with 5 ft2 (4645 cm2) circular sheet. my program was measuring it between 3.73 ft2 (3468 cm2) to 3.81 ft2 (3540 cm2) . So that is inaccurate as well less precise.

adwsystems:
How are you connecting 128 sensors to the Arduino? How are you reading all 128 sensors? How many linear mm are you trying to achieve between readings? How fast does the conveyor move?

I am using 16 CD4021 shift registers for sampling data. At every pulse from proximity. I sample data on shift register and than serially receive it. Conveyor is moving at 60cm/sec

johnwasser:
The sensors that are blocked at the edge don’t necessarily represent a full 2 cm^2 of leather. They probably average 1 cm^2 so after doubling the count (WHICH I DON’T SEE IN YOUR SKETCH) subtract 2 to make up for the edges.

If you are getting 78 interrupts when you should be getting 60 then something is wrong with your hardware. Could your sensor input be bouncing? You might want to note the interrupt time (millis()) and throw out interrupts that happen less than 10 milliseconds (1/100th second) since the previous interrupt:

void sample()

{
  unsigned long currentMillis = millis();
  static unsigned long lastMillis = 0;
  if (currentMillis - lastMillis > 10)
      state = HIGH;
  lastMillis = currentMillis;
}

You are right about edge sensors but I am already getting less value than actual value( measuring 3488 cm2 for 4645cm2 piece).
Yes you are right i was doubling the sum just forgot the last time I changed for some testing.
No sorry I could not convey correctly. I was talking about the actual machine. That machine take data 78 times rather than 60 times( like how I am doing once at every pulse). So II think i dont need that debouncing code.
I tried to read data twice at each pulse (call interrupt at every CHANGE instead of just at RISING) but could not get better results

saki003:
You are right about edge sensors but I am already getting less value than actual value( measuring 3488 cm2 for 4645cm2 piece).

Are you measuring the "actual" area by hand or are you assuming that the original machine is accurate? Have you tried measuring any simple polygons where the "actual" area is easily calculated? If not, you should do that to see if your result is off by a fixed amount or a fixed factor. Cut leather into three- and four-sided polygons and circles. Calculate the area of each. Measure each with your machine. Put the values in a spreadsheet and graph the actual vs measured line.

johnwasser:
Are you measuring the "actual" area by hand or are you assuming that the original machine is accurate? Have you tried measuring any simple polygons where the "actual" area is easily calculated? If not, you should do that to see if your result is off by a fixed amount or a fixed factor. Cut leather into three- and four-sided polygons and circles. Calculate the area of each. Measure each with your machine. Put the values in a spreadsheet and graph the actual vs measured line.

That is standard 5ft2 round sheet. i also measure square sheets with hand measure and machine measured area. I was getting less values. But your suggestion is good to plot values and see what correction factor can be applied.
But that's one part. I am more worried about non reproduce-ability of results. As I mentioned values change from 3468 to 3540. That's 3% change Atleast values should be in between +-1%

5’2" diameter? That’s 62" or 157.48 cm diameter. The radius would be 78.74 cm. Square that and multiply by Pi to get the area19478 cm^2. Why are you getting 4645 cm^2?

4645 cm^2 is a diameter of 78.90 cm (30.277")

Something does not compute.

You could try running the shift registers on SPI bus and get a major speed boost.
You will be reading bytes, 8 sensors at a time and my guess only – looking for anything > 0 to process edges.

saki003:
I checked with 5 ft2 (4645 cm2) circular sheet. my program was measuring it between 3.73 ft2 (3468 cm2) to 3.81 ft2 (3540 cm2) . So that is inaccurate as well less precise.

One reason may be stray light that hits the sensors near the borders of the sheet from outside the shape. But if the machine uses the same sensor array, this cannot be the reason for the smaller size.

Also make sure that the calculated length (accumulated feeder steps) matches the length of the sheet.

As the next test I'd record the left and right limits of each scan row, for later plotting of the corresponding shape. By comparison with the real values more can be found out about the reasons of the difference.

A possible improvement would fit the sender LED and receiver pairs, so that only straight beams are taken into account. Unfortunately this defeats the use of shift registers, unless inputs are interleaved so that the values of 8 sensors across the entire width go into one shift register, their neighbours into the next shift register. Then you can light the related 8 LEDs and strobe the received signals into the register. This costs one output pin for each component of a register and 8 beams.

128 sensors and 16 shift registers…

If you set the serial speed to 115200 baud, and have a monitor that can display at least 128 characters wide in the serial monitor, you can see a visual representation of what the sensors are detecting by adding a couple of print commands to your code:

int readData() {
  int c = 0, d = 0;
  int i;
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(2);
  digitalWrite(latch, HIGH);
  digitalWrite(led, LOW);  // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
  for (i = 127; i >= 0; i--)
  {
    c = digitalRead(daata);
    if (c == 0)               // check either c 0 or c 1 if(c!=0)
      d++;
    Serial.print(c); //************** display input data (either "1" or "0") ************* 
    digitalWrite(cloc, HIGH);
    delayMicroseconds(10);
    digitalWrite(cloc, LOW);
    delayMicroseconds(10);
  }
  Serial.println(); //********************* end of line ********************* 
  digitalWrite(latch, LOW);
  return d;
}

Serial print can be a speed killer. When you print a number in decimal, it has to be converted and all fit in the output buffer before the next sensor can be read. For very high speed in bursts it's buffer then print when not or between sampling.

Its just barely fast enough for testing purposes at 115200 baud, the input is being read at 60 samples/second, with 128 bits per sample. Allowing 10 bits per character, the serial line should be capable of 192 characters per sample, and overflowing the serial buffer is what would get you in big trouble. I wasn't really worrying about missing a sample period anyway, just thought it would be a quick way to find problems with the sensors themselves.

int readData() {
  int c = 0, d = 0;
  int i;
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(2);
  digitalWrite(latch, HIGH);
  digitalWrite(led, LOW);  // turn the LED on (HIGH is the voltage level)
  digitalWrite(13, LOW);   // turn the LED on (HIGH is the voltage level)
  for (i = 127; i >= 0; i--)
  {
    c = digitalRead(daata);
    if (c == 0)               // check either c 0 or c 1 if(c!=0)
      d++;
    Serial.print(c); //************** display input data (either "1" or "0") ************* 
    digitalWrite(cloc, HIGH);
    delayMicroseconds(10);
    digitalWrite(cloc, LOW);
    delayMicroseconds(10);
  }
  Serial.println(); //********************* end of line ********************* 
  digitalWrite(latch, LOW);
  return d;
}

How many ways to say it?

AVR chips have SPI ports to shift the dingaling bits out and in (SPI is full-duplex) while your code moves the data. SPI default rate is 500000 BYTES/second with go-stop control by the SPI master that makes the clock signal (for SPI bus action, time happens when the SPI clock ticks). Arduino has a good standard SPI library that matches your IDE version.

Use SPI and every char you read is the 8 sensors connected to one of those shift registers. How many holes in a 16 inch width does it take to say cut it there? Unless you want em?

In the code above I see a painful bit by bit read and examination. It's so slow it looks like it has to hurt. Hurts to read. Even the reads use Arduino digitalRead() that takes 5x as long as reading the PINx register directly because it safes the pin first which you can do by setting the mode in DDRx or using Arduino setMode() in setup and never change it -- viola you get a 1-cycle read of the whole port, and picking particular bit(s) out takes a little bitwise logic and works like lightning. When you use bit logic with data from 8 sensors at a time, you only need to process 16 bytes per scan,

you should be able to scan and process 16 bytes in under a millisecond using SPI. Then let the leather roll down for how long to go 2 inches? You could scan 1000 times and still need to wait if you work the bits and SPI.