Temperature Set Point / Motor Speed help

Hi, complete newbie here. Sorry for any mistakes/missing information, please update me and I will include it. I don't really remember/know much about PID usage either, sorry about that.

Currently, I amm referencing the filament extrusion machine code from Electronoobs at: Electronoobs Video.

If I missed out on providing any basic details, perhaps some of these details can be found here on his blog at:
Electronoobs Blog

I have assembled the PCB along with corresponding hardware and am currently using the hardware as follows:
Arduino Nano
Nema 17 Motor
12V 40W heating element and thermistor
LCD display
12V 5A power supply
Just one single push button, Button 1 that starts/stops the motor

I do NOT have the potentiometer soldered on top of the Arduino, I do not trust my soldering skills for this task.

I am facing two problems:

  1. The motor appears to be rotating very slowly, supposedly due to the lines of code governing the LCD behavior. If I use a 250ms delay, then it takes 4 steps per second, once every 0.25s. Currently, I am using a 100ms delay at "800 rpm", but it is still terribly slow. Is my understanding even correct here?

  2. The temperature set point for the heating element and thermistor pair does not appear to work. I set the setpoint to 220C, it heated up to 240C and showed no signs of stopping. I have no idea what is causing this. Is it simply unsuitable PID constants?

I would like to:

  1. set the motor to run at a specific speed which I can have greater control over
  2. set the heating element to reach towards and maintain temperature at the point I set.

Please, any insight or guidance at all would be very valuable. Please advise, and thank you very much.

The code I am using is pasted as follows:

//LCD config
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);  //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

//Thermistor needed libraries
#include <thermistor.h>           //Download it here: https://electronoobs.com/eng_arduino_thermistor.php
thermistor therm1(A0,0);          //Connect thermistor on A0, 0 represents TEMP_SENSOR_0 ( configuration.h for more)


//I/O
int PWM_pin = 5;                  //Pin for PWM signal to the MOSFET driver (the BJT npn with pullup)
int speed_pot = A1;
int but1 = 7;
int EN = 2;
int STEP = 3;
int DIR = 4;
int LED = 13;

//Variables
float set_temperature = 210;            //Default temperature setpoint. Leave it 0 and control it with rotary encoder
float temperature_read = 0.0;
float PID_error = 0;
float previous_error = 0;
float elapsedTime, Time, timePrev;
float PID_value = 0;
int button_pressed = 0;
int menu_activated=0;
float last_set_temperature = 0;
int max_PWM = 255;

//Stepper Variables
int max_speed = 1000;
int main_speed = 0;
bool but1_state = true;
bool activate_stepper = false;
int rotating_speed = 0;



#include <AccelStepper.h>
// Define a stepper and the pins it will use
AccelStepper stepper1(1, STEP, DIR); // (Type of driver: with 2 pins, STEP, DIR)

//PID constants
//////////////////////////////////////////////////////////
int kp = 90;   int ki = 30;   int kd = 80;
//////////////////////////////////////////////////////////

int PID_p = 0;    int PID_i = 0;    int PID_d = 0;
float last_kp = 0;
float last_ki = 0;
float last_kd = 0;

int PID_values_fixed =0;



void setup() {  
  pinMode(EN, OUTPUT);
  digitalWrite(EN, HIGH);     //Stepper driver is disbled
  stepper1.setMaxSpeed(max_speed);  
  pinMode(but1, INPUT_PULLUP);
  pinMode(speed_pot, INPUT);
  pinMode(LED, OUTPUT);
  digitalWrite(LED, LOW);
  
  pinMode(PWM_pin,OUTPUT);
  TCCR0B = TCCR0B & B11111000 | B00000010;    // D6 adn D6 PWM frequency of 7812.50 Hz
  Time = millis();

  TCCR1A = 0;             //Reset entire TCCR1A register
  TCCR1B = 0;             //Reset entire TCCR1B register
  TCCR1A |= B00000010;    //   /8
  TCNT1 = 0;              //Reset Timer 1 value to 0
  
  lcd.init();
  lcd.backlight();
}

void loop() {
  if(!digitalRead(but1) && but1_state){
    but1_state = false;
    activate_stepper = !activate_stepper;
    delay(10);
  }
  else if(digitalRead(but1) && !but1_state){
    but1_state = true;
  }
  
  if(activate_stepper){
    digitalWrite(LED, HIGH);
    digitalWrite(EN, LOW);    //We activate stepper driver
    rotating_speed = 800;
    stepper1.setSpeed(800);
    stepper1.runSpeed();
  }
  else

  {
    digitalWrite(EN, HIGH);    //We deactivate stepper driver
    digitalWrite(LED, LOW);
    stepper1.setSpeed(0);
    stepper1.runSpeed();
  }
  
  // First we read the real value of temperature
  temperature_read = therm1.analog2temp(); // read temperature
  
  //Next we calculate the error between the setpoint and the real value
  PID_error = set_temperature - temperature_read + 6;
  //Calculate the P value
  PID_p = 0.01*kp * PID_error;
  //Calculate the I value in a range on +-6
  PID_i = 0.01*PID_i + (ki * PID_error);
  
  
  //For derivative we need real time to calculate speed change rate
  timePrev = Time;                            // the previous time is stored before the actual time read
  Time = millis();                            // actual time read
  elapsedTime = (Time - timePrev) / 1000; 
  //Now we can calculate the D calue
  PID_d = 0.01*kd*((PID_error - previous_error)/elapsedTime);
  //Final total PID value is the sum of P + I + D
  PID_value = PID_p + PID_i + PID_d;

  
  //We define PWM range between 0 and 255
  if(PID_value < 0){
    PID_value = 0;
  }
  if(PID_value > max_PWM){
    PID_value = max_PWM;
  }
  
  //Now we can write the PWM signal to the mosfet on digital pin D5
  analogWrite(PWM_pin,PID_value);
  previous_error = PID_error;     //Remember to store the previous error for next loop.
  
  delay(100); //Refresh rate + delay of LCD print
  lcd.clear();
  
  lcd.setCursor(0,0);
  lcd.print("T: ");  
  lcd.print(temperature_read,1);
  lcd.print(" S: ");  
  lcd.print(rotating_speed);
  
  lcd.setCursor(0,1);
  lcd.print("PID: ");
  lcd.print(PID_value);
 
}//Void loop end


ISR(TIMER1_COMPA_vect){
  TCNT1  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  stepper1.runSpeed();
}

You could remove that delay entirely and see what happens.

Then you could write it so the LCD is updated every 100 milliseconds without using delay:

  static unsigned long lastLCDTime;

  if (millis() - lastLCDTime > 100) {

// do the display stuff here and

    lastLCDTime = millis();    // remember when
  }

There's a 10 millisecond delay in your button handling that does not need to be there, or at least it does not have to mean halting all other operations for 10 milliseconds. That may matter less as you are not all time pressing the button.

I don't know the motor calls at all. It looks like you set speed and tell it to run, so I don't see why it does not, never mind the 100 ms (or whatever) delay limiting loop frequency to 10 Hz max.

a7

2 Likes

Could be something in your wiring and circuit diagram which you did not post.

1 Like

Hi. I am using this wiring screenshot as a reference, with the PCB layer screenshot here.

My own soldered PCB is shown here. It's an older picture, I can grab something more recent if you need but nothing has really changed aside from both LEDs now being lit up. The middle left on one of the MOSFETs were not soldered properly, but now it has been fixed. Also, a heat sink has been attached. The heating element is working really well, shooting past 240C when I only set 220. There's also a wire soldered in place of the "starting switch" that was supposed to be used in the design, at AWG 20. Shouldn't be an issue. Also, there are two wires for button 1 not shown in this diagram. I should really get a better picture, I'll do it later today. Sorry!

Also, my header pins for the stepper motor broke off, so I soldered 4x Male to Male Dupont jumper wires to the slots in the PCB. Possibly not my best move, seller just told me yesterday they each carry <1A current. However, I will try the code as mentioned be alto777 first, hopefully that resolves the motor speed issue. Also, other people not having my header pin issue have reported the same problem with the motor speed, so I am inclined to think it is a problem with the code.

The only major difference I could find between my PCB/wiring and the reference is the lack of a potentiometer soldered to 3 pins on the Arduino Nano which allows manual change in motor speed. Instead, my motor speed is fixed to a constant value within the code.

Sorry for not having better pictures, some of these are snapshots I took from the reference's Youtube videos, which are what I have working off of as well.

Thank you so much! I will try using your suggested code later today. If it helps resolve the motor speed issue, that alone will be a lot of help. I will update regarding the motor speed back here once I have tried out the new code. Thanks a ton!

Ah, sorry. I forgot to mention this, but the PID value displayed on the LCD starts at 255 and never changes. This is partially why I suspect something is either wrong in the PID code used for the temperature setpoint, or with the P, I and D constants listed in the original code. According to the video, the PID value is supposed to decrease as temperature goes towards the setpoint.

I will check this again later today to confirm, but still would appreciate any input or guidance anyone has. Please, and thank you!

@alto777 Thank you very much, the code you provided works like a charm for the motor speed. I set RPM down to 40 and it's already much faster than the previous setup at 800 rpm. Removing the delay and implementing the code you provided solved the motor speed problem entirely, from what I see.

Thank you so much!!

Now my current best guess for the temperature setpoint deviation is unsuitable values for kp, ki and kd. Even using the original reference values of 200C set point and the provided kp, ki and kd values, the temperature continues to rise above 200C even after the shown PID value is at 0.

If anyone could check over my interpretation and provide any feedback, it would be greatly appreciated. Sorry for the trouble, and thank you.

what exact variable has value 0?
WIthout naming this It is unclear what the function of this value is

if the temperature is still rising this might be a problem that your circuitry is wrong.
Depending on the "value" you mentioned that has value 0 but temperature is still rising the reason might be that your wiring is wrong so the heater is switched on permanently.

If this is the case depends on the details described above.

Hi @StefanL38, thank you for chipping in.

According to the code below,

lcd.clear();
  
  lcd.setCursor(0,0);
  lcd.print("T: ");  
  lcd.print(temperature_read,1);
  lcd.print(" S: ");  
  lcd.print(rotating_speed);
  
  lcd.setCursor(0,1);
  lcd.print("PID: ");
  lcd.print(PID_value);
    lastLCDTime = millis();    // remember when
  }

The only values I can see on the LCD are temperature, rotating speed and the PID value. In this case, when the displayed temperature is near the set point, the displayed PID value goes to 0. However, the temperature continues to rise. This is what I was referring to in my previous post.

I do not know how to edit the code to individually display each P, I and D value. Sorry, I honestly have no real experience with Arduino, this is my first project. I am using a PCB for the circuitry as provided by Electronoobs, but it is definitely possible that I might have made a mistake somewhere with connections, especially with the shoddy soldering I did.

Please advise, thank you.

Actually, I looked back at the reference and you have a great point. I need to change my circuitry a bit, will get back asap. So sorry for the confusion, will update as soon as I can.

The most important advice is: provide detailed information.
post a HIGH-resolution picture of the lower-side of the PCB.
So the soldering can be reviewed very carefully.

Provide information if you use the real absolut exact same type of components that the creator uses.

Provide what kind of measurement equipment to you have?

  • Do you have an oscilloscope?
  • Do you have a digital multimeter?
    • can the digital multimeter measure duty-cycle and frequency?
  • Do you have a second microcontroller?

A better way to view a lot of different variables and their values is to add serial printing to your code.

You should post your actual complete sketch new

1 Like

@andrewyap I can't help with the PID stuff other than generally. As @StefanL38 is pointing out, you need to look closely at the code to see what is happening exactly.

Tools for that can be useful, techniques which rely on things you already have available can be helpful if not fully adequate.

Add

  Serial.begin(115200);

to your setup() and use Serial.print() and/or Serial.println() liberally to see the values of key variables and verify that the program flow is what you think.

Now that button:

  if(!digitalRead(but1) && but1_state){
    but1_state = false;
    activate_stepper = !activate_stepper;
    delay(10);
  }
  else if(digitalRead(but1) && !but1_state){
    but1_state = true;
  }

That code may be working for you, but it is flawed and would not always be good enough. You may have had a few surprises already, or somehow the rest of your code masks the flaw.

One small change, viz:

  bool but1_reading = digitalRead(but1);

  if (!but1_reading && but1_state) {
    but1_state = false;
    activate_stepper = !activate_stepper;
    delay(10);
  }
  else if (but1_reading && !but1_state) {
    but1_state = true;
    delay(10);    // need to denounce both edges!
  }

fixes it for all deployment scenarios, at least as long as your switches only bounce for 10 milliseconds. Most do better; I have some crappy arcade style big pushbuttons that bounce so bad I have to use 30 milliseconds for 100 percent reliably detecting a single press or release.

So you still get a 10 ms hit of no nothing happening each time you press, and release, the swtich.

I also digitalRead() the button but once - this is important sometimes, as a subsequent reading even a few microseconds later will be different. By reading once, the real of the logic is based on a snapshot of the external conditions.

Say if those occasional 10 millisecond halts to all progress is significant and a problem and I will post an adjustment that eliminates delay() in that code.

a7

1 Like

Apologies for the delay in response, had a hectic few days. I took another look at my circuitry and @StefanL38 was right. The heating element was indeed connected to the wrong terminal. Now that I have fixed that error, it is able to maintain a steady temperature range of +-3 degrees C without any change to the code or PID values. My mistake there, sorry for the confusion.

With @alto777's excellent help with the code sections, the motor speed is also functioning exactly as I need it to as well. Button 1 has yet to give me any problems, but I am very grateful for the suggested change and will keep it in my back pocket as I continue testing my setup.

For now, as far as I can tell, the code and electronics are fully functional. So sorry for all the trouble and confusion, and thank you all so much for your help with my project.

No problem. No reason to apologise.
Solving problems is always done by analysing the real situation. As sooner as somebody can release assumptions "the bug must be there" the more open minded this person will be and the faster the real (and in most cases) unexpected reason can be found.

The main function of a forum like the arduino-forum is to get help from people with experience that can ask for certain details and make suggestions based on these details what the reason might be.

The more details that are described the better conclusions can be made what the reason can be that is causing the malfunction.

And as hardware is a very natural part of each microcontroller-project the reason might well be the hardware.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.