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");