From 9de20d7ede1bbfc9cba86f76006c24809ead7b4d Mon Sep 17 00:00:00 2001 From: Miguel Angel de Heras <mdeheras@gmail.com> Date: Thu, 13 Mar 2025 18:26:32 +0100 Subject: [PATCH] Actualizada interfaz web --- .../include/interface.html | 113 ++++--- CraterLab_camera/include/constants.h | 16 +- CraterLab_camera/include/interface.html | 308 +++++++++++++----- CraterLab_camera/include/main_m4.cpp | 23 +- CraterLab_camera/include/main_m7.cpp | 2 +- 5 files changed, 314 insertions(+), 148 deletions(-) diff --git a/CraterLab_base_giratoria/include/interface.html b/CraterLab_base_giratoria/include/interface.html index c06fdd2..ebc1488 100644 --- a/CraterLab_base_giratoria/include/interface.html +++ b/CraterLab_base_giratoria/include/interface.html @@ -11,6 +11,7 @@ const char *htmlTemplate = R"rawliteral( color: #ffffff; font-family: Arial, sans-serif; margin: 20px; + font-size: 12px } h2 { @@ -44,7 +45,7 @@ const char *htmlTemplate = R"rawliteral( input[type="text"], input[type="number"], select { - width: 100px; + width: 100%; padding: 5px; margin: 5px 0; background-color: #333; @@ -61,7 +62,7 @@ const char *htmlTemplate = R"rawliteral( /* Estilo de los sliders */ input[type="range"] { - width: 30%; + width: 100%; margin: 10px 0; } @@ -102,7 +103,6 @@ const char *htmlTemplate = R"rawliteral( border-radius: 10px; margin-bottom: 20px; border: 1px solid #333; - /* Bordes más visibles */ } /* Estilo para centrar los formularios en la pantalla */ @@ -110,52 +110,77 @@ const char *htmlTemplate = R"rawliteral( max-width: 600px; margin: 0 auto; } + + .device-360-container { + display: flex; + justify-content: space-between; + gap: 20px; + /* Espaciado entre columnas */ + } + + .device-column { + flex: 1; + text-align: center; + } + + .sync-checkbox { + text-align: center; + margin-top: 20px; + } </style> </head> <body> <!-- Sección Dispositivo 360 --> - <!-- Subsección X0 --> - <h4>X0:</h4> - <label for='x0Degrees'>Grados:</label> - <input type='text' id='x0Degrees'> - <label for='x0Duration'>Duración (s):</label> - <input type='text' id='x0Duration'> - <input type='number' id='x0Read'> - <br> - <button onclick="moveMotor('test_360','x0')">Test</button> - <button onclick="moveMotor('save_360','x0')">Save</button> - <span id="x0Message" style="color: green; display: none;">Movimiento enviado correctamente</span> - <br><br> + <div class="device-360-container"> + <!-- Columna X0 --> + <div class="device-column"> + <h4>X0:</h4> + <label for='x0Degrees'>Grados:</label><br> + <input type='text' id='x0Degrees'><br><br> + <label for='x0Duration'>Duración (s):</label> + <input type='text' id='x0Duration'> + <input type='number' id='x0Read'> + <br><br> + <button onclick="moveMotor('test_360','x0')">Test</button> + <button onclick="moveMotor('save_360','x0')">Save</button> + <span id="x0Message" style="color: green; display: none;">Movimiento enviado correctamente</span> + </div> - <!-- Subsección X1 --> - <h4>X1:</h4> - <label for='x1Degrees'>Grados:</label> - <input type='text' id='x1Degrees'> - <label for='x1Duration'>Duración (s):</label> - <input type='text' id='x1Duration'> - <input type='number' id='x1Read'> - <br> - <button onclick="moveMotor('test_360','x1')">Test</button> - <button onclick="moveMotor('save_360','x1')">Save</button> - <span id="x1Message" style="color: green; display: none;">Movimiento enviado correctamente</span> - <br><br> + <!-- Columna X1 --> + <div class="device-column"> + <h4>X1:</h4> + <label for='x1Degrees'>Grados:</label><br> + <input type='text' id='x1Degrees'><br><br> + <label for='x1Duration'>Duración (s):</label> + <input type='text' id='x1Duration'> + <input type='number' id='x1Read'> + <br><br> + <button onclick="moveMotor('test_360','x1')">Test</button> + <button onclick="moveMotor('save_360','x1')">Save</button> + <span id="x1Message" style="color: green; display: none;">Movimiento enviado correctamente</span> + </div> + + <!-- Columna Y0 --> + <div class="device-column"> + <h4>Y0:</h4> + <label for='y0Degrees'>Grados:</label><br> + <input type='text' id='y0Degrees'><br><br> + <label for='y0Duration'>Duración (s):</label> + <input type='text' id='y0Duration'> + <input type='number' id='y0Read'> + <br><br> + <button onclick="moveMotor('test_360','y0')">Test</button> + <button onclick="moveMotor('save_360','y0')">Save</button> + <span id="y0Message" style="color: green; display: none;">Movimiento enviado correctamente</span> + </div> + </div> + + <!-- Checkbox de sincronización debajo de las tres columnas --> + <div class="sync-checkbox"> + <input type='checkbox' id='syncWithInterval360'> Sincronizar con Intervalómetro + </div> - <!-- Subsección Y0 --> - <h4>Y0:</h4> - <label for='y0Degrees'>Grados:</label> - <input type='text' id='y0Degrees'> - <label for='y0Duration'>Duración (s):</label> - <input type='text' id='y0Duration'> - <input type='number' id='y0Read'> - <br> - <button onclick="moveMotor('test_360','y0')">Test</button> - <button onclick="moveMotor('save_360','y0')">Save</button> - <span id="y0Message" style="color: green; display: none;">Movimiento enviado correctamente</span> - <br><br> - <input type='checkbox' id='syncWithInterval360'> Sincronizar con Intervalómetro - <br><br> - <!-- Script para manejar las interacciones y enviar el JSON --> <script> function sendHeight() { @@ -165,8 +190,8 @@ const char *htmlTemplate = R"rawliteral( window.onload = sendHeight; window.onresize = sendHeight; - setInterval(sendHeight, 500); - + setInterval(sendHeight, 500); + function showMessage(elementId) { const messageElement = document.getElementById(elementId); if (messageElement) { diff --git a/CraterLab_camera/include/constants.h b/CraterLab_camera/include/constants.h index 2dca6da..061f1bd 100644 --- a/CraterLab_camera/include/constants.h +++ b/CraterLab_camera/include/constants.h @@ -1,9 +1,13 @@ -#define FORWARD 0 -#define BACKWARD 1 #define STOP 0 -#define IN 1 -#define OUT 2 -#define IN_OUT 3 +#define FORWARD 1 +#define BACKWARD 2 + +#define IN 3 +#define OUT 4 +#define IN_OUT 5 + + +//Posicion en la array del motor de fps #define FPS_MOTOR 4 //Definicion de los pines del shift register @@ -39,4 +43,4 @@ //Definicion de los limites del sensor lineal #define LINEAL_MAX 4*478 -#define LINEAL_MIN 0 \ No newline at end of file +#define LINEAL_MIN 4 \ No newline at end of file diff --git a/CraterLab_camera/include/interface.html b/CraterLab_camera/include/interface.html index 521a883..51d91aa 100644 --- a/CraterLab_camera/include/interface.html +++ b/CraterLab_camera/include/interface.html @@ -11,6 +11,7 @@ const char *htmlTemplate = R"rawliteral( color: #ffffff; font-family: Arial, sans-serif; margin: 20px; + font-size: 12px } h2 { @@ -40,29 +41,26 @@ const char *htmlTemplate = R"rawliteral( margin-top: 20px; } - /* Estilos de los inputs */ - input[type="text"], - input[type="number"], - select { - width: 100px; - padding: 5px; - margin: 5px 0; + + .button-bar { + display: flex; + justify-content: space-between; background-color: #333; - border: 1px solid #555; - color: #fff; + padding: 10px; border-radius: 5px; + margin-bottom: 20px; } - /* Estilos del checkbox y radio */ - input[type="checkbox"], - input[type="radio"] { - margin: 10px; - } - - /* Estilo de los sliders */ - input[type="range"] { - width: 30%; - margin: 10px 0; + .button-bar button { + background-color: #1e88e5; + border: none; + color: white; + padding: 10px 20px; + text-align: center; + font-size: 16px; + cursor: pointer; + border-radius: 5px; + transition: background-color 0.3s ease; } /* Botones */ @@ -85,78 +83,220 @@ const char *htmlTemplate = R"rawliteral( background-color: #1565c0; } - - /* Dark styling for select dropdown */ - select { - background-color: #333; - color: white; - border: 1px solid #555; - padding: 5px; + .button-bar button:hover { + background-color: #1565c0; + } + + .columns-container { + display: flex; + justify-content: space-between; + width: 100%; + + } + + .section:nth-child(1) { + flex: 22%; + /* Primera columna */ + } + + .section:nth-child(2) { + flex: 15%; + /* Segunda columna */ + } + + .section:nth-child(3) { + flex: 15%; + /* Tercera columna */ + } + + .section:nth-child(4) { + flex: 45%; + /* Cuarta columna */ } - /* Estilo para contenedores de secciones */ .section { background-color: #1e1e1e; padding: 20px; - padding-top: 0px; border-radius: 10px; margin-bottom: 20px; - border: 1px solid #333; - /* Bordes más visibles */ + margin: 5px; } - /* Estilo para centrar los formularios en la pantalla */ - .form-container { - max-width: 600px; - margin: 0 auto; - } - - iframe { - display: block; + /* Estilos de los inputs */ + input[type="text"], + input[type="number"], + select { width: 100%; - min-height: 100px; - /* Evita que sea muy pequeño al inicio */ - overflow: hidden !important; - /* Asegura que no haya barras de desplazamiento */ + padding: 5px; + margin: 5px 0; + background-color: #333; + border: 1px solid #555; + color: #fff; + border-radius: 5px; + } + + /* Estilos del checkbox y radio */ + input[type="checkbox"], + input[type="radio"] { + margin: 10px; + vertical-align: middle; + margin-right: 5px; + /* Ajusta el espacio entre el input y el texto */ + } + + /* Estilo de los sliders */ + + /*input[type="range"] { + writing-mode: bt-lr; + transform: rotate(270deg); + width: auto; + height: 150px; + display: block; + }*/ + + input[type="range"] { + width: 100%; + margin: 10px 0; + } + + /* Estilos de la capa flotante */ + #monitorLayer { + display: none; + position: fixed; + top: 10%; + left: 50%; + transform: translate(-50%, 0); + background: rgba(0, 0, 0, 0.9); + padding: 20px; + border-radius: 10px; + z-index: 1000; + width: 80%; + max-width: 800px; + } + + #monitorLayer iframe { + width: 100%; + height: 400px; + border: none; + } + + #closeMonitor { + background: red; + border: none; + color: white; + padding: 10px; + font-size: 16px; + cursor: pointer; + margin-top: 10px; + } + + .motor-camera { + display: flex; + flex-direction: column; + align-items: center; + } + + .motor-columns { + display: flex; + justify-content: space-between; + width: 100%; + } + + .motor-column { + flex: 1; + padding: 10px; + } + + .motor-buttons { + text-align: center; + margin-top: 20px; + } + + .speed-container { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + margin-bottom: 10px; + + } + + .speed-value { + display: flex; + align-items: center; + gap: 5px; + } + + #iframe360 { + width: 100%; + height: 100%; + min-height: 400px; + /* Ajusta la altura mínima según sea necesario */ border: none; } </style> </head> <body> - <div class="form-container"> - <h2>Control Bolex Paillard</h2> + + <div class="button-bar"> + <button onclick="accion()">REC</button> + <button onclick="corten()">STOP</button> + <button onclick="toggleMonitor()">SCREEN</button> + </div> + + <div id="monitorLayer"> + <iframe src="http://192.168.8.5:8000"></iframe> + <button id="closeMonitor" onclick="toggleMonitor()">Cerrar</button> + </div> + + <div class="columns-container"> <div class="section"> - <!-- Sección Motor Cámara --> <h3>Motor Cámara</h3> - <h4>Counter</h4> - <input type='number' id='frames'> - <h4>Speed</h4> - <label for='fps'>FPS:</label> - <input type='range' min='0' max='48' value='24' id='speedSlider'> - <span id='speedValueDisplay'>24</span> fps - <input type='number' id='fps'> - <input type='checkbox' id='speedCheckbox'> Activar Speed + <div class="motor-columns"> + <!-- Columna 1: Counter y Speed --> + <div class="motor-column"> + <h4>Counter</h4> + <input type='number' id='frames'> - <h4>Intervalómetro:</h4> - <label for='intervalFrames'>Frames:</label> - <input type='number' id='intervalFrames' value='10' min='1'> - <label for='intervalSeconds'>Segundos:</label> - <input type='number' id='intervalSeconds' value='1' min='1'> - <input type='checkbox' id='intervalCheckbox'> Activar Intervalómetro + <h4>Speed</h4> + <label for='fps'>FPS:</label> + <div class="speed-container"> + <input type='range' min='0' max='48' value='24' id='speedSlider'> + <div class="speed-value"> + <span id='speedValueDisplay'>24</span> <span>fps</span> + </div> + </div> + <input type='number' id='fps'><br><br> + <input type='checkbox' id='speedCheckbox'>Speed + </div> - <h4>Dirección:</h4> - <input type='radio' id='forward' name='direction' value='forward' checked> Forward - <input type='radio' id='backward' name='direction' value='backward'> Backward - <br><br> - <button onclick="sendMotorCameraData('test_motor')">Test</button> - <button onclick="sendMotorCameraData('save_motor')">Save</button> - <button onclick="stop()">Stop</button> - <span id="motorCameraMessage" style="color: green; display: none;">Datos enviados correctamente</span> + <!-- Columna 2: Intervalómetro y Dirección --> + <div class="motor-column"> + <h4>Intervalómetro:</h4> + <label for='intervalFrames'>Frames:</label> + <input type='number' id='intervalFrames' value='10' min='1'><br><br> + <label for='intervalSeconds'>Segundos:</label> + <input type='number' id='intervalSeconds' value='1' min='1'><br><br> + <input type='checkbox' id='intervalCheckbox'> Intervalómetro + + <h4>Dirección:</h4> + <input type='radio' id='forward' name='direction' value='forward' checked> Forward<br> + <input type='radio' id='backward' name='direction' value='backward'> Backward + </div> + </div> + + <!-- Botones centrados abajo --> + <div class="motor-buttons"> + <button onclick="sendMotorCameraData('test_motor')">Test</button> + <button onclick="sendMotorCameraData('save_motor')">Save</button> + <button onclick="stop()">Stop</button> + <span id="motorCameraMessage" style="color: green; display: none;">Datos enviados correctamente</span> + </div> </div> + <div class="section"> - <!-- Sección Shutter --> <h3>Shutter</h3> <h4>Fade In/Out Frames:</h4> <p>% apertura inicial: <span id='fadePercentDisplay'>0</span></p> @@ -166,22 +306,16 @@ const char *htmlTemplate = R"rawliteral( <input type='range' min='0' max='100' value='10' id='fadeFramesSlider'> <h4>Fade Activación:</h4> - <input type='checkbox' id='fadeInCheckbox'> Activar Fade In - <input type='checkbox' id='fadeOutCheckbox'> Activar Fade Out + <input type='checkbox' id='fadeInCheckbox'> Fade In + <input type='checkbox' id='fadeOutCheckbox'> Fade Out <br><br> <input type='checkbox' id='syncWithIntervalCheckbox'> Sincronizar con Intervalómetro - <br><br> + <br><br><br> <button onclick="sendShutterData('save_shutter')">Save</button> <span id="shutterMessage" style="color: green; display: none;">Datos enviados correctamente</span> </div> - <div class="section"> - <!-- Sección Monitor de Cámara --> - <h3>Monitor de Cámara</h3> - <iframe src="http://192.168.8.5:8000" width="100%" height="400px" style="border: none;"></iframe> - </div> - <div class="section"> <!-- Sección Óptica --> <h3>Óptica</h3> @@ -213,23 +347,17 @@ const char *htmlTemplate = R"rawliteral( </div> <div class="section"> - <!-- Sección Dispositivo 360 --> <h3>Dispositivo 360</h3> - <iframe id="iframe360" src="http://192.168.8.3" width="100%" height="400px" style="border: none;"></iframe> - <!-- <iframe id="iframe360" src="iframe.html" width="100%" height="400px" style="border: none;"></iframe> --> - </div> - - <div class="section"> - <!-- Sección Rodaje --> - <h3>Rodaje</h3> - <button onclick="accion()">ACCIÓN !!!</button> - <button onclick="corten()">CORTEN !!!</button> - <span id="accionMessage" style="color: green; display: none;">Mensaje enviado correctamente</span> - <br><br> + <iframe id="iframe360" src="http://192.168.8.3"></iframe> </div> </div> + <!-- Script para manejar las interacciones y enviar el JSON --> <script> + function toggleMonitor() { + let monitorLayer = document.getElementById('monitorLayer'); + monitorLayer.style.display = (monitorLayer.style.display === 'none' || monitorLayer.style.display === '') ? 'block' : 'none'; + } window.addEventListener("message", function (event) { console.log("Mensaje recibido:", event.data); // Depuración @@ -456,7 +584,7 @@ const char *htmlTemplate = R"rawliteral( } // Llama a updateSensors cada 500ms - setInterval(updateSensors, 100); + setInterval(updateSensors, 500); </script> </body> diff --git a/CraterLab_camera/include/main_m4.cpp b/CraterLab_camera/include/main_m4.cpp index afb2014..73e218e 100644 --- a/CraterLab_camera/include/main_m4.cpp +++ b/CraterLab_camera/include/main_m4.cpp @@ -15,7 +15,7 @@ bool motorIsSpeedActive = false; int motorIntervalFrames = 1; int motorIntervalSeconds = 1; bool motorIsIntervalActive = false; -bool motorDirection = 1; +bool motorDirection = STOP; // Shutter int shutterFadePercent = 0; @@ -116,6 +116,7 @@ void linear_motor_control(int motor, int SPEED) else stop(motor); } +unsigned long time_lineal_motor = millis(); float time_move_for_move_position_motor[6] = {0, 0, 0, 0, 0, 0}; unsigned long time_refresh_position_motor[6] = { millis(), millis(), millis(), millis(), millis(), millis()}; float position_motor[6] = { 0, 0, 0, 0, 0, 0}; @@ -130,6 +131,7 @@ void config_position_motor(int motor, float position) //Configuracion posicion e { position_motor_objective[motor] = position; Setpoint_Linear = position; + time_lineal_motor = millis(); } else { @@ -166,10 +168,10 @@ static volatile unsigned long lastTimeDebounce = 0; //Tiempo del rebote static volatile bool force_stop = false; //Tiempo del rebote void fps_count_state() { - if((digitalRead(sensor_fps)&&(micros()-lastTimeDebounce>= 100))&&(!closed)) + if((digitalRead(sensor_fps)&&(micros()-lastTimeDebounce>=100))&&(!closed)) { if(motorDirection==FORWARD) FramesCount++; - else FramesCount--; + else if(motorDirection==BACKWARD) FramesCount--; lastTimeDebounce = micros(); fps_temp = 1000000./(float)(micros()-time_fps); if(fps_temp<70) motorSpeedRead = fps_temp; @@ -183,7 +185,7 @@ void fps_count_state() { else if((digitalRead(sensor_fps)&&(micros()-lastTimeDebounce >= 150))&&(closed)) { if(motorDirection==FORWARD) FramesCount++; - else FramesCount--; + else if(motorDirection==BACKWARD) FramesCount--; lastTimeDebounce = micros(); closed = false; force_stop = true; @@ -275,13 +277,20 @@ void ini_motors() stop(3);*/ } + void refresh_position_motors() { position_motor[0] = map(read_lineal_motor(),LINEAL_MAX,LINEAL_MIN,0,100000)/1000; #if PID_ENABLE - Input_Linear = position_motor[0]; - PID_LINEAR.Compute(); - linear_motor_control(0, Output_Linear); + + if ((position_motor[0]>=(Setpoint_Linear+1))||(position_motor[0]<=(Setpoint_Linear-1))) time_lineal_motor = millis(); + if ((millis()-time_lineal_motor)<10) + { + Input_Linear = position_motor[0]; + PID_LINEAR.Compute(); + linear_motor_control(0, Output_Linear); + } + /*Input = (double)fps_temp; // Lectura del encoder óptico. El valor del contador se incrementa/decrementa a través de las interrupciones extrenas (pines 2 y 3). if(myPID.Compute()) analogWrite(EN_MOTOR[4], abs(Output)); // Por el primer pin sale la señal PWM. diff --git a/CraterLab_camera/include/main_m7.cpp b/CraterLab_camera/include/main_m7.cpp index 2a78492..ef7dddc 100644 --- a/CraterLab_camera/include/main_m7.cpp +++ b/CraterLab_camera/include/main_m7.cpp @@ -318,7 +318,7 @@ void loop() { client.println("Content-Type: application/json"); client.println(); String response = "{\"sensors\":[" + String(motorSpeedRead) + "," + String(FadePercentRead) + "," + String(FramesCount) + "]}"; - client.print(response); + client.print(response); } else { // Respuesta para servir la interfaz HTML client.println("HTTP/1.1 200 OK");