Inconsistent Power Scaling with Arduino Control

Discuss roast levels and profiles for espresso, equipment for roasting coffee.
marcism

#1: Post by marcism »

Hey all,

I've got a pretty interesting problem that is leading to some less than ideal roasts. I recently started doing manual control of my popper that is connected via arduino to artisan and all controlled via the MODBUS protocol. I have set up custom buttons that give me incremental control over the Power slider, which in turns is talking via MODBUS to the roaster to control its heater. It works fine and I have 2 MAX6675 thermocouples on temp reading duty for ET and BT. Thermocouples are placed correctly.

What happens is when I get to the upper limit of my power (the nature of the beast it seems with my popper) and make the change from 98 (out of 100 Power) to 99 Power. The ET shoots up (meaning the roaster is kicking in a bunch more power from the heater) and I lose the control I need over that part of my roast to keep the RoR stable.

A picture tells a thousand words:


And my Modbus slider command:


Anyone got a thought as to what is going on here and if there's a way to have proper incremental control over the heater? It just seems as if my roaster is saving a good amount of potential power for the last two steps of its Power control. If it's mechanical then that's a shame, but if it's in the code then perhaps there's a hope to fix it!

Thanks again!

Marc

P.S. Here's the Arduino sketch that I'm using:
// this example is public domain. enjoy!
// www.ladyada.net/learn/sensors/thermocouple

#include <max6675.h>
#include <ModbusRtu.h>

// data array for modbus network sharing
uint16_t au16data[16] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1 };

/**
 *  Modbus object declaration
 *  u8id : node id = 0 for master, = 1..247 for slave
 *  u8serno : serial port (use 0 for Serial)
 *  u8txenpin : 0 for RS-232 and USB-FTDI 
 *               or any pin number > 1 for RS-485
 */
Modbus slave(1,0,0); // this is slave @1 and RS-232 or USB-FTDI



//Thermocouple 1
int thermoDO = 2;
int thermoCS = 3;
int thermoCLK = 4;

//Thermocouple 2
int thermoDO2 = 5; // Add a 2 to each int from first Thermocouple. Ex(ThermoDO to ThermoDO2).
int thermoCS2 = 6; // Change pins to the ones you use for your board. Can be any digital pins.
int thermoCLK2 = 7;

MAX6675 thermocouple2(thermoCLK, thermoCS, thermoDO);

MAX6675 thermocouple(thermoCLK2, thermoCS2, thermoDO2); //Thermocouple 2
  
int led = 9;  
  
void setup() {
  slave.begin( 19200 ); // 19200 baud, 8-bits, none, 1-bit stop
  // use Arduino pins 
  pinMode(led, OUTPUT);
 delay(500);
  
}

void loop() {
  // basic readout test, just print the current temp
  
   //Serial.print("C = "); 
   
   au16data[2] = (uint16_t) (thermocouple.readCelsius()*100); 
   
   au16data[3] = (uint16_t) (thermocouple2.readCelsius()*100);
   
   slave.poll( au16data, 16 );

   for(int i=1; i<=99; i++) {
    if(i<=au16data[4])
      digitalWrite(led, HIGH);
    else
      digitalWrite(led, LOW);
    
    delay(5);
   }
   
}

ira
Supporter ♡

#2: Post by ira »

Unless I'm completely missing something, there's nothing in that sketch having anything to do with controlling the power output.

Ira

Espresso Vision: the perfect cup of coffee starts with understanding your roast
Sponsored by Espresso Vision
User avatar
Qporzk

#3: Post by Qporzk »

I believe this part of the sketch is the power control:

for(int i=1; i<=99; i++) {
if(i<=au16data[4])
digitalWrite(led, HIGH);
else
digitalWrite(led, LOW);

delay(5);
}

I'd assume that most of your actual control range is in the last 10% of your power, so small changes like 98 to 99 are leading to much bigger relative changes. You should be able to massage this loop to have more granular control in this last range, but you would probably have to sacrifice the lower range of control. Maybe something like this:

for(int i=1; i<=99; i++) {
int n=(((100-au16data[4])/2)+au16data[4]);
if(i<=n)
digitalWrite(led, HIGH);
else
digitalWrite(led, LOW);

delay(5);
}

Keep in mind that I haven't used C++ in a while, so you'll probably need to be careful with the types in that calculation.

marcism (original poster)

#4: Post by marcism (original poster) » replying to Qporzk »

This is really helpful and I'll give it a try tomorrow when I get a shot. My question is: what decides where the control range is? Does it come from the code or from the mechanics of the popper itself?

User avatar
yakster
Supporter ♡

#5: Post by yakster »

If the actual power increases exponentially, maybe you could use a log function to compensate so that changes near 100% have less effect.

Maybe use a kill-a-watt to map the delta power for an incremental change across the span.
-Chris

LMWDP # 272

ira
Supporter ♡

#6: Post by ira »

Also, depending on the loop speed and if you're trying to PWM an AC signal, there might be some non-linearity. Properly in that case you'd like a zero-crossing detector and then control power by delaying turn on till the next crossing event turns it off again. You could also try changing the wait(5) to wait(1000) or even wait(10000) which will mitigate most of that problem. Arduino seems to indicate that Wait() has been deprecated and should be replaced with Delay(). Or you can change to code to use this idea, https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay which doesn't pause execution of the code.

Ira

btreichel

#7: Post by btreichel »

Have you taken into account that with zero crossing and firing a pwn to turn on power, that the power is non-linear. AKA 0 to 30 is almost no power, past 70% it also hardly matters.

Baratza: skilled in the art of grinding
Sponsored by Baratza
marcism (original poster)

#8: Post by marcism (original poster) »

yakster wrote:If the actual power increases exponentially, maybe you could use a log function to compensate so that changes near 100% have less effect.

Maybe use a kill-a-watt to map the delta power for an incremental change across the span.
I think you're spot on with the Kill-a-watt idea to get a really accurate picture of what is going on here. Will pick one up today.
btreichel wrote:Have you taken into account that with zero crossing and firing a pwn to turn on power, that the power is non-linear. AKA 0 to 30 is almost no power, past 70% it also hardly matters.
Is there a zero-cross involved? Currently all I have is the Arduino Uno connected to the SSR and that to the heater.

I also found this post on reddit and tested their code changes, but it didn't work. I also don't have a MOSFET connected in my circuit as I could never get it to fire properly.

User avatar
Qporzk

#9: Post by Qporzk »

Ira, I think increasing the delay will cause issues. As I understand the loop, it loops through from 0 to 99, and if the count is above the set power level in artisan it will leave the heater off, and if the count is below the set value it turns the heater on, then waits for the delay time, essentially making a PWM signal with a 500ms period. Increasing the delay to 1000ms will make the period almost 2 minutes, which won't give enough control.

marcism (original poster)

#10: Post by marcism (original poster) » replying to Qporzk »

Oh wow! I honestly have a miniscule amount of experience with coding and it's really interesting to see what's happening here. This comment also explains your earlier code change a lot. Thanks for your really helpful input.

I'll be testing your code change tonight and will report back.