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]);
}
}