Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Made changes to enable high power output #5

Draft
wants to merge 14 commits into
base: master
Choose a base branch
from
52 changes: 47 additions & 5 deletions src/heating.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "board/adc.hpp"
#include "lib/pid.hpp"
#include "preset.hpp"
#include "settings.hpp" // needed to read high power setting

/** Class for controlling heating and measuring cycle
*/
Expand All @@ -16,14 +17,17 @@ class Heating {
static const int PID_K_PROPORTIONAL = 450;
static const int PID_K_INTEGRAL = 1000;
static const int PID_K_DERIVATE = 50;
static const int HEATING_POWER_MAX_MW = 40 * 1000; // mW
// static const int HEATING_POWER_MAX_MW = 40 * 1000; // mW
static const int IDLE_MIN_TIME_MS = 3; // ms
static const int STABILIZE_TIME_MS = 2; // ms
static const int HEATING_MIN_POWER_MW = 100; // mW
static const int TIP_MAX_CURRENT_MA = 9000; // mA
static const int SUPPLY_VOLTAGE_HEATING_MIN_MV = 4300; // mV
static const int SUPPLY_VOLTAGE_MAX_MV = 18000; // mV
static const int TIP_RESISTANCE_SHORTED_MO = 500; // mOhm
static const int RTM_TIP_RESISTANCE_MIN_MO = 1500 // mOhm
static const int RTM_TIP_RESISTANCE_MAX_MO = 2500 // mOhm
static const int RTU_TIP_RESISTANCE_MAX_MO = 4000 // mOhm
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RTU tip has normally 3.5ohm, it is OK if upper limit is 4ohm, but i suggest to set also MIN for RTU, to warn, or make fallback switch to RTM if there will be something less than 2.5ohm

in general it is possible to automatically select the right tip with resistance measurement

what is your opinion?
because if you select high power and then you insert RTM then you immediately broke it.

so option one: write message that is 'shorted' or fallback to RTM power limit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, there is a max resistance for the RTM tips. So the logic checks whether it is between min and max of the RTM (1.5 - 2.5 ohm). Then it is RTM. If it is below 1.5 ohm then it is "low resistance" and essentially an error state of some sort. If it is over 2.5 ohm, we can assume it is RTU, so it sets RTU, UNLESS it is higher than the RTU max (4 ohm) in which case we call it "high resistance" which I understand to also be an error state.

If we added an RTU minimum, then the only new functionality it would allow is to detect an error state in between the two types of tips. So, do we think it is likely that we will see a resistance in between 2.5 and 3 ohm and want to declare that an error state? Our ranges for resistance are arbitrary (RTM is about 2ohm, so we capture anything from 1.5 to 2.5, and then I did the same for RTU, from 3 to 4). But if an RTU tip read 2.9 ohms, would we want it to declare an error, or just run normally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for selecting high power when a RTM tip is inserted, my understanding is that resistance is detected on every clock cycle (that's how I am reading the code, every "tick" is a cycle, is this correct?) that PWM is off, and max power is adjusted the very next clock cycle. So we would very quickly detect that it was an RTM tip, and adjust power limit accordingly, and my assumption is that this wouldn't cause much, if any, damage.

I also set the code so that when the tip is "unknown" (when we first power up the iron, before it runs, it cannot detect resistance), the power limit is 150mW, which isn't even high enough to get the iron warm. But it's just enough power that the iron can detect resistance, and then it adjusts power level. This way, like you said, it won't put full power to a RTM tip (or a tip where it can't tell what it is). Perhaps I can think of a way to always do that on the first cycle when you start heating. That way no matter what, max power will be 150mW until the iron knows for sure what tip is installed.

In my mind there are two ways to do this. We could do it at the beginning or the end. Either very time the "start" routine is called, the iron is set to TipType "UNKNOWN" so that it is forced to 150mW until resistance is confirmed. Or any time the "stop" routine is called, we set TipType to UNKNOWN. Then the routine will immediately determine tip type and continue to function. Then when the user stops the iron, it will remember what type of tip is connected until they start heating again. This could be useful if we, for example, replace the voltage drop display (I don't personally find this useful, maybe it's good for debugging?) with the tip type instead, so a user knows what is detected on their iron (in case they were confused or forgot which tip was which). But once you start you will never accidentally feed 150W to a 40W tip, even for a microsecond.

I will see if I can add this to the code, I don't think it will be too difficult, should just be one line of code, in state_start() or a similar routine, maybe in main.hpp. I will look into it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RTU can have between 3 and 4ohm, if it will be less (e.g 2.9ohm), then it is a problem, because at 24V it will have peaks higher than 200Watts
If someone find RTU tips with less than 3ohm, we can discuss this again, but now I think it is clear

about detecting resistance: YES I checking resistance in very fast loop when is PWM in ON state, then I immediately react on low resistance or too high power and PWM is stopped immediately in microseconds - reason why PWM is driven by SW and not HW PWM peripheral.

Later I try to draw image where I explain heating principle, but be sure, that detecting resistance is possible in microseconds.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I assumed it happened super fast since it was basically every clock cycle. I highly doubt that applying 150W to a 40W tip for that short a period of time (if it even achieved that high power that quickly) would cause any serious damage.

But last night I did add a line to the _state_start() routine where all the variables are reset to zero that also sets _tip_type to UNKNOWN. So basically every time it starts the heating cycle it redetects the tip type and until it does, the max power is 150mW. I'm not sure if running that routine constantly might have an effect on the pid loop (since I think that means it will constantly be set to a max of 150mW and then back to 40W or 150W?). I ran my 40W tip yesterday to test it, and it seemed like the temperature settled one or two degrees low. I can't remember if it did that before, but I don't think so, if anything it was a couple degrees high before.

As for the resistance, you make a good point. I will establish a minimum as well so that a resistance below 3ohm but above 2.5 will register as an error state and neither RTU or RTP. That is an easy change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so option one: write message that is 'shorted' or fallback to RTM power limit.

I didn't see this before. Yeah, I suppose instead of being set to RTU when the resistance is over 2.5, it could be set as RTU when resistance is over 3. This would expand the range of RTM though and might miss an RTM tip that was failing and had a high resistance (does that happen when they fail? I assume it does). I don't know how quickly the resistance increases but if we have the error state in between we might catch a failing RTM instead of putting 150W into it and very quickly destroying it, maybe causing more damage to something else.

So I think you were right the first time, have a gap between the two types of tips that is accurate to how they are really built.

Copy link
Contributor Author

@swissfreek swissfreek Jan 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also in the check_tip_type(), this will allow a tip type of "UNKNOWN" if the resistance is in between the two, because this is true, we don't know if it's an RTU tip with low resistance, or an RTM tip with high resistance. And since it is declared as UNKNOWN in this case, the max power output will be 150mW which is very safe, even if the rest of the code allows the heater to receive power anyway.

static const int TIP_RESISTANCE_MIN_MO = 1500; // mOhm
static const int TIP_RESISTANCE_MAX_MO = 2500; // mOhm
static const int TIP_RESISTANCE_BROKEN_MO = 100000; // mOhm
Expand Down Expand Up @@ -54,6 +58,13 @@ class Heating {
BROKEN,
SHORTED,
} _tip_sensor_status = TipSensorStatus::UNKNOWN;

/* defines new class for tip type and sets default to UNKNOWN */
enum class TipType {
UNKNOWN,
RTM,
RTU,
} _tip_type = TipType::UNKNOWN

private:
Settings &_settings;
Expand All @@ -72,6 +83,7 @@ class Heating {

int _requested_power_mw = 0; // mW
int _power_mw = 0; // mW
int _max_power_mw = 40 * 1000 // mW (sets default max power output to 40W)
int _cpu_voltage_mv_heat = 0; // mV
int _cpu_voltage_mv_idle = 0; // mV
int _supply_voltage_mv_heat = 0; // mV
Expand Down Expand Up @@ -207,17 +219,28 @@ class Heating {
void _check_heating_element() {
if (_heater_resistance_mo < TIP_RESISTANCE_SHORTED_MO) {
_heating_element_status = HeatingElementStatus::SHORTED;
} else if (_heater_resistance_mo < TIP_RESISTANCE_MIN_MO) {
} else if (_heater_resistance_mo < RTM_TIP_RESISTANCE_MIN_MO) {
_heating_element_status = HeatingElementStatus::LOW_RESISTANCE;
} else if (_heater_resistance_mo > TIP_RESISTANCE_BROKEN_MO) {
_heating_element_status = HeatingElementStatus::BROKEN;
} else if (_heater_resistance_mo > TIP_RESISTANCE_MAX_MO) {
} else if (_heater_resistance_mo > RTU_TIP_RESISTANCE_MAX_MO) {
_heating_element_status = HeatingElementStatus::HIGH_RESISTANCE;
} else {
_heating_element_status = HeatingElementStatus::OK;
}
}


/* Checks if resistance is in range of RTM or above it (RTU) or other (unknown) */
void _check_tip_type() {
if (_heater_resistance_mo > RTM_TIP_RESISTANCE_MAX_MO && _heater_resistance_mo < RTU_TIP_RESISTANCE_MAX_MO) {
_tip_type = TipType::RTU;
} else if (_heater_resistance_mo > RTM_TIP_RESISTANCE_MIN_MO && _heater_resistance_mo < RTM_TIP_RESISTACNCE_MAX_MO) {
_tip_type = TipType::RTM;
} else {
_tip_type = TipType::UNKNOWN;
}
}

void _state_heating(const unsigned delta_ticks) {
_measure_ticks += delta_ticks;
if (board::Adc::get_instance().process() != board::Adc::State::DONE) return;
Expand All @@ -231,6 +254,7 @@ class Heating {
_average_heating_measured_values();
_calculate_total_energy();
_calculate_tip_resistance();
_check_tip_type(); // establishes tip type once resistance is calculated
_calculate_voltage_drop();
_check_heating_element();
_state = State::STABILIZE;
Expand Down Expand Up @@ -461,11 +485,29 @@ class Heating {
TipSensorStatus getTipSensorStatus() const {
return _tip_sensor_status;
}

/** Getter tip type
indicate whether RTM or RTU tip is detected

Return:
state from enum TipType
*/
TipType getTipType() const {
return _tip_type;
}

/** Initialize module
*/
void init() {
_pid.set_constants(PID_K_PROPORTIONAL, PID_K_INTEGRAL, PID_K_DERIVATE, PERIOD_TIME_MS, HEATING_POWER_MAX_MW);
_max_power_mw = (40 + (110 * _settings.get_high_power())) * 1000; // mW
/* Below will use tip resistance to set max power, but need to figure out how to calculate tip resistance before init, or how to change max power after init
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AHA, I see why ,-)
another problem is, that RTU will need probably different PID constants, or it is working also with these constants ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I assume that RTU will work better with different PIDs. I am currently traveling for work, and my RTU tip arrived at the house the day after I left, so it will be about two weeks before I can plug it in to test how it works. I also am not sure I have the resources to test the temperature and create a curve to see how much damping or overshoot needs to be adjusted. But if needed I think I may be able to find a friend that can. No promises, though.

BUT, even if it did require different PIDs, I envision that we would have separate constants for both, and then in the IF statement that decides which max power to allow, it would also select the current PIDs. In my mind, finding better PIDs and the maximum power logic are two separate problems to be solved that don't need to be solved at the same time (unless I test the RTU and find that it the current PIDs don't work at all).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, btw, for tuning PID constants I have small python tool, which show diagrams of heating and so... (is not currently published)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUPPLY_VOLTAGE_MAX_MV = 18000; // mV

Yes, you are right, I did not implemented this, I forgotten.
but voltage limits is important to implement, my plan is to disable ON if the voltage limit is over maximum allowed.

Thinking about it now, this is more complicated than I thought. I'm looking for a good place that _supply_voltage_mv_idle could be checked to force a STOP state, but then of course it will also need some notification to the user. So I will chew on this some more and find a good way to implement it.

if (_tip_type = TipType::RTM) {
_max_power_mw = 40 * 1000; // mW
} else if (_tip_type = TipType::RTU) {
_max_power_mw = 150 * 1000; // mW
}
*/
_pid.set_constants(PID_K_PROPORTIONAL, PID_K_INTEGRAL, PID_K_DERIVATE, PERIOD_TIME_MS, _max_power_mw);
}

Preset &get_preset() {
Expand Down