Hello,
I haven't done much programming with Arduino, compared to my previous projects this one is kind of a major project.
I have one of these DIY Filament extruder ,
I am trying to add Filament puller and filament diameter sensor to create a closed loop system which would give a controlled diameter tolerance. Inspired by Meet the Composer and Precision - Desktop Filament Makers | 3devo
I am using a Digital caliper to measure the diameter. I have written code to read the diameter and send it over to Serial if value is different that the previous one, and use this a s Input to PID, compare it with Setpoint and produce output, that will be used to control the speed of DC motor.
I can read the caliper data(Sometimes there're glitches). I decoded to add a 16x2 LCD so that I can view the measured diameter and in later stage add a rotary encode, so that I could change Kp, Ki, Kd and Setpoint values.
But when added code to display the measured diameter on LCD, both Serial and LCD data are incorrect and changes rapidly.
With out LCD code, Serial terminal displays same reading as shown in Caliper display.
Here's the code,
//Digital caliper code to read the value off of a cheap set of digital calipers
//By Making Stuff Youtube channel https://www.youtube.com/c/makingstuff
//This code is open source and in the public domain.
#include <PID_v1.h>
// include the library code:
#include <LiquidCrystal.h>
//#include <LiquidCrystal_I2C.h>
#define PIN_OUTPUT 5 // To motor driver
//Define Variables we'll be connecting to
double Setpoint, Input, Output;
uint8_t SampleTime = 20;
// PID MIN & MAX output values
#define MIN 50
#define MAX 255
//Specify the links and initial tuning parameters
double Kp = 2, Ki = 5, Kd = 1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 6, en = 7, d4 = 8, d5 = 9, d6 = 10, d7 = 11;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
const byte clockPin = 2; //attach to clock pin on calipers
const byte dataPin = 3; //attach to data pin on calipers
//Milliseconds to wait until starting a new value
//This can be a different value depending on which flavor caliper you are using.
const int cycleTime = 32;
unsigned volatile int clockFlag = 0;
long now = 0;
long lastInterrupt = 0;
long value = 0;
float finalValue = 0;
float previousValue = 0;
int newValue = 0;
int sign = 1;
int currentBit = 1;
uint8_t previousOutput = 0;
void setup() {
Serial.begin(115200);
pinMode(clockPin, INPUT);
pinMode(dataPin, INPUT);
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
//We have to take the value on the RISING edge instead of FALLING
//because it is possible that the first bit will be missed and this
//causes the value to be off by .01mm.
attachInterrupt(digitalPinToInterrupt(clockPin), clockISR, RISING);
//initialize the variables we're linked to
Setpoint = 1.75; // Required diameter of filament
//turn the PID on
myPID.SetSampleTime(SampleTime);
myPID.SetOutputLimits(MIN, MAX);
myPID.SetMode(AUTOMATIC);
}
void loop() {
if (newValue)
{
if (finalValue != previousValue) {
previousValue = finalValue;
Serial.println(finalValue, 2);
}
newValue = 0;
}
//The ISR Can't handle the arduino command millis()
//because it uses interrupts to count. The ISR will
//set the clockFlag and the clockFlag will trigger
//a call the decode routine outside of an ISR.
if (clockFlag == 1)
{
clockFlag = 0;
decode();
}
Input = finalValue;
myPID.Compute();
analogWrite(PIN_OUTPUT, Output);
//lcd.setCursor(0, 1);
/*
lcd.print("F:");
lcd.setCursor(2,1);
lcd.print(finalValue);
*/
}
void decode() {
unsigned char dataIn;
dataIn = digitalRead(dataPin);
now = millis();
if ((now - lastInterrupt) > cycleTime)
{
finalValue = (value * sign) / 100.00;
currentBit = 0;
value = 0;
sign = 1;
newValue = 1;
}
else if (currentBit < 16 )
{
if (dataIn == 0)
{
if (currentBit < 16) {
value |= 1 << currentBit;
}
else if (currentBit == 20) {
sign = -1;
}
}
currentBit++;
}
lastInterrupt = now;
}
void clockISR() {
clockFlag = 1;
}
Even uncommenting
[i]lcd.setCursor(0, 1);[/i]
causes error in reading ?
Why is that?
My doubt is that, delay in LCD functions cause this.
So I thought about using I2C based LCD, but now I think it would be much slower that current one(i2c at 100 KHz).
In attached images,
1.PNG : With out LCD code
2.PNG : with LCD code
Here's some useful links if needed : Reading Digital Calipers This is the code I used. I used BC548 to convert 1.5V from Caliper to 5V
My Caliper data is same as shown in this site(I checked using DSO) : Blog of Wei-Hsiung Huang: Using Digital Caliper For Digital Read Out (DRO) Applications
Also as a doubt, I have seen some people using Stepper motor instead of DC motor, any idea why is that??
Thanks
Arduino_caliper_interrupt_lcd.zip (1.61 KB)