commit 0694d4ea69813e3d9f66fa11ac91241955c32d94 Author: Jens Ahrensfeld Date: Mon Sep 10 16:35:27 2018 +0000 reorganized git-svn-id: http://moon:8086/svn/projects/HendiControl@2 fda53097-d464-4ada-af97-ba876c37ca34 diff --git a/Control/.goutputstream-6QMDOZ b/Control/.goutputstream-6QMDOZ new file mode 100755 index 0000000..a8d97cb --- /dev/null +++ b/Control/.goutputstream-6QMDOZ @@ -0,0 +1,54 @@ +#:: + +#0:POWER:GET +#0:POWER:SET ; value={0, 500 .. 3500} + +#0:POTI:GET ; returns {0..1023} +#0:SWITCH:GET ; returns {0, 1} + +#0:INTERVAL:GET +#0:INTERVAL:SET ; in milliseconds, 0 means no reporting + +Commands: ++------------+------+ +| Header | Data | ++------------+------+ +|SEQ|CODE|LEN| DATA | ++------------+------+ +SEQ = 1..255 +CODE = Command code +LEN = length of data [bytes] + +* Command / Response codes: +0x80: OK +0xFF: ERR + +Commands +0x01: CMD_CONFIG_SET -> RSP_SET_CONFIG, OK, ERR +0x02: CMD_CONFIG_GET -> RSP_GET_CONFIG, ERR +0x03: CMD_PWR_SET -> RSP_SET_PWR, OK, ERR +0x04: CMD_PWR_GET -> RSP_GET_PWR, ERR +0x05: CMD_POTI_GET -> RSP_GET_POTI, ERR +0x06: CMD_SWITCH_GET -> RSP_GET_SWITCH, ERR + +Responses +0x81: RSP_CONFIG_SET +0x82: RSP_CONFIG_GET +0x83: RSP_PWR_SET +0x84: RSP_PWR_GET +0x85: RSP_POTI_GET +0x86: RSP_SWITCH_GET + +Notifications +Are responses with SEQ-number set to 0 + +Beispiel +CMD_PWR_SET(3500): +01, 03, 02, AC, 0D + + +OK:RSP_PWR_SET: +01, 83, 02, AC, 0D + +ERR: +01, FF, 02, <2 byte Fehler code> diff --git a/Control/.goutputstream-BPFJOZ b/Control/.goutputstream-BPFJOZ new file mode 100755 index 0000000..a8d97cb --- /dev/null +++ b/Control/.goutputstream-BPFJOZ @@ -0,0 +1,54 @@ +#:: + +#0:POWER:GET +#0:POWER:SET ; value={0, 500 .. 3500} + +#0:POTI:GET ; returns {0..1023} +#0:SWITCH:GET ; returns {0, 1} + +#0:INTERVAL:GET +#0:INTERVAL:SET ; in milliseconds, 0 means no reporting + +Commands: ++------------+------+ +| Header | Data | ++------------+------+ +|SEQ|CODE|LEN| DATA | ++------------+------+ +SEQ = 1..255 +CODE = Command code +LEN = length of data [bytes] + +* Command / Response codes: +0x80: OK +0xFF: ERR + +Commands +0x01: CMD_CONFIG_SET -> RSP_SET_CONFIG, OK, ERR +0x02: CMD_CONFIG_GET -> RSP_GET_CONFIG, ERR +0x03: CMD_PWR_SET -> RSP_SET_PWR, OK, ERR +0x04: CMD_PWR_GET -> RSP_GET_PWR, ERR +0x05: CMD_POTI_GET -> RSP_GET_POTI, ERR +0x06: CMD_SWITCH_GET -> RSP_GET_SWITCH, ERR + +Responses +0x81: RSP_CONFIG_SET +0x82: RSP_CONFIG_GET +0x83: RSP_PWR_SET +0x84: RSP_PWR_GET +0x85: RSP_POTI_GET +0x86: RSP_SWITCH_GET + +Notifications +Are responses with SEQ-number set to 0 + +Beispiel +CMD_PWR_SET(3500): +01, 03, 02, AC, 0D + + +OK:RSP_PWR_SET: +01, 83, 02, AC, 0D + +ERR: +01, FF, 02, <2 byte Fehler code> diff --git a/Control/ATmega328_P AVR MCU with picoPower Technology Data Sheet 40001984A.pdf b/Control/ATmega328_P AVR MCU with picoPower Technology Data Sheet 40001984A.pdf new file mode 100755 index 0000000..b1e47d7 Binary files /dev/null and b/Control/ATmega328_P AVR MCU with picoPower Technology Data Sheet 40001984A.pdf differ diff --git a/Control/DS_FT232R.pdf b/Control/DS_FT232R.pdf new file mode 100755 index 0000000..5ec4087 Binary files /dev/null and b/Control/DS_FT232R.pdf differ diff --git a/Control/LTC6258.pdf b/Control/LTC6258.pdf new file mode 100755 index 0000000..5545830 Binary files /dev/null and b/Control/LTC6258.pdf differ diff --git a/Control/cmds.txt b/Control/cmds.txt new file mode 100755 index 0000000..a8d97cb --- /dev/null +++ b/Control/cmds.txt @@ -0,0 +1,54 @@ +#:: + +#0:POWER:GET +#0:POWER:SET ; value={0, 500 .. 3500} + +#0:POTI:GET ; returns {0..1023} +#0:SWITCH:GET ; returns {0, 1} + +#0:INTERVAL:GET +#0:INTERVAL:SET ; in milliseconds, 0 means no reporting + +Commands: ++------------+------+ +| Header | Data | ++------------+------+ +|SEQ|CODE|LEN| DATA | ++------------+------+ +SEQ = 1..255 +CODE = Command code +LEN = length of data [bytes] + +* Command / Response codes: +0x80: OK +0xFF: ERR + +Commands +0x01: CMD_CONFIG_SET -> RSP_SET_CONFIG, OK, ERR +0x02: CMD_CONFIG_GET -> RSP_GET_CONFIG, ERR +0x03: CMD_PWR_SET -> RSP_SET_PWR, OK, ERR +0x04: CMD_PWR_GET -> RSP_GET_PWR, ERR +0x05: CMD_POTI_GET -> RSP_GET_POTI, ERR +0x06: CMD_SWITCH_GET -> RSP_GET_SWITCH, ERR + +Responses +0x81: RSP_CONFIG_SET +0x82: RSP_CONFIG_GET +0x83: RSP_PWR_SET +0x84: RSP_PWR_GET +0x85: RSP_POTI_GET +0x86: RSP_SWITCH_GET + +Notifications +Are responses with SEQ-number set to 0 + +Beispiel +CMD_PWR_SET(3500): +01, 03, 02, AC, 0D + + +OK:RSP_PWR_SET: +01, 83, 02, AC, 0D + +ERR: +01, FF, 02, <2 byte Fehler code> diff --git a/MotorDriver/1158fb.pdf b/MotorDriver/1158fb.pdf new file mode 100755 index 0000000..4709754 Binary files /dev/null and b/MotorDriver/1158fb.pdf differ diff --git a/MotorDriver/11602fb.pdf b/MotorDriver/11602fb.pdf new file mode 100755 index 0000000..4d9ebc7 Binary files /dev/null and b/MotorDriver/11602fb.pdf differ diff --git a/MotorDriver/LTMag_V02N1_Feb92.pdf b/MotorDriver/LTMag_V02N1_Feb92.pdf new file mode 100755 index 0000000..88f8a25 Binary files /dev/null and b/MotorDriver/LTMag_V02N1_Feb92.pdf differ diff --git a/matlab/brew_eval.m b/matlab/brew_eval.m new file mode 100755 index 0000000..321bae1 --- /dev/null +++ b/matlab/brew_eval.m @@ -0,0 +1,201 @@ +## Copyright (C) 2018 Jens Ahrensfeld +## +## This program is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or +## (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . + +## Author: Jens Ahrensfeld +## Created: 2018-02-08 + +function brew_eval(varargin) +% +% brew_eval('M', 20.0, 'cont_ctrl', 0, 'kp', 0.1, 'ki', 0.1, 'kd', 100, 'T', 1800, 'mass_kleak', 0.2, 'P_q', 100, 'mass_delay', 100, [50 60 70 80]); + +WITH_LOWPASS = 1; +WITH_RUNNING_MEAN = 0; + +params = struct ('cont_ctrl',0, 'C',4.19e3, 'M',10, 'mass_kleak',0.1, 'mass_delay',50, 'P_min',0, 'P_max',3000, 'P_q',100, 'T',100, 'dt',1.0, 'Td',10.0, 'theta_lock',0.5, 'theta_amb',20.0, 'kp',10, 'ki',0.04, 'kd',500, 'pid_kleak',0.1, 'k_noise', 0.01, 'k_noise2', 0.0, 'f_noise2', 0.01); +units = struct ('cont_ctrl', '', 'C', 'J/(kg*K)', 'M', 'kg', 'mass_kleak', '', 'mass_delay', 's', 'P_min', 'W', 'P_max', 'W', 'P_q','W', 'T', 's', 'dt', 's', 'Td', 's', 'theta_lock', '°C', 'theta_amb', '°C', 'kp', '', 'ki', '', 'kd', '', 'pid_kleak', '', 'k_noise', '', 'k_noise2', '', 'f_noise2', 'Hz'); + +% Parse parameters +names = fieldnames(params); +varargin +for k=1:nargin-1, + for n=1:length(names), + if strcmpi(varargin{k}, names{n}) + params.(names{n}) = varargin{k+1}; + end + end +end + +print_parameters(params) + +s_mass = 0; +s_pid = []; +s_pid_rate = []; +theta_ist = params.theta_amb; +theta_last = params.theta_amb; +thetas = varargin{nargin} +heatRate = 0; +heatRateMeasureInterval = 30.0; % seconds +heatRateMeasureCount = 0; % seconds +n = 0; +nSteps = params.P_max / params.P_q; + +N = 2*fix(length(thetas)*params.T/params.dt); + +lp_N = 17; +[lp_b, lp_a] = butter (lp_N-1, 0.125); +lp_z = zeros(1, length(lp_b)-1); +maz = 17; + +for k=1:length(thetas) + theta_soll = thetas(k); + hold_theta = 0; + temp_ok = 0; + while n < N, + err = theta_ist - theta_soll; + [y, yc, s_pid] = pid(s_pid, params.kp, params.ki*params.dt, params.kd*params.dt, 1-params.pid_kleak, -err); + + % Rate controller + err_rate = heatRate - 1.0; + [y_rate, yc_rate, s_pid_rate] = pid(s_pid_rate, 1.0*params.dt, 0.001*params.dt, 0*params.dt, 1-params.pid_kleak, -err_rate); + P_rate = max(params.P_min+1, min(params.P_max, y_rate)); + % Rate controller + + P_norm = max(params.P_min/params.P_max, min(1.0, yc)); + P_cont = P_norm * params.P_max; + P_cont_q = fix(P_norm * nSteps)*params.P_q; + if params.cont_ctrl + P = P_cont_q; + else + duty = mod(n*params.dt/params.Td*params.P_max, params.P_max); + heat = (duty < P_cont_q); + P = params.P_max * heat; + end + [theta, s_mass] = mass(s_mass, params.dt, params.C, params.M, params.mass_kleak, P, params.mass_delay, theta_ist-params.theta_amb); + theta_ist = params.theta_amb + theta + params.k_noise*randn()/sqrt(12) + params.k_noise2*cos(params.f_noise2*2*pi*n*params.dt); + + if WITH_RUNNING_MEAN + [theta_ist, maz] = movingavg(theta_ist, maz); + end + if WITH_LOWPASS + [theta_ist, lp_z] = filter(lp_b, lp_a, theta_ist, lp_z); + end + if heatRateMeasureCount <= 0 + heatRate = 60*(theta_ist-theta_last)/params.dt/heatRateMeasureInterval; + heatRateMeasureCount = heatRateMeasureInterval; + theta_last = theta_ist ; + else + heatRateMeasureCount = heatRateMeasureCount - params.dt; + end + n = n + 1; + theta_ist = theta_ist; + heatRate_(n) = heatRate; + theta_(n) = theta_ist; + err_(n) = err; + p_(n) = P; + pc_(n) = P_cont; + pcq_(n) = P_cont_q; + y_(n) = y; + P_rate_(n) = y_rate; + if hold_theta > 0 + hold_theta = hold_theta - 1; + if hold_theta == 0 + disp('Temperature next') + break; + end + elseif abs(err) < params.theta_lock + hold_theta = params.T/params.dt; + temp_ok = 1; + disp('Temperature is OK!') + end + end +end +close all; +t = (0:n-1)*params.dt; + +subplot(3,1,1) +plot(t, theta_); grid; xlabel('t/s'); ylabel('Theta/°'); title('Temperature'); +subplot(3,1,2) +plot(t, p_, 'b-', t, y_, 'g-', pc_, 'r-'); grid; xlabel('t/s'); ylabel('P/W'); title('Power Control'); legend('P','y','P_{cont}'); +subplot(3,1,3) +plot(t, err_); grid; xlabel('t/s'); ylabel('err/K'); title('Error'); legend('Error'); + +figure; +subplot(3,1,1) +plot(t, heatRate_); grid; xlabel('t/s'); ylabel('Theta/°'); title('Aufheizrate'); axis ([0 length(t)-1 0 5]) +subplot(3,1,2) +plot(t, P_rate_); grid; xlabel('t/s'); ylabel('Theta/°'); title('Aufheizrate'); +subplot(3,1,3) +plot(t, heatRate_); grid; xlabel('t/s'); ylabel('Theta/°'); title('Aufheizrate'); + +function [theta, s] = mass(si, dt, C, M, L, P, Td, dTheta) +s = si; +if ~isstruct(si) + alpha = 1.0; + if Td > 0 + alpha = dt/Td; + end + s = struct('e', 0, 'a', alpha, 'x', 0); +end + +s.e = s.e * (1-((L*dTheta)*dt)/(M*C)); +s.x = (1-s.a)*s.x + s.a*P*dt; +s.e = s.e + s.x; +theta = s.e/(M*C); +endfunction + +function [y, y_clamped, s] = pid(si, kp, ki, kd, kleak, x) +s = si; +if ~isstruct(si) + s = struct('p', 0, 'i', 0, 'd', 0, 'x', 0, 'y_min', -0.0, 'y_max', 1.0, 'diff_aw', 0.0); +end + +s.d = kd*(x - s.x); +s.i = kleak*s.i + ki*x + s.diff_aw; +s.p = kp*x; +s.x = x; + +y = s.p + s.i + s.d; +y_clamped = max(s.y_min, min(s.y_max, y)); + +if (y < s.y_min) + s.diff_aw = abs(y - s.y_min); +end + +if (y > s.y_max) + s.diff_aw = -abs(y - s.y_max); +end + + +endfunction + +function print_parameters(params) +align = 32; +names = fieldnames(params); +for n=1:length(names), + fprintf('%s', names{n}); + remain = align - length(names{n}); + if remain < 0 + error('Invalid variable length!'); + else + for j=1:remain + fprintf(' '); + end + fprintf('= %g %s\n', params.(names{n}), units.(names{n})); + end +end +endfunction + +endfunction +