forked from M-Labs/thermostat
implement setting i_set centerpoint
This commit is contained in:
parent
b394cfa3d4
commit
a84242fb1f
48
README.md
48
README.md
|
@ -46,26 +46,28 @@ The scope of this setting is per TCP session.
|
||||||
|
|
||||||
### Commands
|
### Commands
|
||||||
|
|
||||||
| Syntax | Function |
|
| Syntax | Function |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `report` | Show current input |
|
| `report` | Show current input |
|
||||||
| `report mode` | Show current report mode |
|
| `report mode` | Show current report mode |
|
||||||
| `report mode <off/on>` | Set report mode |
|
| `report mode <off/on>` | Set report mode |
|
||||||
| `pwm` | Show current PWM settings |
|
| `pwm` | Show current PWM settings |
|
||||||
| `pwm <0/1> max_i_pos <ratio>` | Set PWM duty cycle for **max_i_pos** to *ampere* |
|
| `pwm <0/1> max_i_pos <ratio>` | Set PWM duty cycle for **max_i_pos** to *ampere* |
|
||||||
| `pwm <0/1> max_i_neg <ratio>` | Set PWM duty cycle for **max_i_neg** to *ampere* |
|
| `pwm <0/1> max_i_neg <ratio>` | Set PWM duty cycle for **max_i_neg** to *ampere* |
|
||||||
| `pwm <0/1> max_v <ratio>` | Set PWM duty cycle for **max_v** to *volt* |
|
| `pwm <0/1> max_v <ratio>` | Set PWM duty cycle for **max_v** to *volt* |
|
||||||
| `pwm <0/1> <volts>` | Disengage PID, set **i_set** DAC to *ampere* |
|
| `pwm <0/1> <volts>` | Disengage PID, set **i_set** DAC to *ampere* |
|
||||||
| `pwm <0/1> pid` | Set PWM to be controlled by PID |
|
| `pwm <0/1> pid` | Set PWM to be controlled by PID |
|
||||||
| `pid` | Show PID configuration |
|
| `center <0/1> <volts>` | Set the MAX1968 0A-centerpoint to *volts* |
|
||||||
| `pid <0/1> target <value>` | Set the PID controller target |
|
| `center <0/1> vref` | Set the MAX1968 0A-centerpoint to measure from VREF |
|
||||||
| `pid <0/1> kp <value>` | Set proportional gain |
|
| `pid` | Show PID configuration |
|
||||||
| `pid <0/1> ki <value>` | Set integral gain |
|
| `pid <0/1> target <value>` | Set the PID controller target |
|
||||||
| `pid <0/1> kd <value>` | Set differential gain |
|
| `pid <0/1> kp <value>` | Set proportional gain |
|
||||||
| `pid <0/1> output_min <value>` | Set mininum output |
|
| `pid <0/1> ki <value>` | Set integral gain |
|
||||||
| `pid <0/1> output_max <value>` | Set maximum output |
|
| `pid <0/1> kd <value>` | Set differential gain |
|
||||||
| `pid <0/1> integral_min <value>` | Set integral lower bound |
|
| `pid <0/1> output_min <value>` | Set mininum output |
|
||||||
| `pid <0/1> integral_max <value>` | Set integral upper bound |
|
| `pid <0/1> output_max <value>` | Set maximum output |
|
||||||
| `s-h` | Show Steinhart-Hart equation parameters |
|
| `pid <0/1> integral_min <value>` | Set integral lower bound |
|
||||||
| `s-h <0/1> <t/b/r0> <value>` | Set Steinhart-Hart parameter for a channel |
|
| `pid <0/1> integral_max <value>` | Set integral upper bound |
|
||||||
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
|
| `s-h` | Show Steinhart-Hart equation parameters |
|
||||||
|
| `s-h <0/1> <t/b/r0> <value>` | Set Steinhart-Hart parameter for a channel |
|
||||||
|
| `postfilter <0/1> rate <rate>` | Set postfilter output data rate |
|
||||||
|
|
|
@ -13,6 +13,7 @@ use crate::{
|
||||||
ad7172,
|
ad7172,
|
||||||
pid,
|
pid,
|
||||||
steinhart_hart as sh,
|
steinhart_hart as sh,
|
||||||
|
command_parser::CenterPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
const R_INNER: f64 = 2.0 * 5100.0;
|
const R_INNER: f64 = 2.0 * 5100.0;
|
||||||
|
@ -24,6 +25,8 @@ pub struct ChannelState {
|
||||||
pub adc_time: Instant,
|
pub adc_time: Instant,
|
||||||
/// VREF for the TEC (1.5V)
|
/// VREF for the TEC (1.5V)
|
||||||
pub vref: ElectricPotential,
|
pub vref: ElectricPotential,
|
||||||
|
/// i_set 0A center point
|
||||||
|
pub center: CenterPoint,
|
||||||
pub dac_value: ElectricPotential,
|
pub dac_value: ElectricPotential,
|
||||||
pub pid_engaged: bool,
|
pub pid_engaged: bool,
|
||||||
pub pid: pid::Controller,
|
pub pid: pid::Controller,
|
||||||
|
@ -36,8 +39,9 @@ impl ChannelState {
|
||||||
adc_data: None,
|
adc_data: None,
|
||||||
adc_calibration,
|
adc_calibration,
|
||||||
adc_time: Instant::from_secs(0),
|
adc_time: Instant::from_secs(0),
|
||||||
// can be initialized later with Channels.read_vref()
|
// updated later with Channels.read_vref()
|
||||||
vref: ElectricPotential::new::<volt>(3.3 / 2.0),
|
vref: ElectricPotential::new::<volt>(1.5),
|
||||||
|
center: CenterPoint::Vref,
|
||||||
dac_value: ElectricPotential::new::<volt>(0.0),
|
dac_value: ElectricPotential::new::<volt>(0.0),
|
||||||
pid_engaged: false,
|
pid_engaged: false,
|
||||||
pid: pid::Controller::new(pid::Parameters::default()),
|
pid: pid::Controller::new(pid::Parameters::default()),
|
||||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
ad7172,
|
ad7172,
|
||||||
channel::{Channel, Channel0, Channel1},
|
channel::{Channel, Channel0, Channel1},
|
||||||
channel_state::ChannelState,
|
channel_state::ChannelState,
|
||||||
command_parser::PwmPin,
|
command_parser::{CenterPoint, PwmPin},
|
||||||
pins,
|
pins,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,11 +99,17 @@ impl Channels {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_i(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) {
|
pub fn get_i(&mut self, channel: usize) -> (ElectricCurrent, ElectricCurrent) {
|
||||||
let vref = self.channel_state(channel).vref;
|
let state = self.channel_state(channel);
|
||||||
|
let center_point = match state.center {
|
||||||
|
CenterPoint::Vref =>
|
||||||
|
state.vref,
|
||||||
|
CenterPoint::Override(center_point) =>
|
||||||
|
ElectricPotential::new::<volt>(center_point),
|
||||||
|
};
|
||||||
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
|
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
|
||||||
let (voltage, max) = self.get_dac(channel);
|
let (voltage, max) = self.get_dac(channel);
|
||||||
let i_tec = (voltage - vref) / (10.0 * r_sense);
|
let i_tec = (voltage - center_point) / (10.0 * r_sense);
|
||||||
let max = (max - vref) / (10.0 * r_sense);
|
let max = (max - center_point) / (10.0 * r_sense);
|
||||||
(i_tec, max)
|
(i_tec, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +133,18 @@ impl Channels {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_i(&mut self, channel: usize, i_tec: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) {
|
pub fn set_i(&mut self, channel: usize, i_tec: ElectricCurrent) -> (ElectricCurrent, ElectricCurrent) {
|
||||||
let vref = self.channel_state(channel).vref;
|
let state = self.channel_state(channel);
|
||||||
|
let center_point = match state.center {
|
||||||
|
CenterPoint::Vref =>
|
||||||
|
state.vref,
|
||||||
|
CenterPoint::Override(center_point) =>
|
||||||
|
ElectricPotential::new::<volt>(center_point),
|
||||||
|
};
|
||||||
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
|
let r_sense = ElectricalResistance::new::<ohm>(R_SENSE);
|
||||||
let voltage = i_tec * 10.0 * r_sense + vref;
|
let voltage = i_tec * 10.0 * r_sense + center_point;
|
||||||
let (voltage, max) = self.set_dac(channel, voltage);
|
let (voltage, max) = self.set_dac(channel, voltage);
|
||||||
let i_tec = (voltage - vref) / (10.0 * r_sense);
|
let i_tec = (voltage - center_point) / (10.0 * r_sense);
|
||||||
let max = (max - vref) / (10.0 * r_sense);
|
let max = (max - center_point) / (10.0 * r_sense);
|
||||||
(i_tec, max)
|
(i_tec, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,12 @@ pub enum PwmPin {
|
||||||
MaxV,
|
MaxV,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum CenterPoint {
|
||||||
|
Vref,
|
||||||
|
Override(f64),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Quit,
|
Quit,
|
||||||
|
@ -137,6 +143,10 @@ pub enum Command {
|
||||||
PwmPid {
|
PwmPid {
|
||||||
channel: usize,
|
channel: usize,
|
||||||
},
|
},
|
||||||
|
CenterPoint {
|
||||||
|
channel: usize,
|
||||||
|
center: CenterPoint,
|
||||||
|
},
|
||||||
/// PID parameter setting
|
/// PID parameter setting
|
||||||
Pid {
|
Pid {
|
||||||
channel: usize,
|
channel: usize,
|
||||||
|
@ -290,6 +300,25 @@ fn pwm(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn center_point(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
|
let (input, _) = tag("center")(input)?;
|
||||||
|
let (input, _) = whitespace(input)?;
|
||||||
|
let (input, channel) = channel(input)?;
|
||||||
|
let (input, _) = whitespace(input)?;
|
||||||
|
let (input, center) = alt((
|
||||||
|
value(Ok(CenterPoint::Vref), tag("vref")),
|
||||||
|
|input| {
|
||||||
|
let (input, value) = float(input)?;
|
||||||
|
Ok((input, value.map(CenterPoint::Override)))
|
||||||
|
}
|
||||||
|
))(input)?;
|
||||||
|
end(input)?;
|
||||||
|
Ok((input, center.map(|center| Command::CenterPoint {
|
||||||
|
channel,
|
||||||
|
center,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
/// `pid <0-1> <parameter> <value>`
|
/// `pid <0-1> <parameter> <value>`
|
||||||
fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
let (input, channel) = channel(input)?;
|
let (input, channel) = channel(input)?;
|
||||||
|
@ -378,6 +407,7 @@ fn command(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
|
||||||
alt((value(Ok(Command::Quit), tag("quit")),
|
alt((value(Ok(Command::Quit), tag("quit")),
|
||||||
map(report, Ok),
|
map(report, Ok),
|
||||||
pwm,
|
pwm,
|
||||||
|
center_point,
|
||||||
pid,
|
pid,
|
||||||
steinhart_hart,
|
steinhart_hart,
|
||||||
postfilter,
|
postfilter,
|
||||||
|
@ -529,4 +559,22 @@ mod test {
|
||||||
rate: 21.0,
|
rate: 21.0,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_center_point() {
|
||||||
|
let command = Command::parse(b"center 0 1.5");
|
||||||
|
assert_eq!(command, Ok(Command::CenterPoint {
|
||||||
|
channel: 0,
|
||||||
|
center: CenterPoint::Override(1.5),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_center_point_vref() {
|
||||||
|
let command = Command::parse(b"center 1 vref");
|
||||||
|
assert_eq!(command, Ok(Command::CenterPoint {
|
||||||
|
channel: 1,
|
||||||
|
center: CenterPoint::Vref,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/main.rs
45
src/main.rs
|
@ -55,7 +55,7 @@ use server::Server;
|
||||||
mod session;
|
mod session;
|
||||||
use session::{Session, SessionOutput};
|
use session::{Session, SessionOutput};
|
||||||
mod command_parser;
|
mod command_parser;
|
||||||
use command_parser::{Command, ShowCommand, PwmPin};
|
use command_parser::{CenterPoint, Command, ShowCommand, PwmPin};
|
||||||
mod timer;
|
mod timer;
|
||||||
mod pid;
|
mod pid;
|
||||||
mod steinhart_hart;
|
mod steinhart_hart;
|
||||||
|
@ -221,18 +221,32 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
Command::Show(ShowCommand::Pwm) => {
|
Command::Show(ShowCommand::Pwm) => {
|
||||||
for channel in 0..CHANNELS {
|
for channel in 0..CHANNELS {
|
||||||
|
let i_set = channels.get_i(channel);
|
||||||
let state = channels.channel_state(channel);
|
let state = channels.channel_state(channel);
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "channel {}: PID={}",
|
socket, "channel {}: PID={}",
|
||||||
channel,
|
channel,
|
||||||
if state.pid_engaged { "engaged" } else { "disengaged" }
|
if state.pid_engaged { "engaged" } else { "disengaged" }
|
||||||
);
|
);
|
||||||
let i_set = channels.get_i(channel);
|
let _ = write!(
|
||||||
let _ = writeln!(
|
socket, "- i_set={:.3} / {:.3} ",
|
||||||
socket, "- i_set={:.3} / {:.3}",
|
|
||||||
i_set.0.into_format_args(ampere, Abbreviation),
|
i_set.0.into_format_args(ampere, Abbreviation),
|
||||||
i_set.1.into_format_args(ampere, Abbreviation),
|
i_set.1.into_format_args(ampere, Abbreviation),
|
||||||
);
|
);
|
||||||
|
match state.center {
|
||||||
|
CenterPoint::Vref => {
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "center=vref vref={:.3}",
|
||||||
|
state.vref.into_format_args(volt, Abbreviation),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
CenterPoint::Override(volts) => {
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "center={:.3} V",
|
||||||
|
volts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
let max_v = channels.get_max_v(channel);
|
let max_v = channels.get_max_v(channel);
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "- max_v={:.3} / {:.3}",
|
socket, "- max_v={:.3} / {:.3}",
|
||||||
|
@ -321,7 +335,7 @@ fn main() -> ! {
|
||||||
let voltage = ElectricPotential::new::<volt>(value);
|
let voltage = ElectricPotential::new::<volt>(value);
|
||||||
let (voltage, max) = channels.set_max_v(channel, voltage);
|
let (voltage, max) = channels.set_max_v(channel, voltage);
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "channel {:.3}: max_v set to {:.3} / {:.3}",
|
socket, "channel {}: max_v set to {:.3} / {:.3}",
|
||||||
channel,
|
channel,
|
||||||
voltage.into_format_args(volt, Abbreviation),
|
voltage.into_format_args(volt, Abbreviation),
|
||||||
max.into_format_args(volt, Abbreviation),
|
max.into_format_args(volt, Abbreviation),
|
||||||
|
@ -331,7 +345,7 @@ fn main() -> ! {
|
||||||
let current = ElectricCurrent::new::<ampere>(value);
|
let current = ElectricCurrent::new::<ampere>(value);
|
||||||
let (current, max) = channels.set_max_i_pos(channel, current);
|
let (current, max) = channels.set_max_i_pos(channel, current);
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "channel {:.3}: max_i_pos set to {:.3} / {:.3}",
|
socket, "channel {}: max_i_pos set to {:.3} / {:.3}",
|
||||||
channel,
|
channel,
|
||||||
current.into_format_args(ampere, Abbreviation),
|
current.into_format_args(ampere, Abbreviation),
|
||||||
max.into_format_args(ampere, Abbreviation),
|
max.into_format_args(ampere, Abbreviation),
|
||||||
|
@ -341,7 +355,7 @@ fn main() -> ! {
|
||||||
let current = ElectricCurrent::new::<ampere>(value);
|
let current = ElectricCurrent::new::<ampere>(value);
|
||||||
let (current, max) = channels.set_max_i_neg(channel, current);
|
let (current, max) = channels.set_max_i_neg(channel, current);
|
||||||
let _ = writeln!(
|
let _ = writeln!(
|
||||||
socket, "channel {:.3}: max_i_neg set to {:.3} / {:.3}",
|
socket, "channel {}: max_i_neg set to {:.3} / {:.3}",
|
||||||
channel,
|
channel,
|
||||||
current.into_format_args(ampere, Abbreviation),
|
current.into_format_args(ampere, Abbreviation),
|
||||||
max.into_format_args(ampere, Abbreviation),
|
max.into_format_args(ampere, Abbreviation),
|
||||||
|
@ -349,6 +363,23 @@ fn main() -> ! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Command::CenterPoint { channel, center } => {
|
||||||
|
let (i_tec, _) = channels.get_i(channel);
|
||||||
|
let state = channels.channel_state(channel);
|
||||||
|
state.center = center;
|
||||||
|
if !state.pid_engaged {
|
||||||
|
channels.set_i(channel, i_tec);
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "channel {}: center point updated, output readjusted for {:.3}",
|
||||||
|
channel, i_tec.into_format_args(ampere, Abbreviation),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = writeln!(
|
||||||
|
socket, "channel {}: center point updated",
|
||||||
|
channel,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Command::Pid { channel, parameter, value } => {
|
Command::Pid { channel, parameter, value } => {
|
||||||
let pid = &mut channels.channel_state(channel).pid;
|
let pid = &mut channels.channel_state(channel).pid;
|
||||||
use command_parser::PidParameter::*;
|
use command_parser::PidParameter::*;
|
||||||
|
|
Loading…
Reference in New Issue