Thanks for the input! Of course I studied lot's of tutorials on how to tune a PID, but...
RodMcM:
The classic response of a well tuned PID loop is oscillations that are initially about a 1/3 of the step change and then successive 1/3 under and overshoots.
Thanks, I will try that! But before I start fiddling with the parameters again I need to understand if generally my approach (as described in my first post) will do...
Power_Broker:
There's no harm in posting it
OK here is the code:
#include <HX711_ADC.h>
#include <HampelFilter.h>
#include <PID_v1.h>
HX711_ADC LoadCell(0, 1);
double Setpoint, Input, Output;
float Kp = 6.5f;
float Ki = 0.1f;
float Kd = 0.9f;
PID myPID(&Input, &Output, &Tune, Kp, Ki, Kd, REVERSE);
double pid_out_limit;
double tension_over_kg = 0.8L;
HampelFilter scaleHampel_slow = HampelFilter(0.00, 15, 0.02); // only odd numbers as window size
HampelFilter scaleHampel_fast = HampelFilter(0.00, 5, 0.02);
bool holdtension;
bool stepper_start_dir;
double stepper_rpm_factor; // for changing stepper speed on the fly
int pid_auto_stop;
bool override_flag_stepper = 0;
int countdown = -1; // this is needed for a stopwatch like function...
double stepper_step_frequency_max = 7000.0L;
double stepper_rpm_factor_old;
// values for driving the stepper: max = pulse frequency, acc = acceleration, and there are slow and fast modes in this project...
double maxT;
int maxT_fast, maxT_slow = 100;
int accT, accT_fast, accT_slow;
elapsedMillis scale_timestamp = 0;
uint64_t scale_interval;
double kilogramm; // tension in Kg
double kilogramm_dec;
double kilogramm_old = 999.9L; // the value is dummy in order to display initial 0Kg
double kilogramm_max;
bool scale_highspeed = 1; // set scale speed mode
void setup() {
myPID.SetSampleTime(30);
myPID.SetMode(AUTOMATIC);
pid_out_limit = stepper_step_frequency_max / maxT_slow;
myPID.SetOutputLimits(-pid_out_limit, pid_out_limit);
}
void loop() {
LoadCell.update(); // update() should be called at least as often as sample rate: >10Hz@10SPS, >80Hz@80SPS
if (scale_timestamp >= scale_interval) {
kilogramm = LoadCell.getData();
if (scale_highspeed == 1) {scaleHampel_fast.write(kilogramm); kilogramm = scaleHampel_fast.readMedian();}
else {scaleHampel_slow.write(kilogramm); kilogramm = scaleHampel_slow.readMedian();}
if (kilogramm < 0) {kilogramm = 0;}
else {
kilogramm_dec = kilogramm;
if (kilogramm_dec > kilogramm_max) {kilogramm_max = kilogramm_dec;}
kilogramm = kilogramm + 0.05;
kilogramm = (int)(kilogramm * 10);
kilogramm = kilogramm / 10;
}
if (kilogramm_old != kilogramm) {
update_display();
kilogramm_old = kilogramm;
}
scale_timestamp = 0;
}
if (holdtension == 1) {hold_tension();}
}
void hold_tension_start() { // if I press a button this will be called
holdtension = 1;
Setpoint = kilogramm_dec;
maxT = round(maxT_slow);
accT = accT_fast;
if (kilogramm_dec > tension_over_kg) {hold_tension();}
}
void hold_tension() {
Input = kilogramm_dec - Setpoint;
if (myPID.Compute()) {
if (override_flag_stepper == 0) {
if (Output < 0) {stepper_start_dir = 0;} else {stepper_start_dir = 1;}
move_stepper(stepper_start_dir);
override_flag_stepper = 1;
}
else {
// char text1[30]; char text2[30]; dtostrf(Input, 10, 10, text1); dtostrf(Output, 10, 10, text2); char text[65]; snprintf(text, 65, "%s,0,%s", text1, text2); debug->println(text);
if (stepper_start_dir == 0) {stepper_rpm_factor = -Output;}
else {stepper_rpm_factor = Output;}
if (countdown <= 0) {if (abs(Input) < 0.1) {pid_auto_stop++;} else {pid_auto_stop = 0;}}
if (pid_auto_stop > 100 || kilogramm_dec < tension_over_kg) {hold_tension_stop();} else {
if (stepper_rpm_factor != stepper_rpm_factor_old) {
stepper_rpm_factor_old = stepper_rpm_factor;
update_stepper_speed(); // can even change dir if value changes sign
}
}
}
}
}
void hold_tension_stop() {
holdtension = 0;
override_flag_stepper = 0;
pid_auto_stop = 0;
stop_stepper(); // stops motor after target tension is reached
}
There are other filters, for example the Exponential Filter.
Also there are similar questions in various forums, but I didn't find much help reading them. The best source I found at Robotics Stack Exchange.