2

I am reading a TSL1402R with an Arduino Mega2560. The code is based on the sketch from the arduino playground here:http://playground.arduino.cc/Main/TSL1402R

The application is a digital caliper for moving strands of filament. I would like to have the scan rate as fast as possible. I am making my own filament and need some means of quality control.

I am reading the analog values of each photodiode (256) of the sensor to an array. I find an average value of 25 reads for each of the diodes and place that in another array. I then I compare the averaged values for each of the 256 diodes and assign them into 3 groups: dark1, dark2 and dark3 I then count the assigned values and get a total. +1/4 for dark1, 1/2 for dark2 and 1 for dark3. This figure represents the width of a piece of filament casting the shadow on the sensor.(dark1 is partially blocked photodiode, dark2 is 1/2 blocked, dark3 is fully blocked)

I am looking at the clock pin on the sensor with a scope. When I output data with serialprint at (any speed) 115200 The program speed slows down considerably. When I change the program to serialprint only if the previous value changes, it gets even slower. If I serialprint every time through the loop, the buffer fills and the values are not accurate.

I get accurate data from my program. What is the most efficient way to get it out and into a usable form? By way of form I mean to have the data saved so I can see the size deviation of the filament I am producing. It would also be great if I could visualize the data in real time and make adjustments during the extrusion process.

I have been researching this for weeks, tweaking the program and trying different ideas based on responses to questions similar to mine.

My background is industrial electrical systems, not programming. This is my first attempt at something like this. Any advice would be greatly appreciated.

Thanks to all in advance, Dave Stewart, aka bigstew123

#include <EEPROM.h>
#include <TimerOne.h>
#define NPIXELS 255  // No. of pixels in array

// Define various ADC prescaler:
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

const byte PWMDAC1pin = 11; // PWM DAC, only pins 9 and 10 are allowed
const byte period = 128; // for 10 bit DAC

const int LEDpin = 8;
const int CLKpin = 3;    // <-- Arduino pin delivering the clock pulses to      pin 3 (CLK) of the TSL1401
const int SIpin = 4;     // <-- Arduino pin delivering the SI (serial-input) pulse to pin 2 of the TSL1401
const int AOpin = 1;    // <-- Arduino pin connected to pin 4 (analog output 1)of the TSL1401

unsigned int intArray[NPIXELS]; // <-- the array where the readout of the photodiodes is stored, as integers

int nAggr = 5;        // image averaging count per one scan. should not exceed 10
int timer = 5;        // value output averaging counter
int sensor_value = 0;
int sensor_value_1 = 0;
int sensor_value_2 = 0;
int sensor_value_3 = 0;
float sensor_value_mapped = 0;
float dark_pixels_1 = 0;
float dark_pixels_2 = 0;
float dark_pixels_3 = 0;
float dark_pixels_total = 0;
float dark_pixels_avg = 0;
float width_mm = 0;
float width_mm_old = 0;

// default filament width
double lowpassValue = 1.75;
double lowpassFactor = 0.5;

double calibFactor =  15.75; // (default pixel per mm = 15.748 for 400dpi     sensor

boolean debugMessage = false;
boolean doCalibration = false;

int timerCounter = 0;
double timerValue = 0;


void setup() {
// To set up the ADC, first remove bits set by Arduino library, then choose
// a prescaler: PS_16, PS_32, PS_64 or PS_128:
    ADCSRA &= ~PS_128;
    ADCSRA |= PS_32; // <-- Using PS_32 makes a single ADC conversion take ~30 us
    pinMode(PWMDAC1pin, OUTPUT);
// Timer1.initialize(period);
    Timer1.initialize(40);
// Next, assert default setting:
    analogReference(DEFAULT);

// Set all IO pins low:
    for (int i = 0; i < 14; i++) {
        digitalWrite(i, LOW);
    }

    pinMode(LEDpin, OUTPUT);
    initSensor();
    Serial.begin(115200);
//Serial.begin(9600);
}


void loop() {
    Timer1.pwm(PWMDAC1pin, (dark_pixels_avg));
    sensor_value = 750; //this is the 0-1023 value for the light/dark threshold
    sensor_value_mapped = sensor_value;
    sensor_value_1 = sensor_value_mapped;
    sensor_value_2 = sensor_value_mapped * 75 / 100;//this is 3/4/
    sensor_value_3 = sensor_value_mapped * 65 / 100; //this is 1/2
    delay(50);
    scanSensor();
    MATH();
    delay(50);
    /*
     *   testing code here: if the value is different, serial print with 100 delay, if the value is unchanged, update at 1000
     *   this is code I used to try to plot the values to a python script running on a raspberry pi 2b
     *   with this setup, the program slows and the scan rate is so slow I miss deviations in the filament.
     *
     if
     (width_mm != width_mm_old)
     {
     Serial.println (width_mm, 4);
     delay(100);

     }
     else
     {Serial.println (width_mm_old, 4);
     delay(1000);

     }
     */
// every scan, print the width
    Serial.println(width_mm, 4);

// Command processor
    if (Serial.available() > 0) {
        char incomingByte = Serial.read();

        switch (incomingByte) {
            case 'd':    // Debugging message toggle
                debugMessage = !debugMessage;
                break;

            case 'c':    // Calibration
                doCalibration = true;
                break;

            case 'h':
                //helpMessage();
                array_value();
                break;
        }
    }

    if (debugMessage) {
        //   Serial.print("Number of dark pixels       ");
        //   Serial.println(dark_pixels);
        // delay(300);
        Serial.print("Dark pixel average          ");
        Serial.println(dark_pixels_avg, 4);
        Serial.print("Dark pixel 1                ");
        Serial.println(dark_pixels_1);
        Serial.print("Dark pixel 2                ");
        Serial.println(dark_pixels_2);
        Serial.print("Dark pixel 3                ");
        Serial.println(dark_pixels_3);
        Serial.print("dark_pixels_total             ");
        Serial.println(dark_pixels_total);
        Serial.print("filament width in mm       ");
        Serial.println(width_mm, 4);
        //  Serial.print ("sensor pot value          ");
        // Serial.println (sensor_value);
        //  Serial.print ("sensor value mapped        ");
        //   Serial.println (sensor_value_mapped);
        delay(200);
        //  Serial.print("Raw:\t");
//    printDouble(lowpassValue, 4);
//   Serial.print("\t(mm)=\t");
//    printDouble(mmValue, 3);
//   Serial.println();
//Serial.println(intArray[i]);//////////////////////////////////////////
//Serial.print(";");
    }

    width_mm_old = width_mm;
}

void initSensor() {
// Initialize two Arduino pins as digital output:
    pinMode(CLKpin, OUTPUT);
    pinMode(SIpin, OUTPUT);

// Clock out any existing SI pulse through the ccd register:
    for (int i = 0; i < NPIXELS + 4; i++) {
        ClockPulse();
    }

// Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

    for (int i = 0; i < NPIXELS + 4; i++) {
        ClockPulse();
    }
}


void scanSensor() {
    // Stop the ongoing integration of light quanta from each photodiode by  clocking in a
    // SI pulse:
    // Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

    // Next, a new measuring cycle is starting once 18 clock pulses have passed. At
    // that time, the photodiodes are once again active. We clock out the SI pulse through
    // the NPIXELS bit register in order to be ready to halt the ongoing measurement at our will
    // (by clocking in a new SI pulse):
    for (int i = 0; i < NPIXELS + 4; i++) {
        if (i == 18) {
            // Now the photodiodes goes active..
            // An external trigger can be placed here
        }

        ClockPulse();
    }

    // The integration time of the current program / measurement cycle is ~2ms. If a larger time
// of integration is wanted, uncomment the next line:
//delay(1);
// Stop the ongoing integration of light quanta from each photodiode by clocking in a SI pulse
// into the sensors register:
// Create a new SI pulse and clock out that same SI pulse through the sensor register:
    digitalWrite(SIpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    delayMicroseconds(1);
    digitalWrite(SIpin, LOW);
    delayMicroseconds(1);
    digitalWrite(CLKpin, LOW);

// Next, read all 256 pixels in parallell. Store the result in the array. Each clock pulse
// causes a new pixel to expose its value on the two outputs:
    for (int i = 0; i < NPIXELS; i++) {
        delayMicroseconds(2);// <-- We add a delay to stabilize the AO output from the sensor
        intArray[i] = analogRead(AOpin);    //(AOpin);
        ClockPulse();
    }
}
//here we have a sensor value that is an integer number between 0 and 1023 to represent the value of the pixels read in intArray[]
//  the number varies, so really dark pixels are set at 75, medium at 100, and light at 125....  of course, this will be a % and scaled
//so when the operator adjusts the sensitivity, each value will adjust accordingly.
// each function only counts the pixels in its range so there is no overlapp
//for a sensor value of 200, sensor value 1 will be 200, value 2 will be 150 and value 3 will be 100
////////////////////////////////////////really dark///////////////////

void MATH() {
    int x = 0;
    int y0 = 0;
    int y1 = 0;
    int y2 = 0;
    int y3 = 0;
    float dpa = 0;

    for (int i = 0; i < NPIXELS; i++) {
        x = intArray[i];

        if (x <= sensor_value_1 && x >= sensor_value_2 && x >=  sensor_value_3) { //less than 200, but greater than 150 and 100
            y1 = y1 + 1;   //////////////////////////////////////not very dark/////////////////////////
        }

        if (x <= sensor_value_1 && x <= sensor_value_2 && x >= sensor_value_3) { //less than 200, less than 150, but more than 100
            y2 = y2 + 1;   //////////////////////////////////////medium dark////////////////////////
        }

        if (x <= sensor_value_1 && x <= sensor_value_2 && x <= sensor_value_3) { //less than 200 or 150 or 100 (really dark pixel(low intArray value)
            y3 = y3 + 1;   //////////////////////////////////////very dark/////////////////////////
        }
    }

    dark_pixels_1 = y1 * 25 / 100; ///1/4 of a count for each pixel
    dark_pixels_2 = y2 * 50 / 100; // half a count for each pixel
    dark_pixels_3 = y3; // full count for each pixel
/////////////////////////add up the totals///////////////////////////////
    dark_pixels_total = dark_pixels_3 + dark_pixels_2 + dark_pixels_1;

    for (int q = 0; q < 25; q++) {
        dpa  += dark_pixels_total;
    }

    dark_pixels_avg = dpa / 25;
    float k = 0;
    k =  map(dark_pixels_avg, 50, 97, 157, 313); //map the values to a known     width and convert to mm
    width_mm = k / 100;
    //
    //   Serial.print("Number of dark pixels       ");
    //   Serial.println(dark_pixels);
    // delay(300);
    //Serial.print("Dark pixel average          ");
    // Serial.println(dark_pixels_avg);
    // Serial.print("Dark pixel 1                ");
    // Serial.println(dark_pixels_1);
    // Serial.print("Dark pixel 2                ");
    //  Serial.println(dark_pixels_2);
    //  Serial.print("Dark pixel 3                ");
    //  Serial.println(dark_pixels_3);
    //  Serial.print("dark_pixels_avg             ");
    //  Serial.println(dark_pixels_avg);
    //  Serial.print ("filament width in mm       ");
    //  Serial.println (width_mm, 4);
    //   Serial.print ("sensor pot value          ");
    //   Serial.println (sensor_value);
    //   Serial.print ("sensor value mapped        ");
//    Serial.println (sensor_value_mapped);
//    delay(200);
}

// This function generates an outgoing clock pulse from the Arduino digital pin 'CLKpin'. This clock
// pulse is fed into pin 3 of the linear sensor:
void ClockPulse() {
    delayMicroseconds(1);
    digitalWrite(CLKpin, HIGH);
    digitalWrite(CLKpin, LOW);
}

void array_value() {
    for (int i = 0; i < NPIXELS; i++) {
        Serial.print("ARRAY VALUE");
        Serial.print(i);
        Serial.print("\t");
        Serial.println(intArray[i]);
    }
}

closed as unclear what you're asking by Chris Stratton, KIIV, rebatoma, Dat Ha, Code Gorilla Nov 18 '16 at 13:07

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • Unfortunately this is not answerable without details of the program. Either you are keeping the serial port busy, and that is the limitation, or you have another part of the program which is necessarily time consuming, or you have a program mistake which makes something take far longer than it should. – Chris Stratton Nov 16 '16 at 16:08
  • I posted the code. Not pretty, I see now there are remnants of things I have tried and since removed. I hope you can make some sense of it. Thanks for your efforts. – bigstew123 Nov 16 '16 at 16:53
  • 1
    How often do you need this loop to run? At a quick and dirty count of the output (230 characters or so), at 115200 baud (11520 char/sec), the output needs 20 ms, meaning the loop can't run any faster than 50 hz or it will be held up waiting for the the output buffer to clear. You could gain some speed by formatting your (currently 6) output values into a single line, comma-separated, and without the text labels. But ultimately you need to calculate what rate you need and adjust the output quantity and speed to be compatible. – JRobert Nov 17 '16 at 0:46
  • I am trying to check filament diameter as it is wound from a master spool onto a standard 2.2kg spool. I have the sensor enclosed in a box with a line laser diode aimed at it. When the filament blocks the laser, the photodiodes on the sensor drop their analog output value to about 20% of the fully illuminated value. It takes 256 analog reads to complete a full scan of the diodes on the sensor. Sometimes there are defects in my filament that are about an inch long. I would like to capture the defect while winding the filament as fast as possible. – bigstew123 Nov 17 '16 at 1:16
  • My previous best guess was that I was reading about 5 complete scans per second. At 50 feet per minute spool rate, that is 600 inches per minute or 10 inches per second going past the sensor. If I only read 5 scans per second, that is one scan for every two inches of filament. A deviation caused a blob about 1.75 inches long at 4mm diameter (target is 2.85mm filament diameter). My setup missed the blob, and that is what has prompted me to post here and try and sort it out. The Serial.print lines are for debugging, I only output the width_mm value. – bigstew123 Nov 17 '16 at 1:23