Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c92745d2bc |
+9
-29
@@ -44,23 +44,9 @@ def get_float(values, strId):
|
|||||||
window['-StartCycle-'].update(disabled = True)
|
window['-StartCycle-'].update(disabled = True)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def read_pi_coeff(values, key, params, param_key):
|
|
||||||
# PI coefficient is entered as a human value and stored as Q8 fixed-point
|
|
||||||
# (value * 256), clamped to the 16-bit range expected by the firmware.
|
|
||||||
# On a bad/empty field the previous stored value is kept and Start is disabled.
|
|
||||||
try:
|
|
||||||
params[param_key] = max(0, min(65535, int(float(values[key]) * 256)))
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
window['-StartCycle-'].update(disabled = True)
|
|
||||||
|
|
||||||
def shorten(i):
|
def shorten(i):
|
||||||
return "{:.2f}".format(round(i, 2))
|
return "{:.2f}".format(round(i, 2))
|
||||||
|
|
||||||
def shorten4(i):
|
|
||||||
# Higher-precision readout (0.0001) for temperature/current — needed to see
|
|
||||||
# small fluctuations while tuning the PI controller for temperature stability.
|
|
||||||
return "{:.4f}".format(round(i, 4))
|
|
||||||
|
|
||||||
|
|
||||||
def set_initial_params():
|
def set_initial_params():
|
||||||
params = {}
|
params = {}
|
||||||
@@ -133,13 +119,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
event, values = window.read(timeout=GUI_TIMEOUT_INTERVAL)
|
event, values = window.read(timeout=GUI_TIMEOUT_INTERVAL)
|
||||||
|
|
||||||
if values:
|
|
||||||
read_pi_coeff(values, '-InputKp1-', params, 'ProportionalCoeff_1')
|
|
||||||
read_pi_coeff(values, '-InputKi1-', params, 'IntegralCoeff_1')
|
|
||||||
read_pi_coeff(values, '-InputKp2-', params, 'ProportionalCoeff_2')
|
|
||||||
read_pi_coeff(values, '-InputKi2-', params, 'IntegralCoeff_2')
|
|
||||||
|
|
||||||
enable_manual_settings = window['-EnableManualSettings-'].get()
|
enable_manual_settings = window['-EnableManualSettings-'].get()
|
||||||
if current_and_temperature_settings_available:
|
if current_and_temperature_settings_available:
|
||||||
window['-EnableT1-'].update(disabled = enable_manual_settings)
|
window['-EnableT1-'].update(disabled = enable_manual_settings)
|
||||||
@@ -452,15 +432,15 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
update_data_lists()
|
update_data_lists()
|
||||||
|
|
||||||
window['-TOUT_1-'].update(gui.READ_TEMPERATURE_TEXT+' 1: '+shorten4(data['Temp_1'])+' C')
|
window['-TOUT_1-'].update(gui.READ_TEMPERATURE_TEXT+' 1: '+shorten(data['Temp_1'])+' C')
|
||||||
window['-TOUT_2-'].update(gui.READ_TEMPERATURE_TEXT+' 2: '+shorten4(data['Temp_2'])+' C')
|
window['-TOUT_2-'].update(gui.READ_TEMPERATURE_TEXT+' 2: '+shorten(data['Temp_2'])+' C')
|
||||||
window['-IOUT_1-'].update(gui.READ_CURRENT_TEXT+' 1: '+shorten4(data['I1'])+' мА')
|
window['-IOUT_1-'].update(gui.READ_CURRENT_TEXT+' 1: '+shorten(data['I1'])+' мА')
|
||||||
window['-IOUT_2-'].update(gui.READ_CURRENT_TEXT+' 2: '+shorten4(data['I2'])+' мА')
|
window['-IOUT_2-'].update(gui.READ_CURRENT_TEXT+' 2: '+shorten(data['I2'])+' мА')
|
||||||
window['-DateTime-'].update(data['datetime'].strftime('%d-%m-%Y %H:%M:%S:%f')[:-3])
|
window['-DateTime-'].update(data['datetime'].strftime('%d-%m-%Y %H:%M:%S:%f')[:-3])
|
||||||
window['-TTerm1-'].update('T терм 1: '+shorten4(data['Temp_Ext_1'])+' C')
|
window['-TTerm1-'].update('T терм 1: '+shorten(data['Temp_Ext_1'])+' C')
|
||||||
window['-TTerm2-'].update('T терм 2: '+shorten4(data['Temp_Ext_2'])+' C')
|
window['-TTerm2-'].update('T терм 2: '+shorten(data['Temp_Ext_2'])+' C')
|
||||||
window['-I1_PANEL-'].update('I1: '+shorten4(data['I1'])+' мА')
|
window['-I1_PANEL-'].update('I1: '+shorten(data['I1'])+' мА')
|
||||||
window['-I2_PANEL-'].update('I2: '+shorten4(data['I2'])+' мА')
|
window['-I2_PANEL-'].update('I2: '+shorten(data['I2'])+' мА')
|
||||||
window['-3V3-'].update('3V3: '+shorten(data['MON_3V3'])+' В')
|
window['-3V3-'].update('3V3: '+shorten(data['MON_3V3'])+' В')
|
||||||
window['-5V1-'].update('5V1: '+shorten(data['MON_5V1'])+' В')
|
window['-5V1-'].update('5V1: '+shorten(data['MON_5V1'])+' В')
|
||||||
window['-5V2-'].update('5V2: '+shorten(data['MON_5V2'])+' В')
|
window['-5V2-'].update('5V2: '+shorten(data['MON_5V2'])+' В')
|
||||||
|
|||||||
@@ -88,9 +88,6 @@ def request_state(prt):
|
|||||||
|
|
||||||
def send_control_parameters(prt, params):
|
def send_control_parameters(prt, params):
|
||||||
# Send control parameters
|
# Send control parameters
|
||||||
print("Sending PI coeffs (Q8): P1={} I1={} P2={} I2={}".format(
|
|
||||||
params['ProportionalCoeff_1'], params['IntegralCoeff_1'],
|
|
||||||
params['ProportionalCoeff_2'], params['IntegralCoeff_2']))
|
|
||||||
hexstring = cmd.encode_Input(params)
|
hexstring = cmd.encode_Input(params)
|
||||||
cmd.send_DECODE_ENABLE(prt,hexstring)
|
cmd.send_DECODE_ENABLE(prt,hexstring)
|
||||||
time.sleep(WAIT_AFTER_SEND)
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
@@ -103,9 +100,6 @@ def send_control_parameters(prt, params):
|
|||||||
|
|
||||||
def send_task_command(prt, sending_param):
|
def send_task_command(prt, sending_param):
|
||||||
# Send task command (TASK_ENABLE state in firmware)
|
# Send task command (TASK_ENABLE state in firmware)
|
||||||
print("Sending PI coeffs (Q8): P1={} I1={} P2={} I2={}".format(
|
|
||||||
sending_param['ProportionalCoeff_1'], sending_param['IntegralCoeff_1'],
|
|
||||||
sending_param['ProportionalCoeff_2'], sending_param['IntegralCoeff_2']))
|
|
||||||
hexstring = cmd.create_TaskEnableCommand(sending_param)
|
hexstring = cmd.create_TaskEnableCommand(sending_param)
|
||||||
cmd.send_TASK_ENABLE(prt,hexstring)
|
cmd.send_TASK_ENABLE(prt,hexstring)
|
||||||
time.sleep(WAIT_AFTER_SEND)
|
time.sleep(WAIT_AFTER_SEND)
|
||||||
|
|||||||
@@ -19,11 +19,6 @@ SET_MANUAL_MODE_TEXT = 'Ручной режим ввода'
|
|||||||
SET_TEXT_WIDTH = 34
|
SET_TEXT_WIDTH = 34
|
||||||
SET_INPUT_WIDTH = 5
|
SET_INPUT_WIDTH = 5
|
||||||
|
|
||||||
SET_KP_TEXT_1 = 'Коэфф. P регулятора лазера 1 (0-255):'
|
|
||||||
SET_KI_TEXT_1 = 'Коэфф. I регулятора лазера 1 (0-255):'
|
|
||||||
SET_KP_TEXT_2 = 'Коэфф. P регулятора лазера 2 (0-255):'
|
|
||||||
SET_KI_TEXT_2 = 'Коэфф. I регулятора лазера 2 (0-255):'
|
|
||||||
|
|
||||||
SET_MIN_TEMPERATURE_TEXT_1 = 'Минимальная температура лазера 1 (C):'
|
SET_MIN_TEMPERATURE_TEXT_1 = 'Минимальная температура лазера 1 (C):'
|
||||||
SET_MAX_TEMPERATURE_TEXT_1 = 'Максимальная температура лазера 1 (C):'
|
SET_MAX_TEMPERATURE_TEXT_1 = 'Максимальная температура лазера 1 (C):'
|
||||||
SET_DELTA_TEMPERATURE_TEXT_1 = 'Шаг дискретизации температуры лазера 1 (0.05-1 С):'
|
SET_DELTA_TEMPERATURE_TEXT_1 = 'Шаг дискретизации температуры лазера 1 (0.05-1 С):'
|
||||||
@@ -58,7 +53,7 @@ GRAPH_I_MAX = 1.0 # mA
|
|||||||
READ_TEMPERATURE_TEXT = 'Температура лазера'
|
READ_TEMPERATURE_TEXT = 'Температура лазера'
|
||||||
READ_CURRENT_TEXT = 'Ток фотодиода'
|
READ_CURRENT_TEXT = 'Ток фотодиода'
|
||||||
|
|
||||||
VOLTAGE_TEXT_WIDTH = 18
|
VOLTAGE_TEXT_WIDTH = 15
|
||||||
H_SEPARATOR_PAD = (1, 20)
|
H_SEPARATOR_PAD = (1, 20)
|
||||||
OUTPUT_TEXT_PAD = (5, (20, 5))
|
OUTPUT_TEXT_PAD = (5, (20, 5))
|
||||||
WINDOW_MARGIN = (60, 90)
|
WINDOW_MARGIN = (60, 90)
|
||||||
@@ -115,13 +110,7 @@ def setup_gui(params):
|
|||||||
|
|
||||||
[sg.Text(SET_CURRENT_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
[sg.Text(SET_CURRENT_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
||||||
sg.Input(params['Iset_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI1-', disabled = True)],
|
sg.Input(params['Iset_1'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI1-', disabled = True)],
|
||||||
|
|
||||||
[sg.Text(SET_KP_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
|
||||||
sg.Input(params['ProportionalCoeff_1']/256, size=(SET_INPUT_WIDTH,1), key='-InputKp1-')],
|
|
||||||
|
|
||||||
[sg.Text(SET_KI_TEXT_1, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
|
||||||
sg.Input(params['IntegralCoeff_1']/256, size=(SET_INPUT_WIDTH,1), key='-InputKi1-')],
|
|
||||||
|
|
||||||
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
|
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
|
||||||
|
|
||||||
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 1: ', key='-TOUT_1-')],
|
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 1: ', key='-TOUT_1-')],
|
||||||
@@ -140,15 +129,9 @@ def setup_gui(params):
|
|||||||
layout_input_col2 = [[sg.Text(SET_TEMPERATURE_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
layout_input_col2 = [[sg.Text(SET_TEMPERATURE_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
||||||
sg.Input(params['Temp_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT2-', disabled = True)],
|
sg.Input(params['Temp_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputT2-', disabled = True)],
|
||||||
|
|
||||||
[sg.Text(SET_CURRENT_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
[sg.Text(SET_CURRENT_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
||||||
sg.Input(params['Iset_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI2-', disabled = True)],
|
sg.Input(params['Iset_2'], disabled_readonly_background_color="Gray", size=(SET_INPUT_WIDTH,1), key='-InputI2-', disabled = True)],
|
||||||
|
|
||||||
[sg.Text(SET_KP_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
|
||||||
sg.Input(params['ProportionalCoeff_2']/256, size=(SET_INPUT_WIDTH,1), key='-InputKp2-')],
|
|
||||||
|
|
||||||
[sg.Text(SET_KI_TEXT_2, size=(SET_TEXT_WIDTH, 1)), sg.Push(),
|
|
||||||
sg.Input(params['IntegralCoeff_2']/256, size=(SET_INPUT_WIDTH,1), key='-InputKi2-')],
|
|
||||||
|
|
||||||
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
|
[sg.HSeparator(pad=H_SEPARATOR_PAD)],
|
||||||
|
|
||||||
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 2: ', key='-TOUT_2-')],
|
[sg.Push(), sg.Text(READ_TEMPERATURE_TEXT+' 2: ', key='-TOUT_2-')],
|
||||||
|
|||||||
@@ -215,9 +215,13 @@ class Protocol:
|
|||||||
# ---- Raw I/O
|
# ---- Raw I/O
|
||||||
|
|
||||||
def send_raw(self, data: bytes) -> None:
|
def send_raw(self, data: bytes) -> None:
|
||||||
|
if self._serial is None or not self._serial.is_open:
|
||||||
|
raise CommunicationError("Serial port is not connected")
|
||||||
self._serial.write(data)
|
self._serial.write(data)
|
||||||
|
|
||||||
def receive_raw(self, length: int) -> bytes:
|
def receive_raw(self, length: int) -> bytes:
|
||||||
|
if self._serial is None or not self._serial.is_open:
|
||||||
|
raise CommunicationError("Serial port is not connected")
|
||||||
return self._serial.read(length)
|
return self._serial.read(length)
|
||||||
|
|
||||||
# ---- Static encoding helpers (no connection required) ---------------
|
# ---- Static encoding helpers (no connection required) ---------------
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
|
||||||
|
set "PROJECT_DIR=%~dp0"
|
||||||
|
pushd "%PROJECT_DIR%" >nul || (
|
||||||
|
echo Failed to switch to project directory: %PROJECT_DIR%
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
set "VENV_DIR=.venv"
|
||||||
|
set "VENV_PYTHON=%VENV_DIR%\Scripts\python.exe"
|
||||||
|
set "VENV_ACTIVATE=%VENV_DIR%\Scripts\activate.bat"
|
||||||
|
|
||||||
|
if exist "%VENV_PYTHON%" goto venv_ready
|
||||||
|
|
||||||
|
echo Creating virtual environment...
|
||||||
|
call :find_python
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
|
||||||
|
"%PYTHON_EXE%" %PYTHON_ARGS% -m venv "%VENV_DIR%"
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
|
||||||
|
:venv_ready
|
||||||
|
|
||||||
|
call "%VENV_ACTIVATE%"
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
|
||||||
|
if exist "requirements.txt" (
|
||||||
|
echo Installing dependencies...
|
||||||
|
python -m pip install --disable-pip-version-check -r requirements.txt
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
) else (
|
||||||
|
echo requirements.txt not found. Skipping dependency installation.
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Starting _device_main.py...
|
||||||
|
python _device_main.py
|
||||||
|
set "EXIT_CODE=%ERRORLEVEL%"
|
||||||
|
|
||||||
|
popd >nul
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:find_python
|
||||||
|
where py >nul 2>&1
|
||||||
|
if not errorlevel 1 (
|
||||||
|
set "PYTHON_EXE=py"
|
||||||
|
set "PYTHON_ARGS=-3"
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
|
||||||
|
where python >nul 2>&1
|
||||||
|
if not errorlevel 1 (
|
||||||
|
set "PYTHON_EXE=python"
|
||||||
|
set "PYTHON_ARGS="
|
||||||
|
exit /b 0
|
||||||
|
)
|
||||||
|
|
||||||
|
echo Python 3 was not found. Install Python and try again.
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:error
|
||||||
|
set "EXIT_CODE=%ERRORLEVEL%"
|
||||||
|
echo Script failed with exit code %EXIT_CODE%.
|
||||||
|
popd >nul
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
Reference in New Issue
Block a user