Compare commits

...
Author SHA1 Message Date
kraemr 52d4da37c9 timeout fixed the el3062 2026-01-28 13:06:31 +01:00
kraemr 65fb1ab6ad possible fix 2026-01-28 12:33:01 +01:00
kraemr 924227ce14 hopefully fixed el3062 2026-01-28 12:00:05 +01:00
11 changed files with 82 additions and 115 deletions

No files matched your search

@@ -9,6 +9,7 @@ import { EditValue } from "@/control/EditValue";
import { Badge } from "@/components/ui/badge";
import { Label } from "@/control/Label";
import { HeatingZone } from "../../extruder/HeatingZone";
import { StatusBadge } from "@/control/StatusBadge";
export function Aquapath1ControlPage() {
const {
@@ -51,21 +52,19 @@ export function Aquapath1ControlPage() {
const frontTargetFlow = state?.flow_states.front.should_flow ?? false;
const backTargetFlow = state?.flow_states.back.should_flow ?? false;
console.log(state);
return (
<Page>
<ControlGrid columns={2}>
<ControlCard title="Reservoir 1">
<div className="grid grid-rows-5 gap-4">
<div className="flex flex-row">
<TimeSeriesValueNumeric
label="Flow"
unit="l/min"
timeseries={front_flow}
renderValue={(value) => value.toFixed(1)}
/>
{ state?.front_flow === true ? (
<StatusBadge variant="success">Flow: active</StatusBadge>
) : (
<StatusBadge variant="error">Flow: inactive</StatusBadge>
)}
</div>
<div className="flex flex-row">
<TimeSeriesValueNumeric
label="Temperature"
@@ -149,13 +148,13 @@ export function Aquapath1ControlPage() {
<ControlCard title="Reservoir 2">
<div className="grid grid-rows-4 gap-4">
<div className="flex flex-row">
<TimeSeriesValueNumeric
label="Flow"
unit="l/min"
timeseries={back_flow}
renderValue={(value) => value.toFixed(1)}
/>
</div>
<div className="flex flex-row">
{ state?.back_flow === true ? (
<StatusBadge variant="success">Flow: active</StatusBadge>
) : (
<StatusBadge variant="error">Flow: inactive</StatusBadge>
)}
</div></div>
<div className="flex flex-row">
<TimeSeriesValueNumeric
@@ -14,12 +14,12 @@ export function Aquapath1Page() {
title: "Control",
icon: "lu:CirclePlay",
},
{
link: "graph",
title: "Graph",
icon: "lu:ChartSpline",
activeLink: "graphs",
},
//{
// link: "graph",
//title: "Graph",
//icon: "lu:ChartSpline",
//activeLink: "graphs",
//},
{
link: "settings",
title: "Config",
@@ -72,8 +72,6 @@ export const toleranceStatesSchema = z.object({
* Live values event schema (time-series data)
*/
export const liveValuesEventDataSchema = z.object({
front_flow: z.number(),
back_flow: z.number(),
front_temperature: z.number(),
back_temperature: z.number(),
front_temp_reservoir: z.number(),
@@ -96,6 +94,8 @@ export const stateEventDataSchema = z.object({
temperature_states: tempStatesSchema,
fan_states: fanStatesSchema,
tolerance_states: toleranceStatesSchema,
front_flow: z.boolean(),
back_flow: z.boolean(),
});
// ========== Event Schemas with Wrappers ==========
@@ -113,9 +113,6 @@ export type Aquapath1NamespaceStore = {
state: StateEvent | null;
defaultState: StateEvent | null;
front_flow: TimeSeries;
back_flow: TimeSeries;
front_temperature: TimeSeries;
back_temperature: TimeSeries;
@@ -217,7 +214,7 @@ export function aquapath1MessageHandler(
// Live values events (time-series data)
else if (eventName === "LiveValuesEvent") {
const liveValuesEvent = liveValuesEventSchema.parse(event);
console.log(liveValuesEvent);
updateStore((state) => ({
...state,
front_temperature: addTemperature1(state.front_temperature, {
+3 -3
View File
@@ -416,12 +416,12 @@ export const aquapath1: MachineProperties = {
},
{
role: 4,
role_label: "EL5152",
role_label: "EL1002",
allowed_devices: [
{
vendor_id: 2,
product_id: 0x14203052,
revision: 0x140000,
product_id: 0x3ea3052,
revision: 0x120000,
},
],
},
+2 -8
View File
@@ -161,18 +161,12 @@ impl crate::coe::Configuration for EL3062_0030TxPdo {
len += 1;
device.sdo_write(0x1C13, len, 0x1A00u16).await?;
}
if let Some(_) = &self.ai_compact_channel1 {
len += 1;
device.sdo_write(0x1C13, len, 0x1A01u16).await?;
}
if let Some(_) = &self.ai_standard_channel2 {
len += 1;
device.sdo_write(0x1C13, len, 0x1A02u16).await?;
}
if let Some(_) = &self.ai_compact_channel2 {
len += 1;
device.sdo_write(0x1C13, len, 0x1A03u16).await?;
}
device.sdo_write(0x1C13, 0, len).await?;
Ok(())
}
+7 -2
View File
@@ -23,8 +23,13 @@ impl MachineAct for AquaPathV1 {
let now = Instant::now();
self.front_controller.update(now_ts);
self.back_controller.update(now_ts);
if self.front_controller.update(now_ts) {
self.emit_state();
}
if self.back_controller.update(now_ts) {
self.emit_state();
}
if now.duration_since(self.last_measurement_emit) > Duration::from_secs_f64(1.0 / 30.0) {
self.emit_live_values();
+2 -2
View File
@@ -14,8 +14,6 @@ use tracing::instrument;
#[derive(Serialize, Debug, Clone, Default)]
pub struct LiveValuesEvent {
pub front_flow: f64,
pub back_flow: f64,
pub front_temperature: f64,
pub back_temperature: f64,
pub front_temp_reservoir: f64,
@@ -43,6 +41,8 @@ pub struct StateEvent {
pub temperature_states: TempStates,
pub fan_states: FanStates,
pub tolerance_states: ToleranceStates,
pub front_flow: bool,
pub back_flow: bool,
}
impl StateEvent {
+17 -25
View File
@@ -1,7 +1,8 @@
use crate::aquapath1::VolumeRate;
use crate::aquapath1::{Flow, Temperature};
use control_core::controllers::pid::PidController;
use ethercat_hal::io::encoder_input::EncoderInput;
use ethercat_hal::io::analog_input::AnalogInput;
use ethercat_hal::io::digital_input::DigitalInput;
use ethercat_hal::io::{
analog_output::AnalogOutput, digital_output::DigitalOutput, temperature_input::TemperatureInput,
};
@@ -44,9 +45,10 @@ pub struct Controller {
pub heating_allowed: bool,
pub flow: Flow,
pub is_flowing : bool,
pump_relais: DigitalOutput,
pub should_pump: bool,
pub flow_sensor: EncoderInput,
pub flow_sensor: AnalogInput,
pub pump_allowed: bool,
pub current_flow: VolumeRate,
pub max_flow: VolumeRate,
@@ -68,7 +70,7 @@ impl Controller {
flow: Flow,
pump_relais: DigitalOutput,
flow_sensor: EncoderInput,
flow_sensor: AnalogInput,
) -> Self {
Self {
pid: PidController::new(kp, ki, kd),
@@ -93,6 +95,7 @@ impl Controller {
cooling_allowed: false,
heating_allowed: false,
is_flowing : false,
temperature_sensor_in: temp_sensor_in,
temperature_sensor_out: temp_sensor_out,
@@ -220,27 +223,15 @@ impl Controller {
self.should_pump
}
pub fn get_flow(&mut self) -> VolumeRate {
let value = match self.flow_sensor.get_frequency_value() {
pub fn get_flow(&mut self) -> bool {
/* let value = match self.flow_sensor.get_value() {
Ok(val) => val,
Err(_e) => {
return VolumeRate::new::<liter_per_minute>(0.0);
false
}
};
};*/
match value {
Some(val) => {
if val == 0 {
return VolumeRate::new::<liter_per_minute>(0.0);
}
// Formula: f = 8.1*q - 3, so q = (f + 3) / 8.1
let actual_flow = ((val / 100) as f32 + 3.0) / 8.1;
VolumeRate::new::<liter_per_minute>(actual_flow.into())
}
None => {
return VolumeRate::new::<liter_per_minute>(0.0);
}
}
false
}
pub fn get_current_revolutions(&self) -> AngularVelocity {
@@ -272,10 +263,10 @@ impl Controller {
self.total_energy
}
pub fn update(&mut self, now: Instant) -> () {
pub fn update(&mut self, now: Instant) -> bool {
let current_flow = self.get_flow();
self.current_flow = current_flow;
self.flow.flow = current_flow;
let flow_changed = current_flow == self.is_flowing;
self.is_flowing = current_flow;
let should_flow = self.get_should_pump();
self.flow.should_pump = should_flow;
@@ -308,7 +299,7 @@ impl Controller {
if self.temperature.cooling {
self.turn_cooling_off();
}
if self.heating_allowed && current_flow > VolumeRate::new::<liter_per_minute>(0.0) {
if self.heating_allowed && self.is_flowing {
self.turn_heating_on();
self.total_energy += self.get_current_power() * elapsed.as_secs_f64() / 3600.0;
@@ -323,7 +314,7 @@ impl Controller {
if self.temperature.heating {
self.turn_heating_off();
}
if self.cooling_allowed && current_flow > VolumeRate::new::<liter_per_minute>(0.0) {
if self.cooling_allowed && self.is_flowing {
if !self.temperature.cooling {
self.turn_cooling_on();
}
@@ -344,5 +335,6 @@ impl Controller {
}
}
}
flow_changed
}
}
+2 -2
View File
@@ -121,8 +121,6 @@ impl AquaPathV1 {
.back_controller
.current_temperature
.get::<degree_celsius>(),
front_flow: self.front_controller.current_flow.get::<liter_per_minute>(),
back_flow: self.back_controller.current_flow.get::<liter_per_minute>(),
front_temp_reservoir: self.front_controller.temp_reservoir.get::<degree_celsius>(),
back_temp_reservoir: self.back_controller.temp_reservoir.get::<degree_celsius>(),
front_revolutions: self
@@ -228,6 +226,8 @@ impl AquaPathV1 {
.get::<degree_celsius>(),
},
},
front_flow: self.front_controller.is_flowing,
back_flow: self.back_controller.is_flowing,
}
}
+24 -46
View File
@@ -11,18 +11,13 @@ use anyhow::Error;
use ethercat_hal::{
coe::ConfigurableDevice,
devices::{
ek1100::{EK1100, EK1100_IDENTITY_A},
el2008::{EL2008, EL2008_IDENTITY_A, EL2008_IDENTITY_B, EL2008Port},
el3204::{EL3204, EL3204_IDENTITY_A, EL3204_IDENTITY_B, EL3204Port},
el4002::{EL4002, EL4002_IDENTITY_A, EL4002Port},
el5152::{
ek1100::{EK1100, EK1100_IDENTITY_A}, el1002::{EL1002, EL1002_IDENTITY_A}, el2008::{EL2008, EL2008_IDENTITY_A, EL2008_IDENTITY_B, EL2008Port}, el3062_0030::{EL3062_0030, EL3062_0030_IDENTITY_A, EL3062_0030Configuration}, el3204::{EL3204, EL3204_IDENTITY_A, EL3204_IDENTITY_B, EL3204Port}, el4002::{EL4002, EL4002_IDENTITY_A, EL4002Port}, el5152::{
EL5152, EL5152_IDENTITY_A, EL5152Configuration, EL5152Port,
EL5152PredefinedPdoAssignment,
},
}
},
io::{
analog_output::AnalogOutput, digital_output::DigitalOutput, encoder_input::EncoderInput,
temperature_input::TemperatureInput,
analog_input::AnalogInput, analog_output::AnalogOutput, digital_input::DigitalInput, digital_output::DigitalOutput, encoder_input::EncoderInput, temperature_input::TemperatureInput
},
};
use std::time::Instant;
@@ -83,49 +78,32 @@ impl MachineNewTrait for AquaPathV1 {
.await?
.0;
let el5152 =
get_ethercat_device::<EL5152>(hardware, params, 4, [EL5152_IDENTITY_A].to_vec())
let el3062_0030 =
get_ethercat_device::<EL3062_0030>(hardware, params, 4, [EL3062_0030_IDENTITY_A].to_vec())
.await?
.0;
let config = EL5152Configuration {
pdo_assignment: EL5152PredefinedPdoAssignment::Frequency,
..Default::default()
};
let subdevice = get_subdevice_by_index(hardware.subdevices, 4)?;
el5152
.write()
.await
.write_config(&subdevice, &config)
.await?;
let el3062_0030_subdevice = get_subdevice_by_index(hardware.subdevices, 4)?;
let mut guard = el3062_0030.write().await;
let config = EL3062_0030Configuration::default();
guard.write_config(el3062_0030_subdevice,&config).await;
drop(guard);
let enc1 = EncoderInput::new(el5152.clone(), EL5152Port::ENC1);
let ai1 = AnalogInput::new(el3062_0030.clone(),ethercat_hal::devices::el3062_0030::EL3062_0030Port::AI1);
let ai2 = AnalogInput::new(el3062_0030.clone(), ethercat_hal::devices::el3062_0030::EL3062_0030Port::AI2);
let enc2 = EncoderInput::new(el5152.clone(), EL5152Port::ENC2);
//after heating
let t1 = TemperatureInput::new(el3204.clone(), EL3204Port::T1);
//in reservoir
let t2 = TemperatureInput::new(el3204.clone(), EL3204Port::T2);
//after heating
let t3 = TemperatureInput::new(el3204.clone(), EL3204Port::T3);
//in reservoir
let t1 = TemperatureInput::new(el3204.clone(), EL3204Port::T1);
let t2 = TemperatureInput::new(el3204.clone(), EL3204Port::T2);
let t3 = TemperatureInput::new(el3204.clone(), EL3204Port::T3);
let t4 = TemperatureInput::new(el3204.clone(), EL3204Port::T4);
//pump flow control
//phys 1
let do1 = DigitalOutput::new(el2008.clone(), EL2008Port::DO1);
//phys 5
let do2 = DigitalOutput::new(el2008.clone(), EL2008Port::DO2);
//heating
//phys 6
let do4 = DigitalOutput::new(el2008.clone(), EL2008Port::DO4);
//phys 3
let do5 = DigitalOutput::new(el2008.clone(), EL2008Port::DO5);
//phys 7
let do6 = DigitalOutput::new(el2008.clone(), EL2008Port::DO6);
//cooling power cut
//phys 8
//pump flow control
let do1 = DigitalOutput::new(el2008.clone(), EL2008Port::DO1);
let do2 = DigitalOutput::new(el2008.clone(), EL2008Port::DO2);
let do4 = DigitalOutput::new(el2008.clone(), EL2008Port::DO4);
let do5 = DigitalOutput::new(el2008.clone(), EL2008Port::DO5);
let do6 = DigitalOutput::new(el2008.clone(), EL2008Port::DO6);
let do8 = DigitalOutput::new(el2008.clone(), EL2008Port::DO8);
let ao1 = AnalogOutput::new(el4002.clone(), EL4002Port::AO1);
@@ -145,7 +123,7 @@ impl MachineNewTrait for AquaPathV1 {
AngularVelocity::new::<revolution_per_minute>(100.0),
Flow::default(),
do1,
enc1,
ai1,
);
let back_controller = Controller::new(
@@ -162,7 +140,7 @@ impl MachineNewTrait for AquaPathV1 {
AngularVelocity::new::<revolution_per_minute>(100.0),
Flow::default(),
do5,
enc2,
ai2,
);
let (sender, receiver) = smol::channel::unbounded();
let mut water_cooling = Self {
+2
View File
@@ -433,6 +433,8 @@ pub async fn setup_loop(
)
.await?;
smol::Timer::after(Duration::from_millis(3000)).await;
let group_safe = match group_preop.into_safe_op(&maindevice).await {
Ok(group_op) => {
tracing::info!("Group in Safe-OP state");