simple solder selection

This commit is contained in:
Stefan Kögl 2012-11-15 19:08:59 +01:00
parent 2dba6d5bac
commit 61462a50a4
3 changed files with 93 additions and 73 deletions

View File

@ -3,6 +3,8 @@
#include <LiquidCrystal.h> #include <LiquidCrystal.h>
#include "profile.h" #include "profile.h"
//Pin assignments for SainSmart LCD Keypad Shield //Pin assignments for SainSmart LCD Keypad Shield
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
DFR_Key keypad; DFR_Key keypad;
@ -16,13 +18,6 @@ OvenCtl::OvenCtl() {
actual_dt = 0.f; actual_dt = 0.f;
// timestamps of event beginnings/ends
Ts_time_start = 0;
Ts_time_end = 0;
Tl_time_start = 0;
Tl_time_end = 0;
Tp_time_start = 0;
Tp_time_end = 0;
// thermostat // thermostat
set_min = 0; set_min = 0;
@ -30,7 +25,7 @@ OvenCtl::OvenCtl() {
set_dt_min = 0; set_dt_min = 0;
set_dt_max = 0; set_dt_max = 0;
op_state = OP_CONFIG; oven_mode = OM_CONFIG;
profile_state = START_STATE; profile_state = START_STATE;
error_condition = 0; error_condition = 0;
is_oven_heating = false; is_oven_heating = false;
@ -43,10 +38,6 @@ OvenCtl::OvenCtl() {
lcd.begin(16, 2); lcd.begin(16, 2);
} }
void OvenCtl::reset() {
digitalWrite(7, LOW);
}
void OvenCtl::send_state() { void OvenCtl::send_state() {
Serial.write(time & 0xff); Serial.write(time & 0xff);
@ -80,16 +71,23 @@ void OvenCtl::recv_config() {
} }
void OvenCtl::dispatch_input_config(int cmd) { void OvenCtl::dispatch_remote_cmd(COMMAND cmd) {
if (cmd == 255) switch (cmd) {
case SEND_CONFIG:
send_config(); send_config();
else if (cmd == 254) break;
case RECV_CONFIG:
recv_config(); recv_config();
else if (cmd == 250) break;
reset(); case SEND_STATE:
else if (cmd == 253) recv_config();
break;
case RECV_STEPS:
break;
default:
; ;
} }
}
void OvenCtl::handle_stand_alone_state() { void OvenCtl::handle_stand_alone_state() {
time++; time++;
@ -112,18 +110,20 @@ void OvenCtl::handle_remote_state() {
* *
*/ */
void OvenCtl::loop() { void OvenCtl::loop() {
int cmd = -1; // int cmd = -1;
switch (op_state) { switch (oven_mode) {
case OP_CONFIG: case OM_CONFIG:
// if (profile.handle_config_state()) // if (profile.handle_config_state())
// set_start_state(); // set_start_state();
break; break;
case OP_STAND_ALONE: case OM_CALIBRATION:
break;
case OM_STAND_ALONE:
// if (profile.handle_config_state()) // if (profile.handle_config_state())
// set_start_state(); // set_start_state();
// break; // break;
case OP_REMOTE: case OM_REMOTE:
// if (profile.handle_config_state()) // if (profile.handle_config_state())
// set_start_state(); // set_start_state();
break; break;
@ -133,24 +133,13 @@ void OvenCtl::loop() {
// set_error_state(); // set_error_state();
// } // }
if (Serial.available() > 0) {
cmd = Serial.read();
if (cmd == 255)
send_config();
else if (cmd == 254)
send_state();
else if (cmd == 253)
recv_config();
else if (cmd == 252)
reset();
// else if (cmd == 251) // else if (cmd == 251)
// set_start_state(); // set_start_state();
}
control_oven(); control_oven();
if (profile_state > 0) { if (oven_mode != OM_CONFIG) {
print_status(); print_status();
delay(1000); delay(1000);
} }
@ -214,14 +203,17 @@ void OvenCtl::print_status() {
void OvenCtl::control_oven() { void OvenCtl::control_oven() {
if (temperature <= set_min + actual_hysteresis && !is_oven_heating) { if (is_oven_heating) {
is_oven_heating = true; if (temperature >= set_min + actual_hysteresis) {
// Serial.println("Oven turned on");
}
else if (temperature >= set_min + actual_hysteresis && is_oven_heating) {
is_oven_heating = false; is_oven_heating = false;
} }
} }
else {
if (temperature <= set_min + actual_hysteresis) {
is_oven_heating = true;
}
}
}
void OvenCtl::set_temp(int min, int max, int dt_min, int dt_max) { void OvenCtl::set_temp(int min, int max, int dt_min, int dt_max) {

View File

@ -7,10 +7,18 @@
#define OP_STAND_ALONE 1 #define OP_STAND_ALONE 1
#define OP_REMOTE 2*/ #define OP_REMOTE 2*/
enum OP_STATE { enum OVEN_MODE {
OP_CONFIG, OM_CONFIG,
OP_STAND_ALONE, OM_CALIBRATION,
OP_REMOTE OM_STAND_ALONE,
OM_REMOTE
};
enum COMMAND {
SEND_CONFIG,
RECV_CONFIG,
SEND_STATE,
RECV_STEPS
}; };
#define E_DT_MIN 1 // temperature dt too small #define E_DT_MIN 1 // temperature dt too small
@ -55,19 +63,13 @@ public:
// void set_config_state(); // void set_config_state();
private: private:
// system time, timestamps and temperatures from sensors // system time, timestamps and temperatures from sensors
int time; // profile seconds int time; // profile seconds
int temperature; // actual oven temp int temperature; // actual oven temp
int last_temperature; // last oven temp int last_temperature; // last oven temp
float actual_dt; // actual difference from last to actual temperatur float actual_dt; // actual difference from last to actual temperatur
// timestamps of event beginnings/ends
int Ts_time_start;
int Ts_time_end;
int Tl_time_start;
int Tl_time_end;
int Tp_time_start;
int Tp_time_end;
// thermostat // thermostat
float set_min; float set_min;
@ -84,7 +86,7 @@ private:
// state machine // state machine
unsigned int error_condition; unsigned int error_condition;
OP_STATE op_state; OVEN_MODE oven_mode;
PROFILE_STATE profile_state; PROFILE_STATE profile_state;
boolean is_oven_heating; boolean is_oven_heating;
@ -127,13 +129,11 @@ private:
// void check_Tp_duration_min(); // void check_Tp_duration_min();
// void check_Tp_duration_max(); // void check_Tp_duration_max();
// commands
void send_state(); void send_state();
void send_config(); void send_config();
void reset();
void recv_config(); void recv_config();
void dispatch_remote_cmd(COMMAND cmd);
void dispatch_input_config(int);
}; };
#endif #endif

50
qtplot.py → reflowctl_gui.py Normal file → Executable file
View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
#!/usr/bin/python
import sys, os, random import sys, os, random
@ -31,6 +32,7 @@ class Solder(object):
self.psteps = [] self.psteps = []
self.durations = dict() self.durations = dict()
self.rates = dict() self.rates = dict()
self.name = None
#start = self.add_state("start", 25) #start = self.add_state("start", 25)
#ps = self.add_state("preheat start", 150) #ps = self.add_state("preheat start", 150)
@ -47,6 +49,12 @@ class Solder(object):
#self.add_rate((pe, tal), 1) #self.add_rate((pe, tal), 1)
#self.add_rate((tal, end), -2) #self.add_rate((tal, end), -2)
def __unicode__(self):
return unicode(self.name)
def __str__(self):
return self.name
def add_state(self, name, temp): def add_state(self, name, temp):
s = State(name, temp) s = State(name, temp)
@ -131,6 +139,7 @@ class Solder(object):
xmltree = etree.parse(filename) xmltree = etree.parse(filename)
root = xmltree.getroot() root = xmltree.getroot()
s = Solder() s = Solder()
s.name = root[0].attrib["name"]
for state in root[0].findall("state"): for state in root[0].findall("state"):
s.add_state(state.attrib["name"], int(state.attrib["temperature"])) s.add_state(state.attrib["name"], int(state.attrib["temperature"]))
for duration in root[0].findall("duration"): for duration in root[0].findall("duration"):
@ -147,7 +156,21 @@ class Solder(object):
return s return s
class SolderListModel(QtCore.QAbstractListModel):
def __init__(self, parent=None, *args):
""" datain: a list where each item is a row
"""
super(SolderListModel, self).__init__(parent, *args)
self.listdata = [Solder.unpack(os.path.join("solder_types", p)) for p in os.listdir("solder_types")]
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.listdata)
def data(self, index, role):
if index.isValid() and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.listdata[index.row()].name)
else:
return QtCore.QVariant()
class MyDynamicMplCanvas(FigureCanvas): class MyDynamicMplCanvas(FigureCanvas):
"""A canvas that updates itself every second with a new plot.""" """A canvas that updates itself every second with a new plot."""
@ -293,23 +316,32 @@ class ApplicationWindow(QtGui.QMainWindow):
self.help_menu.addAction('&About', self.about) self.help_menu.addAction('&About', self.about)
self.main_widget = QtGui.QWidget(self) self.main_widget = QtGui.QWidget(self)
self.profile_widget = QtGui.QWidget(self)
self.dpi = 100 self.dpi = 100
#pl = QtGui.QVBoxLayout(self.main_widget) pl = QtGui.QHBoxLayout(self.profile_widget)
#self.p self.solder_model = SolderListModel(self)
self.solder_view = QtGui.QListView()
self.solder_view.setModel(self.solder_model)
self.connect(self.solder_view, QtCore.SIGNAL("clicked(QModelIndex)"), self.solder_selected)
pl.addWidget(self.solder_view)
l = QtGui.QVBoxLayout(self.main_widget) l = QtGui.QVBoxLayout(self.main_widget)
#sc = MyStaticMplCanvas(self.main_widget, width=5, height=4, dpi=100)
self.dc = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=self.dpi) self.dc = MyDynamicMplCanvas(self.main_widget, width=5, height=4, dpi=self.dpi)
#l.addWidget(sc) l.addWidget(self.profile_widget, 1)
l.addWidget(self.dc) l.addWidget(self.dc, 10)
self.main_widget.setFocus() self.main_widget.setFocus()
self.setCentralWidget(self.main_widget) self.setCentralWidget(self.main_widget)
self.statusBar().showMessage("All hail matplotlib!", 2000) self.statusBar().showMessage("All hail matplotlib!", 2000)
def solder_selected(self, index):
if index.isValid():
self.dc.solder = self.solder_model.listdata[index.row()]
def save_plot(self): def save_plot(self):
file_choices = "PNG (*.png)|*.png" file_choices = "PNG (*.png)|*.png"
@ -326,13 +358,9 @@ class ApplicationWindow(QtGui.QMainWindow):
def about(self): def about(self):
QtGui.QMessageBox.about(self, "About %s" % progname, QtGui.QMessageBox.about(self, "About %s" % progname,
u"""%(prog)s version %(version)s u"""%(prog)s version %(version)s
Copyright \N{COPYRIGHT SIGN} 2005 Florent Rougon, 2006 Darren Dale Copyright \N{COPYRIGHT SIGN} 2012 Stefan Kögl
This program is a simple example of a Qt4 application embedding matplotlib reflowctl frontend"""
canvases.
It may be used and modified with no restriction; raw copies as well as
modified versions may be distributed without limitation."""
% {"prog": progname, "version": progversion}) % {"prog": progname, "version": progversion})