first commit
This commit is contained in:
commit
2c599aaa51
39
CraterLab_base_giratoria/include/README
Normal file
39
CraterLab_base_giratoria/include/README
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
9
CraterLab_base_giratoria/include/constants.h
Normal file
9
CraterLab_base_giratoria/include/constants.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#define DEBUG_M4 false
|
||||
#define DEBUG_M7 false
|
||||
#define PULSE_REV 400
|
||||
#define REDUCTION_XY 5
|
||||
#define REDUCTION_A 60
|
||||
const int EN[3] = {10, 7, 4};
|
||||
const int DIRP[3] = {9, 6, 3};
|
||||
const int PUL[3] = {8, 5, 2};
|
||||
const int FC[3] = {51, 53, 49};
|
259
CraterLab_base_giratoria/include/interface.html
Normal file
259
CraterLab_base_giratoria/include/interface.html
Normal file
|
@ -0,0 +1,259 @@
|
|||
// Plantilla HTML
|
||||
const char *htmlTemplate = R"rawliteral(
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<style>
|
||||
/* Tema oscuro básico */
|
||||
body {
|
||||
background-color: #1e1e1e;
|
||||
color: #ffffff;
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #cccccc;
|
||||
/* Gris claro */
|
||||
font-size: 32px;
|
||||
border-bottom: 2px solid #555555;
|
||||
/* Un borde gris medio */
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #bbbbbb;
|
||||
/* Gris medio-claro */
|
||||
font-size: 20px;
|
||||
margin-top: 30px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #444444;
|
||||
/* Un borde gris oscuro */
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: #dddddd;
|
||||
/* Blanco roto o gris muy claro */
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* Estilos de los inputs */
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select {
|
||||
width: 100px;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Estilo de los sliders */
|
||||
input[type="range"] {
|
||||
width: 30%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* Botones */
|
||||
button {
|
||||
background-color: #1e88e5;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 10px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #1565c0;
|
||||
}
|
||||
|
||||
|
||||
/* Dark styling for select dropdown */
|
||||
select {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
border: 1px solid #555;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
/* Estilo para centrar los formularios en la pantalla */
|
||||
.form-container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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() {
|
||||
const height = document.documentElement.scrollHeight || document.body.scrollHeight;
|
||||
window.parent.postMessage(height, "*");
|
||||
}
|
||||
|
||||
window.onload = sendHeight;
|
||||
window.onresize = sendHeight;
|
||||
setInterval(sendHeight, 500);
|
||||
|
||||
function showMessage(elementId) {
|
||||
const messageElement = document.getElementById(elementId);
|
||||
if (messageElement) {
|
||||
messageElement.style.display = 'inline';
|
||||
setTimeout(() => {
|
||||
messageElement.style.display = 'none';
|
||||
}, 3000); // Mostrar el mensaje durante 3 segundos
|
||||
}
|
||||
}
|
||||
|
||||
function moveMotor(type_mode, motor) {
|
||||
const degrees = document.getElementById(`${motor}Degrees`).value;
|
||||
const duration = document.getElementById(`${motor}Duration`).value;
|
||||
const syncWithInterval = document.getElementById('syncWithInterval360').checked;
|
||||
|
||||
const motorData = {
|
||||
type: type_mode,
|
||||
motor: motor,
|
||||
degrees: degrees,
|
||||
duration: duration,
|
||||
syncWithInterval: syncWithInterval
|
||||
};
|
||||
fetch('/moveMotor360', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(motorData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage(`${motor}Message`))
|
||||
.catch(error => console.error('Motor Error:', error));
|
||||
}
|
||||
|
||||
function updatex0Position() {
|
||||
fetch('/x0Read')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('x0Read').value = data.x0Read;
|
||||
})
|
||||
.catch(error => console.error('Error al obtener x0:', error));
|
||||
}
|
||||
|
||||
function updatex1Position() {
|
||||
fetch('/x1Read')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('x1Read').value = data.x1Read;
|
||||
})
|
||||
.catch(error => console.error('Error al obtener x1:', error));
|
||||
}
|
||||
|
||||
function updatey0Position() {
|
||||
fetch('/y0Read')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('y0Read').value = data.y0Read;
|
||||
})
|
||||
.catch(error => console.error('Error al obtener y0:', error));
|
||||
}
|
||||
|
||||
function updateSensors() {
|
||||
fetch('/sensors')
|
||||
.then(response => response.json()) // Parsear la respuesta como JSON
|
||||
.then(data => {
|
||||
if (data.sensors && Array.isArray(data.sensors)) {
|
||||
const sensorValues = data.sensors;
|
||||
// Asignar los valores a los elementos de la interfaz
|
||||
if (sensorValues.length >= 1) {
|
||||
document.getElementById('x0Read').value = sensorValues[0];
|
||||
}
|
||||
if (sensorValues.length >= 2) {
|
||||
document.getElementById('x1Read').value = sensorValues[1];
|
||||
}
|
||||
if (sensorValues.length >= 3) {
|
||||
document.getElementById('y0Read').value = sensorValues[2];
|
||||
}
|
||||
} else {
|
||||
console.error('Estructura inesperada:', data);
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error al obtener sensores:', error));
|
||||
}
|
||||
|
||||
// Llama a updateSensors cada 500ms
|
||||
setInterval(updateSensors, 500);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
)rawliteral";
|
416
CraterLab_base_giratoria/include/main_m4.cpp
Normal file
416
CraterLab_base_giratoria/include/main_m4.cpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <RPC.h>
|
||||
#include <constants.h>
|
||||
|
||||
using namespace rtos;
|
||||
|
||||
Thread sensorThread;
|
||||
|
||||
#define x1_axis 0
|
||||
#define y0_axis 1
|
||||
#define x0_axis 2
|
||||
|
||||
#define RIGHT false
|
||||
#define LEFT true
|
||||
#define STOP 0
|
||||
#define ZERO 1
|
||||
#define CONTINUOUS 2
|
||||
#define ANGLE_MODE 3
|
||||
|
||||
|
||||
// Dispositivo 360
|
||||
int x0Degrees = 0;
|
||||
unsigned long x0Duration = 10000;
|
||||
int x1Degrees = 0;
|
||||
unsigned long x1Duration = 10000;
|
||||
int y0Degrees = 0;
|
||||
unsigned long y0Duration = 10000;
|
||||
bool syncx0WithInterval360 = false;
|
||||
bool syncx1WithInterval360 = false;
|
||||
bool syncy0WithInterval360 = false;
|
||||
bool isAction[3] = {false, false, false};
|
||||
int mode = STOP;
|
||||
|
||||
|
||||
#if defined(ARDUINO_GIGA_M7)
|
||||
#define debug Serial
|
||||
#elif defined(ARDUINO_GIGA_M4)
|
||||
#define debug RPC
|
||||
#endif
|
||||
|
||||
#define TIME_PULSE_XY 2500
|
||||
#define TIME_PULSE_A 500
|
||||
|
||||
bool direction[3] = {RIGHT, RIGHT, RIGHT};
|
||||
|
||||
unsigned long time_fc_zero[3] = {millis(), millis(), millis()};
|
||||
bool enable_zero[3] = {true, true, true};
|
||||
|
||||
void search_zero()
|
||||
{
|
||||
time_fc_zero[x1_axis] = millis();
|
||||
while(digitalRead(FC[x1_axis])||((millis()-time_fc_zero[x1_axis])<10))
|
||||
{
|
||||
digitalWrite(PUL[x1_axis], HIGH);
|
||||
delayMicroseconds(2000);
|
||||
digitalWrite(PUL[x1_axis], LOW);
|
||||
delayMicroseconds(2000);
|
||||
if(digitalRead(FC[x1_axis])) time_fc_zero[x1_axis] = millis();
|
||||
}
|
||||
time_fc_zero[y0_axis] = millis();
|
||||
while(digitalRead(FC[y0_axis])||((millis()-time_fc_zero[y0_axis])<10))
|
||||
{
|
||||
digitalWrite(PUL[y0_axis], HIGH);
|
||||
delayMicroseconds(2000);
|
||||
digitalWrite(PUL[y0_axis], LOW);
|
||||
delayMicroseconds(2000);
|
||||
if(digitalRead(FC[y0_axis])) time_fc_zero[y0_axis] = millis();
|
||||
};
|
||||
time_fc_zero[x0_axis] = millis();
|
||||
while(digitalRead(FC[x0_axis])||((millis()-time_fc_zero[x0_axis])<10))
|
||||
{
|
||||
digitalWrite(PUL[x0_axis], HIGH);
|
||||
delayMicroseconds(250);
|
||||
digitalWrite(PUL[x0_axis], LOW);
|
||||
delayMicroseconds(250);
|
||||
if(digitalRead(FC[x0_axis])) time_fc_zero[x0_axis] = millis();
|
||||
}
|
||||
}
|
||||
|
||||
int angle_pulses[3] = {0, 0, 0}; //Varaible temporal de pulsos
|
||||
float axis_angle[3] = {0, 0, 0}; //Angulo actual
|
||||
|
||||
float angleRead(int axis)
|
||||
{
|
||||
int sensorReading = angle_pulses[axis];
|
||||
float reduction = REDUCTION_XY;
|
||||
if (axis==2) reduction = REDUCTION_A;
|
||||
return (360*sensorReading/(reduction*PULSE_REV));
|
||||
}
|
||||
|
||||
int axis_pulses[3] = {0, 0, 0}; //Pulsos necesarios para llegar al angulo indicado
|
||||
int axis_direction[3] = {1, 1, 0}; //Direccion de giro
|
||||
int angle_pulses_MAX[3] = {0, 0, 0}; //Pulsos necesarios para dar una vuelta completa
|
||||
int angle_pulses_ant[3] = {0, 0, 0}; //Varaible temporal de pulsos
|
||||
bool flag_search[3] = {false, false, false};
|
||||
bool flag_equal[3] = {true, true, true};
|
||||
bool flag_refresh[3] = {false, false, false};
|
||||
|
||||
unsigned long time_axis[3] = { millis(), millis(), millis()};
|
||||
unsigned long time_parts[3] = {10, 10, 10};
|
||||
unsigned long time_pulse[3] = {TIME_PULSE_XY, TIME_PULSE_XY, TIME_PULSE_A};
|
||||
int ant_angle[3] = {0, 0, 0};
|
||||
|
||||
void stop_all()
|
||||
{
|
||||
for(int i=0; i<3; i++) flag_refresh[i] = false;
|
||||
}
|
||||
|
||||
#define RESOLUTION_ANGLE 0.25
|
||||
float axis_angle_ant[3] = {0,0,0};
|
||||
|
||||
void search_angle(int axis, int angle, unsigned long time_initial, unsigned long time_final)
|
||||
{
|
||||
if(isAction[axis])
|
||||
{
|
||||
axis_angle[axis] = angleRead(axis);
|
||||
if((axis_angle[axis]>((float)angle+RESOLUTION_ANGLE))||(axis_angle[axis]<((float)angle-RESOLUTION_ANGLE)))
|
||||
{
|
||||
if (axis_angle_ant[axis]!=axis_angle[axis])
|
||||
{
|
||||
#if DEBUG_M4
|
||||
RPC.print(axis_angle[axis]);
|
||||
RPC.print(" ");
|
||||
RPC.println(angle);
|
||||
#endif
|
||||
axis_angle_ant[axis] = axis_angle[axis];
|
||||
}
|
||||
if (flag_search[axis])
|
||||
{
|
||||
flag_search[axis] = false;
|
||||
#if DEBUG_M4
|
||||
RPC.print(axis_angle[axis]);
|
||||
RPC.print(" ");
|
||||
RPC.print(angle);
|
||||
#endif
|
||||
if (axis_angle[axis]<(angle + RESOLUTION_ANGLE)) direction[axis] = RIGHT;
|
||||
else direction[axis] = LEFT;
|
||||
if ((abs(axis_angle[axis])>360)||(abs(angle)>360))enable_zero[axis] = false;
|
||||
else enable_zero[axis] = true;
|
||||
if((axis==y0_axis)||(axis==x0_axis)) direction[axis]=!direction[axis];
|
||||
digitalWrite(DIRP[axis], direction[axis]);
|
||||
if (axis!=x0_axis) axis_pulses[axis] = map(abs(angle-axis_angle[axis]), 0, 359, 0, PULSE_REV*REDUCTION_XY);
|
||||
else axis_pulses[axis] = map(abs(angle-axis_angle[axis]), 0, 359, 0, PULSE_REV*REDUCTION_A);
|
||||
time_pulse[axis] = ((1000/2)*(time_final-time_initial)/axis_pulses[axis]); //1000 es conversion de milisegundos a microsegundos entre dos porque es tiempo de 0 a 1
|
||||
if((time_pulse[axis]<TIME_PULSE_XY)&&(axis<=y0_axis)) time_pulse[axis]=TIME_PULSE_XY;
|
||||
else if((time_pulse[axis]<TIME_PULSE_A)&&(axis==x0_axis)) time_pulse[axis]=TIME_PULSE_A;
|
||||
#if DEBUG_M4
|
||||
RPC.print(" ");
|
||||
RPC.print(axis_pulses[axis]);
|
||||
RPC.print(" ");
|
||||
RPC.println(time_pulse[axis]);
|
||||
#endif
|
||||
flag_refresh[axis] = true;
|
||||
}
|
||||
}
|
||||
else if((axis_angle[axis]<=((float)angle+RESOLUTION_ANGLE))&&(axis_angle[axis]>=((float)angle-RESOLUTION_ANGLE))) flag_refresh[axis] = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long time_refresh_x = micros();
|
||||
unsigned long time_refresh_y = micros();
|
||||
unsigned long time_refresh_a = micros();
|
||||
bool state_x = false;
|
||||
bool state_y = false;
|
||||
bool state_a = false;
|
||||
void refresh_steppers()
|
||||
{
|
||||
if(((micros()-time_refresh_x)>=time_pulse[x1_axis])&&(flag_refresh[x1_axis]))
|
||||
{
|
||||
time_refresh_x = micros();
|
||||
digitalWrite(PUL[x1_axis], state_x);
|
||||
if(state_x)
|
||||
{
|
||||
if (direction[x1_axis]==RIGHT) angle_pulses[x1_axis]++;
|
||||
else angle_pulses[x1_axis]--;
|
||||
}
|
||||
state_x = !state_x;
|
||||
}
|
||||
if(((micros()-time_refresh_y)>=time_pulse[y0_axis])&&(flag_refresh[y0_axis]))
|
||||
{
|
||||
time_refresh_y = micros();
|
||||
digitalWrite(PUL[y0_axis], state_y);
|
||||
if(state_y)
|
||||
{
|
||||
if (direction[y0_axis]==LEFT) angle_pulses[y0_axis]++;
|
||||
else angle_pulses[y0_axis]--;
|
||||
}
|
||||
state_y = !state_y;
|
||||
}
|
||||
if(((micros()-time_refresh_a)>=time_pulse[x0_axis])&&(flag_refresh[x0_axis]))
|
||||
{
|
||||
time_refresh_a = micros();
|
||||
digitalWrite(PUL[x0_axis], state_a);
|
||||
if(state_a)
|
||||
{
|
||||
if (direction[x0_axis]==LEFT) angle_pulses[x0_axis]++;
|
||||
else angle_pulses[x0_axis]--;
|
||||
}
|
||||
state_a = !state_a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
long startTimex = 0;
|
||||
long startTimey = 0;
|
||||
long startTimea = 0;
|
||||
const int timeThreshold = 500;
|
||||
|
||||
void f_x1_axis(){ //Funcion de paso por cero de la interrupcion del eje x
|
||||
if (((millis() - startTimex) > timeThreshold)&&(enable_zero[x1_axis]))
|
||||
{
|
||||
if(angle_pulses[x1_axis]>0) angle_pulses_MAX[x1_axis] = angle_pulses[x1_axis]; //Varaible de pulsos maximos por vuelta
|
||||
angle_pulses[x1_axis] = 0; //Varaible temporal de pulsos
|
||||
startTimex = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void f_y0_axis(){ //Funcion de paso por cero de la interrupcion del eje y
|
||||
if (((millis() - startTimey) > timeThreshold)&&(enable_zero[y0_axis]))
|
||||
{
|
||||
if(angle_pulses[y0_axis]>0) angle_pulses_MAX[y0_axis] = angle_pulses[y0_axis]; //Varaible de pulsos maximos por vuelta
|
||||
angle_pulses[y0_axis] = 0; //Varaible temporal de pulsos
|
||||
startTimey = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void f_x0_axis(){ //Funcion de paso por cero de la interrupcion del eje a
|
||||
if (((millis() - startTimea) > timeThreshold)&&(enable_zero[x0_axis]))
|
||||
{
|
||||
if(angle_pulses[x0_axis]>0) angle_pulses_MAX[x0_axis] = angle_pulses[x0_axis]; //Varaible de pulsos maximos por vuelta
|
||||
angle_pulses[x0_axis] = 0; //Varaible temporal de pulsos
|
||||
startTimea = millis();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Functions on the M4 that returns axis
|
||||
*/
|
||||
int AxisA_Read() {
|
||||
int result = angle_pulses[x0_axis];
|
||||
return result;
|
||||
}
|
||||
|
||||
int AxisX_Read() {
|
||||
int result = angle_pulses[x1_axis];
|
||||
return result;
|
||||
}
|
||||
|
||||
int AxisY_Read() {
|
||||
int result = angle_pulses[y0_axis];
|
||||
return result;
|
||||
}
|
||||
|
||||
int read_value[10];
|
||||
int* decode_values(String inputString_rpc, int num_dec)
|
||||
{
|
||||
String str = inputString_rpc.substring(inputString_rpc.lastIndexOf(":") + 1);
|
||||
read_value[0] = str.substring(0, str.indexOf(',')).toInt();
|
||||
for(int i=1; i<num_dec; i++)
|
||||
{
|
||||
str = str.substring(str.indexOf(',')+1);
|
||||
read_value[i] = str.substring(0, str.indexOf(',')).toInt();
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
char c_rpc;
|
||||
String inputString_rpc;
|
||||
void RPCRead()
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/////// RUTINA TRATAMIENTO DE STRINGS DEL UART ///////////
|
||||
////////////////////////////////////////////////////////////
|
||||
if (RPC.available())
|
||||
{
|
||||
c_rpc = RPC.read();
|
||||
if ((c_rpc == '\r') || (c_rpc == '\n'))
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
if (inputString_rpc.startsWith("/axisA:")) //Interval Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 4);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido axis M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<4; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
x0Degrees = value[0];
|
||||
x0Duration = value[1]*1000;
|
||||
syncx0WithInterval360 = value[2];
|
||||
mode = ANGLE_MODE;
|
||||
if(!value[3]) //Save or test
|
||||
{
|
||||
isAction[x0_axis] = true;
|
||||
flag_search[x0_axis] = true;
|
||||
time_axis[x0_axis] = millis();
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/axisX:")) //Interval Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 4);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido axis M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<4; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
x1Degrees = value[0];
|
||||
x1Duration = value[1]*1000;
|
||||
syncx1WithInterval360 = value[2];
|
||||
mode = ANGLE_MODE;
|
||||
if(!value[3]) //Save or test
|
||||
{
|
||||
isAction[x1_axis] = true;
|
||||
flag_search[x1_axis] = true;
|
||||
time_axis[x1_axis] = millis();
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/axisY:")) //Interval Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 4);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido axis M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<4; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
y0Degrees = value[0];
|
||||
y0Duration = value[1]*1000;
|
||||
syncy0WithInterval360 = value[2];
|
||||
mode = ANGLE_MODE;
|
||||
if(!value[3]) //Save or test
|
||||
{
|
||||
isAction[y0_axis] = true;
|
||||
flag_search[y0_axis] = true;
|
||||
time_axis[y0_axis] = millis();
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/action:")) //Interval Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 1);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido action M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<1; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
if (value[0])
|
||||
{
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
isAction[i] = true;
|
||||
flag_search[i] = true;
|
||||
time_axis[i] = millis();
|
||||
}
|
||||
}
|
||||
else
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
isAction[i] = false;
|
||||
flag_refresh[i] = false;
|
||||
}
|
||||
}
|
||||
inputString_rpc = String();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
else
|
||||
inputString_rpc += c_rpc;
|
||||
}
|
||||
}
|
||||
|
||||
void requestReading() {
|
||||
while (true) {
|
||||
//delay(100);
|
||||
RPCRead();
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
RPC.begin();
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
pinMode(EN[i], OUTPUT);
|
||||
pinMode(DIRP[i], OUTPUT);
|
||||
pinMode(PUL[i], OUTPUT);
|
||||
digitalWrite(EN[i], LOW);
|
||||
digitalWrite(DIRP[i], HIGH);
|
||||
digitalWrite(PUL[i], HIGH);
|
||||
}
|
||||
for(int i=0; i<3; i++) pinMode(FC[i], INPUT_PULLUP);
|
||||
search_zero();
|
||||
//delay(10000);
|
||||
attachInterrupt(digitalPinToInterrupt(FC[x1_axis]), f_x1_axis, FALLING);
|
||||
attachInterrupt(digitalPinToInterrupt(FC[y0_axis]), f_y0_axis, FALLING);
|
||||
attachInterrupt(digitalPinToInterrupt(FC[x0_axis]), f_x0_axis, FALLING);
|
||||
|
||||
flag_refresh[y0_axis]=false;
|
||||
flag_refresh[x1_axis]=false;
|
||||
flag_refresh[x0_axis]=false;
|
||||
|
||||
//Bind the sensorRead() function on the M4
|
||||
RPC.bind("AxisA", AxisA_Read);
|
||||
RPC.bind("AxisX", AxisX_Read);
|
||||
RPC.bind("AxisY", AxisY_Read);
|
||||
/*
|
||||
Starts a new thread that loops the requestReading() function
|
||||
*/
|
||||
//sensorThread.start(requestReading);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
search_angle(x0_axis, x0Degrees, 0, x0Duration);
|
||||
search_angle(x1_axis, x1Degrees, 0, x1Duration);
|
||||
search_angle(y0_axis, y0Degrees, 0, y0Duration);
|
||||
refresh_steppers();
|
||||
RPCRead();
|
||||
}
|
315
CraterLab_base_giratoria/include/main_m7.cpp
Normal file
315
CraterLab_base_giratoria/include/main_m7.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#include <RPC.h>
|
||||
#include "RPC.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include "interface.html"
|
||||
#include <constants.h>
|
||||
|
||||
#define AP_MODE false
|
||||
|
||||
// Inicializando RTOS
|
||||
using namespace rtos;
|
||||
Thread sensorThread;
|
||||
|
||||
#define WIFI true
|
||||
|
||||
#if WIFI
|
||||
#include <WiFi.h>
|
||||
char ssid[] = "Analogue_Hyperlapse_Camera"; // your network SSID (name)
|
||||
char password[] = "CraterLab"; // your network password (use for WPA, or use as key for WEP)
|
||||
IPAddress ip(192, 168, 8, 3);
|
||||
IPAddress remote_ip(192, 168, 8, 4);
|
||||
IPAddress gateway(192, 168, 8, 1);
|
||||
IPAddress subnet(255, 255, 255, 0);
|
||||
IPAddress dns(8, 8, 8, 8); //primaryDNS
|
||||
// Crear el servidor en el puerto 80
|
||||
WiFiServer server(80);
|
||||
char packetBuffer[255]; //buffer to hold incoming packet
|
||||
char ReplyBuffer[] = "acknowledged"; // a string to send back
|
||||
WiFiUDP Udp;
|
||||
unsigned int localPort = 2390; // local port to listen on
|
||||
unsigned int remotePort = 2392; // local port to send
|
||||
#endif
|
||||
|
||||
#define x1_axis 0
|
||||
#define y0_axis 1
|
||||
#define x0_axis 2
|
||||
|
||||
#define STOP 0
|
||||
#define ZERO 1
|
||||
#define CONTINUOUS 2
|
||||
#define ANGLE_MODE 3
|
||||
|
||||
// Motor
|
||||
int motorSpeedValue = 25;
|
||||
bool motorIsSpeedActive = false;
|
||||
int motorIntervalFrames = 1;
|
||||
int motorIntervalSeconds = 1;
|
||||
bool motorIsIntervalActive = false;
|
||||
int motorDirection = 1;
|
||||
|
||||
// Shutter
|
||||
int shutterFadePercent = 0;
|
||||
int shutterFadeFrames = 50;
|
||||
bool shutterSyncWithInterval = false;
|
||||
bool shutterFadeInActive = false;
|
||||
bool shutterFadeOutActive = false;
|
||||
|
||||
// Óptica
|
||||
int zoomValue = 50;
|
||||
int focusValue = 50;
|
||||
float diaphragmValue = 1.8;
|
||||
bool syncWithIntervalOptics = false;
|
||||
|
||||
// Dispositivo 360
|
||||
int x0Degrees = 0;
|
||||
int x0Duration = 0;
|
||||
int x1Degrees = 0;
|
||||
int x1Duration = 0;
|
||||
int y0Degrees = 0;
|
||||
int y0Duration = 0;
|
||||
bool syncWithInterval360 = false;
|
||||
|
||||
//Sensores
|
||||
float motorSpeedRead = 0;
|
||||
float FadePercentRead = 0;
|
||||
int zoomValueRead = 0;
|
||||
int focusValueRead = 0;
|
||||
float diaphragmValueRead = 0;
|
||||
int x0DegreesRead = 0;
|
||||
int x1DegreesRead = 0;
|
||||
int y0DegreesRead = 0;
|
||||
|
||||
int mode = CONTINUOUS;
|
||||
|
||||
const char axis_c[] = {'x','y','a'};
|
||||
|
||||
float Motor_axis[3] = {0,0,0};
|
||||
|
||||
int read_value[10];
|
||||
int* decode_values(String inputString, int num_dec)
|
||||
{
|
||||
String str = inputString.substring(inputString.lastIndexOf(":") + 1);
|
||||
read_value[0] = str.substring(0, str.indexOf(',')).toInt();
|
||||
for(int i=1; i<num_dec; i++)
|
||||
{
|
||||
str = str.substring(str.indexOf(',')+1);
|
||||
read_value[i] = str.substring(0, str.indexOf(',')).toInt();
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
void handlePostRequest(String body) {
|
||||
// Parseamos el cuerpo del JSON
|
||||
StaticJsonDocument<1000> doc;
|
||||
deserializeJson(doc, body);
|
||||
int save = true;
|
||||
//DeserializationError error = deserializeJson(doc, body);
|
||||
/*if (error) {
|
||||
Serial.println("Error al parsear el JSON");
|
||||
return;
|
||||
}*/
|
||||
|
||||
Serial.println("Procesando JSON...");
|
||||
String type = doc["type"];
|
||||
if((type=="test_360")||(type=="save_360"))
|
||||
{
|
||||
Serial.println(type);
|
||||
if (type=="save_360") save = true;
|
||||
else save = false;
|
||||
String axis = doc["motor"];
|
||||
if (axis=="x0")
|
||||
{
|
||||
x0Degrees = doc["degrees"];
|
||||
x0Duration = doc["duration"];
|
||||
syncWithInterval360 = doc["syncWithInterval"];
|
||||
RPC.println("/axisA:" + String(x0Degrees) + "," + String(x0Duration) + "," + String(syncWithInterval360) + "," + String(save));
|
||||
}
|
||||
else if (axis=="x1")
|
||||
{
|
||||
x1Degrees = doc["degrees"];
|
||||
x1Duration = doc["duration"];
|
||||
syncWithInterval360 = doc["syncWithInterval"];
|
||||
RPC.println("/axisX:" + String(x1Degrees) + "," + String(x1Duration) + "," + String(syncWithInterval360) + "," + String(save));
|
||||
}
|
||||
else if (axis=="y0")
|
||||
{
|
||||
y0Degrees = doc["degrees"];
|
||||
y0Duration = doc["duration"];
|
||||
syncWithInterval360 = doc["syncWithInterval"];
|
||||
RPC.println("/axisY:" + String(y0Degrees) + "," + String(y0Duration) + "," + String(syncWithInterval360) + "," + String(save));
|
||||
}
|
||||
}
|
||||
else Serial.println("No reconocido");
|
||||
}
|
||||
|
||||
/*
|
||||
This thread calls the sensorThread() function remotely
|
||||
every second. Result is printed to the RPC1 stream.
|
||||
*/
|
||||
|
||||
void requestReading() {
|
||||
while (true) {
|
||||
delay(25);
|
||||
Motor_axis[x1_axis] = RPC.call("AxisX").as<int>();
|
||||
Motor_axis[y0_axis] = RPC.call("AxisY").as<int>();
|
||||
Motor_axis[x0_axis] = RPC.call("AxisA").as<int>();
|
||||
x0DegreesRead = 360*Motor_axis[x0_axis]/(REDUCTION_A*PULSE_REV);
|
||||
y0DegreesRead = 360*Motor_axis[y0_axis]/(REDUCTION_XY*PULSE_REV);
|
||||
x1DegreesRead = 360*Motor_axis[x1_axis]/(REDUCTION_XY*PULSE_REV);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int mode_Read() {
|
||||
int result = mode;
|
||||
return result;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(1000000);
|
||||
RPC.begin(); //boots M4
|
||||
#if WIFI
|
||||
#if AP_MODE
|
||||
int status = WL_IDLE_STATUS;
|
||||
// Create open network. Change this line if you want to create an WEP network:
|
||||
WiFi.config(ip, dns, gateway, subnet);
|
||||
status = WiFi.beginAP(ssid, password);
|
||||
if (status != WL_AP_LISTENING) {
|
||||
Serial.println("Creating access point failed");
|
||||
// don't continue
|
||||
while (true)
|
||||
;
|
||||
}
|
||||
#else
|
||||
WiFi.config(ip, dns, gateway, subnet);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(1000);
|
||||
Serial.print(".");
|
||||
}
|
||||
#endif
|
||||
Serial.println();
|
||||
Serial.println("Conectado a WiFi!");
|
||||
Serial.print("Dirección IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
#endif
|
||||
while (digitalRead(FC[x0_axis])||digitalRead(FC[x1_axis])||digitalRead(FC[y0_axis]));
|
||||
// Enable Server
|
||||
server.begin();
|
||||
// Enable UDP
|
||||
Udp.begin(localPort);
|
||||
//Starts a new thread that loops the requestReading() function
|
||||
sensorThread.start(requestReading);
|
||||
}
|
||||
|
||||
void readUDP()
|
||||
{
|
||||
int packetSize = Udp.parsePacket();
|
||||
if (packetSize) {
|
||||
#if DEBUG_M7
|
||||
Serial.print("Received packet of size ");
|
||||
Serial.println(packetSize);
|
||||
Serial.print("From ");
|
||||
IPAddress remoteIp = Udp.remoteIP();
|
||||
Serial.print(remoteIp);
|
||||
Serial.print(", port ");
|
||||
Serial.println(Udp.remotePort());
|
||||
#endif
|
||||
// read the packet into packetBufffer
|
||||
int len = Udp.read(packetBuffer, 255);
|
||||
if (len > 0) {
|
||||
packetBuffer[len] = 0;
|
||||
}
|
||||
RPC.println(packetBuffer);
|
||||
#if DEBUG_M7
|
||||
Serial.println("Contents:");
|
||||
Serial.println(packetBuffer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
WiFiClient client = server.available();
|
||||
if (client) {
|
||||
#if DEBUG_M7
|
||||
Serial.println("Nuevo cliente conectado");
|
||||
#endif
|
||||
String request = "";
|
||||
bool isPostRequest = false;
|
||||
|
||||
while (client.connected()) {
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
request += c;
|
||||
|
||||
// Identificar si es una solicitud POST
|
||||
if (request.indexOf("POST") >= 0) {
|
||||
isPostRequest = true;
|
||||
}
|
||||
|
||||
// Si se encuentra el final de la solicitud
|
||||
if (c == '\n' && request.endsWith("\r\n\r\n")) {
|
||||
#if DEBUG_M7
|
||||
Serial.println("Solicitud recibida:");
|
||||
Serial.println(request);
|
||||
#endif
|
||||
|
||||
if (isPostRequest) {
|
||||
String body = "";
|
||||
while (client.available()) {
|
||||
body += (char)client.read();
|
||||
}
|
||||
#if DEBUG_M7
|
||||
Serial.println("Cuerpo del mensaje recibido:");
|
||||
Serial.println(body);
|
||||
#endif
|
||||
// Llamamos a la función para procesar la petición POST
|
||||
handlePostRequest(body);
|
||||
// Respuesta al cliente
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/plain");
|
||||
client.println();
|
||||
client.println("Datos enviados correctamente");
|
||||
} else if (request.indexOf("GET /sensors") >= 0) { // actualiza fps en interface
|
||||
// Respuesta para la ruta /motorSpeed
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-Type: application/json");
|
||||
client.println();
|
||||
String response = "{\"sensors\":[" + String(x0DegreesRead) + "," + String(x1DegreesRead) + "," + String(y0DegreesRead) + "]}";
|
||||
client.print(response);
|
||||
} else {
|
||||
// Respuesta para servir la interfaz HTML
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/html");
|
||||
client.println();
|
||||
client.print(htmlTemplate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
client.stop();
|
||||
#if DEBUG_M7
|
||||
Serial.println("Cliente desconectado");
|
||||
#endif
|
||||
}
|
||||
readUDP();
|
||||
#if DEBUG_M7
|
||||
String buffer = "";
|
||||
|
||||
while (RPC.available()) {
|
||||
|
||||
buffer += (char)RPC.read(); // Fill the buffer with characters
|
||||
|
||||
}
|
||||
|
||||
if (buffer.length() > 0) {
|
||||
|
||||
Serial.print(buffer);
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
46
CraterLab_base_giratoria/lib/README
Normal file
46
CraterLab_base_giratoria/lib/README
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in a an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
30
CraterLab_base_giratoria/platformio.ini
Normal file
30
CraterLab_base_giratoria/platformio.ini
Normal file
|
@ -0,0 +1,30 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:ARDUINO_GIGA_M7]
|
||||
;platform = https://github.com/dberlin/platform-ststm32.git#develop
|
||||
;platform = https://github.com/dberlin/platform-ststm32
|
||||
platform = ststm32
|
||||
board = giga_r1_m7
|
||||
framework = arduino
|
||||
monitor_speed = 1000000
|
||||
;upload_port = COM16
|
||||
board_build.arduino.flash_layout = 75_25 ;50_50, 75_25, 100_0
|
||||
lib_deps = bblanchon/ArduinoJson@^7.2.0
|
||||
|
||||
[env:ARDUINO_GIGA_M4]
|
||||
;platform = https://github.com/dberlin/platform-ststm32.git#develop
|
||||
platform = ststm32
|
||||
board = giga_r1_m4
|
||||
framework = arduino
|
||||
monitor_speed = 1000000
|
||||
;upload_port = COM16
|
||||
board_build.arduino.flash_layout = 75_25 ;50_50, 75_25, 100_0
|
||||
;board_build.arduino.flash_layout = 100_0 ;50_50, 75_25, 100_0
|
5
CraterLab_base_giratoria/src/main.cpp
Normal file
5
CraterLab_base_giratoria/src/main.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
#if defined(ARDUINO_GIGA_M7)
|
||||
#include<main_m7.cpp>
|
||||
#elif defined(ARDUINO_GIGA_M4)
|
||||
#include<main_m4.cpp>
|
||||
#endif
|
11
CraterLab_base_giratoria/test/README
Normal file
11
CraterLab_base_giratoria/test/README
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
39
CraterLab_camera/include/README
Normal file
39
CraterLab_camera/include/README
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
42
CraterLab_camera/include/constants.h
Normal file
42
CraterLab_camera/include/constants.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#define FORWARD 0
|
||||
#define BACKWARD 1
|
||||
#define STOP 0
|
||||
#define IN 1
|
||||
#define OUT 2
|
||||
#define IN_OUT 3
|
||||
#define FPS_MOTOR 4
|
||||
|
||||
//Definicion de los pines del shift register
|
||||
#define Data_pin 8
|
||||
#define Clock_pin 4
|
||||
#define Latch_pin 12
|
||||
#define Enable 7
|
||||
|
||||
//Definicion de los Motores 0,1,2,3 en el shift register
|
||||
#define M2A 0
|
||||
#define M1A 1
|
||||
#define M0A 2
|
||||
#define M0B 3
|
||||
#define M1B 4
|
||||
#define M3A 5
|
||||
#define M2B 6
|
||||
#define M3B 7
|
||||
|
||||
//Definicion de los enable (PWM) de los Motores 0,1,2,3 en las gpio del Arduino
|
||||
#define EN0 11
|
||||
#define EN1 3
|
||||
#define EN2 5
|
||||
#define EN3 6
|
||||
|
||||
//Definicion del Motor 4
|
||||
#define EN_M4 33
|
||||
#define R_M4 10
|
||||
#define L_M4 9
|
||||
|
||||
//Definicion de los pines de los sensores
|
||||
#define sensor_fps 20
|
||||
#define sensor_lineal_motor A0
|
||||
|
||||
//Definicion de los limites del sensor lineal
|
||||
#define LINEAL_MAX 478
|
||||
#define LINEAL_MIN 0
|
452
CraterLab_camera/include/interface.html
Normal file
452
CraterLab_camera/include/interface.html
Normal file
|
@ -0,0 +1,452 @@
|
|||
// Plantilla HTML
|
||||
const char *htmlTemplate = R"rawliteral(
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<style>
|
||||
/* Tema oscuro básico */
|
||||
body {
|
||||
background-color: #121212;
|
||||
color: #ffffff;
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #cccccc;
|
||||
/* Gris claro */
|
||||
font-size: 32px;
|
||||
border-bottom: 2px solid #555555;
|
||||
/* Un borde gris medio */
|
||||
padding-bottom: 5px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #bbbbbb;
|
||||
/* Gris medio-claro */
|
||||
font-size: 20px;
|
||||
margin-top: 30px;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #444444;
|
||||
/* Un borde gris oscuro */
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: #dddddd;
|
||||
/* Blanco roto o gris muy claro */
|
||||
font-size: 18px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
/* Estilos de los inputs */
|
||||
input[type="text"],
|
||||
input[type="number"],
|
||||
select {
|
||||
width: 100px;
|
||||
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;
|
||||
}
|
||||
|
||||
/* Estilo de los sliders */
|
||||
input[type="range"] {
|
||||
width: 30%;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* Botones */
|
||||
button {
|
||||
background-color: #1e88e5;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 10px 2px;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #1565c0;
|
||||
}
|
||||
|
||||
|
||||
/* Dark styling for select dropdown */
|
||||
select {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
border: 1px solid #555;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
||||
/* Estilo para centrar los formularios en la pantalla */
|
||||
.form-container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
iframe {
|
||||
display: block;
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
/* Evita que sea muy pequeño al inicio */
|
||||
overflow: hidden !important;
|
||||
/* Asegura que no haya barras de desplazamiento */
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="form-container">
|
||||
<h2>Control Bolex Paillard</h2>
|
||||
<div class="section">
|
||||
<!-- Sección Motor Cámara -->
|
||||
<h3>Motor Cámara</h3>
|
||||
|
||||
<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
|
||||
|
||||
<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>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>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<!-- Sección Shutter -->
|
||||
<h3>Shutter</h3>
|
||||
<h4>Fade In/Out Frames:</h4>
|
||||
<p>% apertura inicial: <span id='fadePercentDisplay'>50</span></p>
|
||||
<input type='range' min='0' max='100' value='50' id='fadePercentSlider'>
|
||||
<input type='number' id='fade'>
|
||||
<p>Número de frames: <span id='fadeFramesDisplay'>50</span></p>
|
||||
<input type='range' min='0' max='100' value='50' id='fadeFramesSlider'>
|
||||
|
||||
<h4>Fade Activación:</h4>
|
||||
<input type='checkbox' id='fadeInCheckbox'> Activar Fade In
|
||||
<input type='checkbox' id='fadeOutCheckbox'> Activar Fade Out
|
||||
<br><br>
|
||||
<input type='checkbox' id='syncWithIntervalCheckbox'> Sincronizar con Intervalómetro
|
||||
|
||||
<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>
|
||||
<h4>Zoom:</h4>
|
||||
<p>Valor de zoom: <span id='zoomValueDisplay'>50</span></p>
|
||||
<input type='range' min='0' max='100' value='50' id='zoomSlider'>
|
||||
|
||||
<h4>Foco:</h4>
|
||||
<p>Valor de foco: <span id='focusValueDisplay'>50</span></p>
|
||||
<input type='range' min='0' max='100' value='50' id='focusSlider'>
|
||||
|
||||
<h4>Diafragma:</h4>
|
||||
<select id='diaphragmSelect'>
|
||||
<option value='1.9'>1.9</option>
|
||||
<option value='2.2'>2.2</option>
|
||||
<option value='4'>4</option>
|
||||
<option value='5.6'>5.6</option>
|
||||
<option value='8'>8</option>
|
||||
<option value='11'>11</option>
|
||||
<option value='16'>16</option>
|
||||
<option value='22'>22</option>
|
||||
</select>
|
||||
<br><br>
|
||||
<input type='checkbox' id='syncWithIntervalOptics'> Sincronizar con Intervalómetro
|
||||
<br><br>
|
||||
<button onclick="sendOpticsData('test_optics')">Test</button>
|
||||
<button onclick="sendOpticsData('save_optics')">Save</button>
|
||||
<span id="opticsMessage" style="color: green; display: none;">Datos enviados correctamente</span>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Script para manejar las interacciones y enviar el JSON -->
|
||||
<script>
|
||||
|
||||
window.addEventListener("message", function (event) {
|
||||
console.log("Mensaje recibido:", event.data); // Depuración
|
||||
|
||||
// Seleccionar el iframe específico por su ID
|
||||
const targetIframe = document.getElementById("iframe360");
|
||||
|
||||
// Verificar que el mensaje contiene un número válido (altura)
|
||||
if (targetIframe && typeof event.data === "number" && event.data > 0) {
|
||||
targetIframe.style.height = event.data + "px";
|
||||
console.log("Altura ajustada del iframe a:", event.data + "px"); // Depuración
|
||||
}
|
||||
});
|
||||
|
||||
function updateDisplay() {
|
||||
document.getElementById('speedValueDisplay').innerText = document.getElementById('speedSlider').value;
|
||||
document.getElementById('fadePercentDisplay').innerText = document.getElementById('fadePercentSlider').value;
|
||||
document.getElementById('fadeFramesDisplay').innerText = document.getElementById('fadeFramesSlider').value;
|
||||
document.getElementById('zoomValueDisplay').innerText = document.getElementById('zoomSlider').value;
|
||||
document.getElementById('focusValueDisplay').innerText = document.getElementById('focusSlider').value;
|
||||
}
|
||||
|
||||
function showMessage(elementId) {
|
||||
const messageElement = document.getElementById(elementId);
|
||||
if (messageElement) {
|
||||
messageElement.style.display = 'inline';
|
||||
setTimeout(() => {
|
||||
messageElement.style.display = 'none';
|
||||
}, 3000); // Mostrar el mensaje durante 3 segundos
|
||||
}
|
||||
}
|
||||
|
||||
function sendMotorCameraData(type_mode) {
|
||||
const motorData = {
|
||||
type: type_mode,
|
||||
/*speedValue: document.getElementById('speedSlider').value,
|
||||
isSpeedActive: document.getElementById('speedCheckbox').checked,
|
||||
intervalFrames: document.getElementById('intervalFrames').value,
|
||||
intervalSeconds: document.getElementById('intervalSeconds').value,
|
||||
isIntervalActive: document.getElementById('intervalCheckbox').checked,
|
||||
direction: document.querySelector('input[name="direction"]:checked').value*/
|
||||
0: document.getElementById('speedSlider').value,
|
||||
1: document.getElementById('speedCheckbox').checked,
|
||||
2: document.getElementById('intervalFrames').value,
|
||||
3: document.getElementById('intervalSeconds').value,
|
||||
4: document.getElementById('intervalCheckbox').checked,
|
||||
5: document.querySelector('input[name="direction"]:checked').value
|
||||
};
|
||||
fetch('/updateMotorCamera', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(motorData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('motorCameraMessage'))
|
||||
.catch(error => console.error('Motor Camera Error:', error));
|
||||
}
|
||||
|
||||
function stop() {
|
||||
|
||||
const accionData = {
|
||||
type: 'stop',
|
||||
};
|
||||
fetch('/stop', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(accionData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('motorCameraMessage'))
|
||||
.catch(error => console.error('Stop Error:', error));
|
||||
}
|
||||
|
||||
function sendShutterData(type_mode) {
|
||||
const shutterData = {
|
||||
type: type_mode,
|
||||
/*fadePercent: document.getElementById('fadePercentSlider').value,
|
||||
fadeFrames: document.getElementById('fadeFramesSlider').value,
|
||||
syncWithInterval: document.getElementById('syncWithIntervalCheckbox').checked,
|
||||
fadeInActive: document.getElementById('fadeInCheckbox').checked,
|
||||
fadeOutActive: document.getElementById('fadeOutCheckbox').checked*/
|
||||
0: document.getElementById('fadePercentSlider').value,
|
||||
1: document.getElementById('fadeFramesSlider').value,
|
||||
2: document.getElementById('syncWithIntervalCheckbox').checked,
|
||||
3: document.getElementById('fadeInCheckbox').checked,
|
||||
4: document.getElementById('fadeOutCheckbox').checked
|
||||
};
|
||||
fetch('/updateShutter', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(shutterData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('shutterMessage'))
|
||||
.catch(error => console.error('Shutter Error:', error));
|
||||
}
|
||||
|
||||
function sendOpticsData(type_mode) {
|
||||
const opticsData = {
|
||||
type: type_mode,
|
||||
zoomValue: document.getElementById('zoomSlider').value,
|
||||
focusValue: document.getElementById('focusSlider').value,
|
||||
diaphragmValue: document.getElementById('diaphragmSelect').value,
|
||||
syncWithInterval: document.getElementById('syncWithIntervalOptics').checked
|
||||
};
|
||||
fetch('/updateOptics', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(opticsData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('opticsMessage'))
|
||||
.catch(error => console.error('Optics Error:', error));
|
||||
}
|
||||
|
||||
function moveMotor(type_mode, motor) {
|
||||
const degrees = document.getElementById(`${motor}Degrees`).value;
|
||||
const duration = document.getElementById(`${motor}Duration`).value;
|
||||
const syncWithInterval = document.getElementById('syncWithInterval360').checked;
|
||||
|
||||
const motorData = {
|
||||
type: type_mode,
|
||||
motor: motor,
|
||||
degrees: degrees,
|
||||
duration: duration,
|
||||
syncWithInterval: syncWithInterval
|
||||
};
|
||||
fetch('/moveMotor360', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(motorData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage(`${motor}Message`))
|
||||
.catch(error => console.error('Motor Error:', error));
|
||||
}
|
||||
|
||||
function accion() {
|
||||
|
||||
const accionData = {
|
||||
type: 'accion',
|
||||
};
|
||||
fetch('/accion', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(accionData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('accionMessage'))
|
||||
.catch(error => console.error('Accion Error:', error));
|
||||
}
|
||||
|
||||
function corten() {
|
||||
|
||||
const accionData = {
|
||||
type: 'corten',
|
||||
};
|
||||
fetch('/corten', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(accionData),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(() => showMessage('accionMessage'))
|
||||
.catch(error => console.error('Corten Error:', error));
|
||||
}
|
||||
|
||||
// Actualizar la interfaz al cambiar los sliders
|
||||
document.getElementById('speedSlider').addEventListener('input', updateDisplay);
|
||||
document.getElementById('fadePercentSlider').addEventListener('input', updateDisplay);
|
||||
document.getElementById('fadeFramesSlider').addEventListener('input', updateDisplay);
|
||||
document.getElementById('zoomSlider').addEventListener('input', updateDisplay);
|
||||
document.getElementById('focusSlider').addEventListener('input', updateDisplay);
|
||||
|
||||
// pide motorSpeed al M7
|
||||
function updateMotorSpeed() {
|
||||
fetch('/motorSpeed')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('fps').value = data.motorSpeedRead;
|
||||
})
|
||||
.catch(error => console.error('Error al obtener motorSpeed:', error));
|
||||
}
|
||||
|
||||
function updatefadePosition() {
|
||||
fetch('/fadePercent')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('fade').value = data.FadePercentRead;
|
||||
})
|
||||
.catch(error => console.error('Error al obtener fadePercent:', error));
|
||||
}
|
||||
|
||||
function updateSensors() {
|
||||
fetch('/sensors')
|
||||
.then(response => response.json()) // Parsear la respuesta como JSON
|
||||
.then(data => {
|
||||
if (data.sensors && Array.isArray(data.sensors)) {
|
||||
const sensorValues = data.sensors;
|
||||
// Asignar los valores a los elementos de la interfaz
|
||||
if (sensorValues.length >= 1) {
|
||||
document.getElementById('fps').value = sensorValues[0];
|
||||
}
|
||||
if (sensorValues.length >= 2) {
|
||||
document.getElementById('fade').value = sensorValues[1];
|
||||
}
|
||||
} else {
|
||||
console.error('Estructura inesperada:', data);
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error al obtener sensores:', error));
|
||||
}
|
||||
|
||||
// Llama a updateSensors cada 500ms
|
||||
setInterval(updateSensors, 500);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
)rawliteral";
|
539
CraterLab_camera/include/main_m4.cpp
Normal file
539
CraterLab_camera/include/main_m4.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
#include <Arduino.h>
|
||||
#include <ShiftRegister74HC595.h>
|
||||
//#include <PID_v1.h>
|
||||
//#include <SPI.h>
|
||||
#include <RPC.h>
|
||||
#include "constants.h"
|
||||
|
||||
#define DEBUG_M4 false
|
||||
#define MIN_SPEED 55
|
||||
|
||||
// Motor
|
||||
int motorSpeedValue = 24;
|
||||
bool motorIsSpeedActive = false;
|
||||
int motorIntervalFrames = 1;
|
||||
int motorIntervalSeconds = 1;
|
||||
bool motorIsIntervalActive = false;
|
||||
bool motorDirection = 1;
|
||||
|
||||
// Shutter
|
||||
int shutterFadePercent = 0;
|
||||
int shutterFadeFrames = 50;
|
||||
bool shutterSyncWithInterval = false;
|
||||
bool shutterFadeInActive = false;
|
||||
bool shutterFadeOutActive = false;
|
||||
|
||||
// Óptica
|
||||
int zoomValue = 50;
|
||||
int focusValue = 50;
|
||||
float diaphragmValue = 1.8;
|
||||
bool syncWithIntervalOptics = false;
|
||||
|
||||
bool closed=false;
|
||||
bool isAction=false;
|
||||
|
||||
#if PID_ENABLE
|
||||
// ************************************************ Variables PID *****************************************************************
|
||||
double Setpoint = 0.0, Input = 0.0, Output = 0.0; // Setpoint=Posición designada; Input=Posición del motor; Output=Tensión de salida para el motor.
|
||||
double kp = 0.0, ki = 0.0, kd = 0.0; // Constante proporcional, integral y derivativa.
|
||||
double outMax = 0.0, outMin = 0.0; // Límites para no sobrepasar la resolución del PWM.
|
||||
// **************************************************** Otras Variables ***********************************************************
|
||||
volatile long contador = 0; // En esta variable se guardará los pulsos del encoder y que interpreremos como distancia (o ángulo si ese fuese el caso).
|
||||
byte ant = 0, act = 0; // Sólo se utiliza los dos primeros bits de estas variables y servirán para decodificar el encoder. (ant=anterior, act=actual.)
|
||||
byte cmd = 0; // Un byte que utilizamos para la comunicación serie. (cmd=comando.)
|
||||
unsigned int tmp = 0; // Variable que utilizaremos para poner el tiempo de muestreo.
|
||||
const byte ledok = 13; // El pin 13 de los Arduinos tienen un led que utilizo para mostrar que el motor ya ha llegado a la posición designada.
|
||||
// ********************************************************************************************************************************
|
||||
|
||||
PID myPID(&Input, &Output, &Setpoint, 0.0, 0.0, 0.0, DIRECT); // Parámetros y configuración para invocar la librería.
|
||||
#endif
|
||||
|
||||
// parameters: <number of shift registers> (data pin, clock pin, latch pin)
|
||||
ShiftRegister74HC595<1> sr(Data_pin, Clock_pin, Latch_pin);
|
||||
const int EN_MOTOR[4] = {EN0, EN1, EN2, EN3};
|
||||
const int MA_MOTOR[4] = {M0A, M1A, M2A, M3A};
|
||||
const int MB_MOTOR[4] = {M0B, M1B, M2B, M3B};
|
||||
const long TIME_LINEAL_MAX[6] = {4150, 670, 4250, 6200, 4000, 4000 }; //ms
|
||||
|
||||
void backward(int motor, int SPEED)
|
||||
{
|
||||
if(motor<4)
|
||||
{
|
||||
sr.set(MA_MOTOR[motor], HIGH);
|
||||
sr.set(MB_MOTOR[motor], LOW);
|
||||
analogWrite(EN_MOTOR[motor], SPEED);
|
||||
}
|
||||
else
|
||||
{
|
||||
analogWrite(L_M4, SPEED);
|
||||
analogWrite(R_M4, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void forward(int motor, int SPEED)
|
||||
{
|
||||
if(motor<4)
|
||||
{
|
||||
sr.set(MA_MOTOR[motor], LOW);
|
||||
sr.set(MB_MOTOR[motor], HIGH);
|
||||
analogWrite(EN_MOTOR[motor], SPEED);
|
||||
}
|
||||
else
|
||||
{
|
||||
analogWrite(L_M4, 0);
|
||||
analogWrite(R_M4, SPEED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void stop(int motor)
|
||||
{
|
||||
|
||||
if(motor<4)
|
||||
{
|
||||
analogWrite(EN_MOTOR[motor], 0);
|
||||
sr.set(MA_MOTOR[motor], LOW);
|
||||
sr.set(MB_MOTOR[motor], LOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
analogWrite(L_M4, 0);
|
||||
analogWrite(R_M4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
float position_motor_objective[6] = { 0, 0, 0, 0, 0, 0};
|
||||
bool moving_position_motor[6] = { false, false, false, false, false, false};
|
||||
|
||||
void config_position_motor(int motor, float position) //Configuracion posicion en % motor
|
||||
{
|
||||
if((position!=position_motor[motor])&&(!moving_position_motor[motor]))
|
||||
{
|
||||
if(motor==0)
|
||||
{
|
||||
if(position>position_motor[motor]) forward(motor,255);
|
||||
else backward(motor,255);
|
||||
position_motor_objective[motor] = position;
|
||||
moving_position_motor[motor] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_move_for_move_position_motor[motor] = (abs(position_motor[motor]-position)*TIME_LINEAL_MAX[motor])/100.;
|
||||
if(position>position_motor[motor]) forward(motor,255);
|
||||
else backward(motor,255);
|
||||
time_refresh_position_motor[motor] = millis();
|
||||
position_motor_objective[motor] = position;
|
||||
moving_position_motor[motor] = true;
|
||||
//RPC.println("/debug:" + String(position_motor[motor]) + "," + String(position) + "," + String(millis()-time_refresh_position_motor[motor]) + "," + String(time_move_for_move_position_motor[motor]) + "," + "INI");
|
||||
//Serial.println(time_move_for_move_position_motor[motor]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool state_smotor[6] = { false, false, false, false, false, false};
|
||||
|
||||
void config_speed_motor(int motor, int direction, int speed) //Configuracion velocidad motor
|
||||
{
|
||||
closed = false;
|
||||
if(direction==FORWARD) forward(motor,speed);
|
||||
else if(direction==BACKWARD) backward(motor,speed);
|
||||
if(speed>0) state_smotor[motor] = true;
|
||||
else state_smotor[motor] = false;
|
||||
}
|
||||
|
||||
|
||||
volatile float fps_read = 0;
|
||||
volatile float fps_temp = 0;
|
||||
unsigned long time_sec= millis();
|
||||
unsigned long time_fps = micros();
|
||||
|
||||
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))
|
||||
{
|
||||
lastTimeDebounce = micros();
|
||||
fps_temp = 1000000./(float)(micros()-time_fps);
|
||||
if(fps_temp<70) fps_read = fps_temp;
|
||||
time_fps = micros();
|
||||
if((millis()-time_sec)>=1000)
|
||||
{
|
||||
//RPC.println(fps_read);
|
||||
time_sec = millis();
|
||||
}
|
||||
}
|
||||
else if((digitalRead(sensor_fps)&&(micros()-lastTimeDebounce >= 150))&&(closed))
|
||||
{
|
||||
lastTimeDebounce = micros();
|
||||
closed = false;
|
||||
force_stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
int interval_direction[6] = {0, 0, 0, 0, 0, 0};
|
||||
int interval_frames[6] = {0, 0, 0, 0, 0, 0};
|
||||
unsigned long interval_time[6] = {0, 0, 0, 0, 0, 0};
|
||||
int frames_count[6] = {0, 0, 0, 0, 0, 0};
|
||||
unsigned long time_interval_count[6] = {0, 0, 0, 0, 0, 0};
|
||||
void config_interval_motor(int direction, int Frames, int Seconds) //Configuracion velocidad motor
|
||||
{
|
||||
closed = false;
|
||||
interval_direction[FPS_MOTOR] = direction;
|
||||
interval_frames[FPS_MOTOR] = Frames;
|
||||
interval_time[FPS_MOTOR] = Seconds*1000;
|
||||
frames_count[FPS_MOTOR] = 0;
|
||||
time_interval_count[FPS_MOTOR] = millis();
|
||||
}
|
||||
|
||||
float inc_position_fade = 0;
|
||||
int fade_direction = 0;
|
||||
void config_automatic_fade(int shutterFadeFrames, int shutterSyncWithInterval, int shutterFadeInActive, int shutterFadeOutActive) //Configuracion fade
|
||||
{
|
||||
|
||||
if((shutterFadeInActive)&&(!shutterFadeOutActive))
|
||||
{
|
||||
fade_direction=IN;
|
||||
inc_position_fade = (100-position_motor[0])/(float)shutterFadeFrames;
|
||||
}
|
||||
else if((!shutterFadeInActive)&&(shutterFadeOutActive))
|
||||
{
|
||||
fade_direction=OUT;
|
||||
inc_position_fade = (position_motor[0])/(float)shutterFadeFrames;
|
||||
}
|
||||
else if((shutterFadeInActive)&&(shutterFadeOutActive))
|
||||
{
|
||||
fade_direction=IN_OUT;
|
||||
inc_position_fade = (100)/(float)shutterFadeFrames;
|
||||
}
|
||||
else fade_direction=STOP;
|
||||
}
|
||||
|
||||
void config_optics(int zoomValue, int focusValue, int diaphragmValue, int syncWithIntervalOptics) //Configuracion de las opticas
|
||||
{
|
||||
config_position_motor(1, zoomValue);
|
||||
config_position_motor(2, focusValue);
|
||||
config_position_motor(3, map(int(diaphragmValue*10), 19, 220, 0, 100));
|
||||
}
|
||||
|
||||
void secure_stop(int direction)
|
||||
{
|
||||
config_speed_motor(FPS_MOTOR, direction, 0);
|
||||
delay(150);
|
||||
if (!digitalRead(sensor_fps))
|
||||
{
|
||||
config_speed_motor(FPS_MOTOR, direction, MIN_SPEED);
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void next_frame(int direction)
|
||||
{
|
||||
config_speed_motor(FPS_MOTOR, motorDirection, MIN_SPEED);
|
||||
closed = true;
|
||||
}
|
||||
|
||||
#define NUM 20.
|
||||
int read_lineal_motor()
|
||||
{
|
||||
int value = 0;
|
||||
for (int i=0; i<10; i++) value += analogRead(sensor_lineal_motor);
|
||||
return value/10;
|
||||
}
|
||||
|
||||
void ini_motors()
|
||||
{
|
||||
//forward(0,255);
|
||||
while (read_lineal_motor()>LINEAL_MAX) forward(0,255);
|
||||
stop(0);
|
||||
while (read_lineal_motor()<LINEAL_MAX) backward(0,255);
|
||||
stop(0);
|
||||
|
||||
/*backward(1,255);
|
||||
backward(2,255);
|
||||
backward(3,255);
|
||||
delay(TIME_LINEAL_MAX[3]);
|
||||
stop(0);
|
||||
stop(1);
|
||||
stop(2);
|
||||
stop(3);*/
|
||||
}
|
||||
|
||||
void refresh_position_motors()
|
||||
{
|
||||
position_motor[0] = map(read_lineal_motor(),LINEAL_MAX,LINEAL_MIN,0,100);
|
||||
if((position_motor[0]==position_motor_objective[0])&&(moving_position_motor[0]))
|
||||
{
|
||||
stop(0);
|
||||
moving_position_motor[0] = false;
|
||||
}
|
||||
for(int i=1; i<4; i++)
|
||||
{
|
||||
if(((millis()-time_refresh_position_motor[i])>(unsigned long)time_move_for_move_position_motor[i])&&(moving_position_motor[i]))
|
||||
{
|
||||
stop(i);
|
||||
position_motor[i] = position_motor_objective[i];
|
||||
moving_position_motor[i] = false;
|
||||
//RPC.println("/debug:" + String(position_motor[i]) + "," + String(position_motor_objective[i]) + "," + String(millis()-time_refresh_position_motor[i]) + "," + String(time_move_for_move_position_motor[i]) + "," + "END");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int change_direction_inout = 1;
|
||||
|
||||
void refresh_interval_motors()
|
||||
{
|
||||
if((((millis()-time_interval_count[FPS_MOTOR])>=interval_time[FPS_MOTOR])&&(interval_frames[FPS_MOTOR]!=frames_count[FPS_MOTOR]))&&(isAction))
|
||||
{
|
||||
frames_count[FPS_MOTOR]++;
|
||||
time_interval_count[FPS_MOTOR] = millis();
|
||||
if(frames_count[FPS_MOTOR]>=interval_frames[FPS_MOTOR]) isAction=false;
|
||||
if (shutterSyncWithInterval)
|
||||
{
|
||||
float value_position=0;
|
||||
if(fade_direction==IN)
|
||||
{
|
||||
value_position = position_motor[0] + inc_position_fade;
|
||||
if (value_position>100) value_position=100;
|
||||
config_position_motor(0, value_position);
|
||||
}
|
||||
else if(fade_direction==OUT)
|
||||
{
|
||||
value_position = position_motor[0] - inc_position_fade;
|
||||
if (value_position<0) value_position=0;
|
||||
config_position_motor(0, value_position);
|
||||
}
|
||||
else if(fade_direction==IN_OUT)
|
||||
{
|
||||
if (((position_motor[0] + inc_position_fade)>100)&&(change_direction_inout==1)) change_direction_inout=-1;
|
||||
else if (((position_motor[0] - inc_position_fade)<0)&&(change_direction_inout==-1)) change_direction_inout=1;
|
||||
value_position = position_motor[0] + change_direction_inout*inc_position_fade;
|
||||
RPC.println("/fade:" + String(position_motor[0]) + "," + String(change_direction_inout) + "," + String(inc_position_fade) + "," + String(0) + "," + String(shutterFadeOutActive));
|
||||
config_position_motor(0, value_position);
|
||||
}
|
||||
//else value_position = position_motor[0];
|
||||
|
||||
}
|
||||
next_frame(interval_direction[FPS_MOTOR]);
|
||||
}
|
||||
}
|
||||
|
||||
float fps_request = 24;
|
||||
uint8_t speed_request = 0;
|
||||
unsigned long time_adjust = millis();
|
||||
|
||||
/*
|
||||
Functions on the M4 that returns FPS
|
||||
*/
|
||||
int fpsRead() {
|
||||
int result = fps_read;
|
||||
return result;
|
||||
}
|
||||
|
||||
int read_value[10];
|
||||
int* decode_values(String inputString_rpc, int num_dec)
|
||||
{
|
||||
String str = inputString_rpc.substring(inputString_rpc.lastIndexOf(":") + 1);
|
||||
read_value[0] = str.substring(0, str.indexOf(',')).toInt();
|
||||
for(int i=1; i<num_dec; i++)
|
||||
{
|
||||
str = str.substring(str.indexOf(',')+1);
|
||||
read_value[i] = str.substring(0, str.indexOf(',')).toInt();
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
char c_rpc;
|
||||
String inputString_rpc;
|
||||
unsigned long time_led = millis();
|
||||
|
||||
void RPCRead()
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/////// RUTINA TRATAMIENTO DE STRINGS DEL UART ///////////
|
||||
////////////////////////////////////////////////////////////
|
||||
if (RPC.available())
|
||||
{
|
||||
c_rpc = RPC.read();
|
||||
if ((c_rpc == '\r') || (c_rpc == '\n'))
|
||||
{
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
if (inputString_rpc.startsWith("/s_motor:")) //Speed Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 4);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido Speed M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<4; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
motorDirection = value[1];
|
||||
motorSpeedValue = value[2];
|
||||
motorIsSpeedActive = true;
|
||||
motorIsIntervalActive = false;
|
||||
//if (motorSpeedValue>0) motorSpeedValue = map(motorSpeedValue, 24, 48, 146, 192); //Fake fps
|
||||
if (motorSpeedValue>0) motorSpeedValue = map(motorSpeedValue, 0, 48, 0, 255); //Fake fps
|
||||
//if (motorSpeedValue>0) motorSpeedValue = 255;
|
||||
if (value[3]==false) //Si es falso, se ejecuta, sino se guarda sin ejecutar
|
||||
{
|
||||
if (motorSpeedValue==0)
|
||||
{
|
||||
isAction = false;
|
||||
secure_stop(motorDirection);
|
||||
}
|
||||
else config_speed_motor(value[0], motorDirection, motorSpeedValue);
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/i_motor:")) //Interval Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 5);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido Interval M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<5; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
motorDirection = value[1];
|
||||
motorIntervalFrames = value[2];
|
||||
motorIntervalSeconds = value[3];
|
||||
motorIsIntervalActive = true;
|
||||
motorIsSpeedActive = false;
|
||||
if (value[4]==false) //Si es falso, se ejecuta, sino se guarda sin ejecutar
|
||||
{
|
||||
isAction = true;
|
||||
config_interval_motor(motorDirection, motorIntervalFrames, motorIntervalSeconds);
|
||||
}
|
||||
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/fade:")) //Fade configuration
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 6);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido fade M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<6; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
shutterFadePercent = value[0];
|
||||
shutterFadeFrames = value[1];
|
||||
shutterSyncWithInterval = value[2];
|
||||
shutterFadeInActive = value[3];
|
||||
shutterFadeOutActive = value[4];
|
||||
//RPC.println("/fade:" + String(shutterFadePercent) + "," + String(shutterFadeFrames) + "," + String(shutterSyncWithInterval) + "," + String(shutterFadeInActive) + "," + String(shutterFadeOutActive));
|
||||
config_position_motor(0, shutterFadePercent);
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/optics:")) //Optics configuration
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 5);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido optics M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<5; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
zoomValue = value[0];
|
||||
focusValue = value[1];
|
||||
diaphragmValue = value[2];
|
||||
syncWithIntervalOptics = value[3];
|
||||
if (value[4]==false) //Si es falso, se ejecuta, sino se guarda sin ejecutar
|
||||
{
|
||||
config_optics(zoomValue, focusValue, diaphragmValue, syncWithIntervalOptics);
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/action:")) //Optics configuration
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 1);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido action M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<1; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
isAction=value[0];
|
||||
if (isAction)
|
||||
{
|
||||
if (motorIsSpeedActive) config_speed_motor(4, motorDirection, motorSpeedValue);
|
||||
else config_interval_motor(motorDirection, motorIntervalFrames, motorIntervalSeconds);
|
||||
config_automatic_fade(shutterFadeFrames, shutterSyncWithInterval, shutterFadeInActive, shutterFadeOutActive);
|
||||
}
|
||||
else
|
||||
{
|
||||
secure_stop(motorDirection);
|
||||
}
|
||||
}
|
||||
else if (inputString_rpc.startsWith("/sensors:")) //Optics configuration
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 1);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido fps M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<1; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
if(value[0])
|
||||
RPC.println("/sensors:" + String(fps_read) + "," + String(analogRead(sensor_lineal_motor)) + "," + String(position_motor[1]) + "," + String(position_motor[2]) + "," + String(position_motor[3]));
|
||||
//RPC.println("/sensors:" + String(fps_read) + "," + String(position_motor[0]) + "," + String(position_motor[1]) + "," + String(position_motor[2]) + "," + String(position_motor[3]));
|
||||
//RPC.println(fps_read);
|
||||
}
|
||||
inputString_rpc = String();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
else
|
||||
inputString_rpc += c_rpc;
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
//SCB_CleanDCache();
|
||||
RPC.begin();
|
||||
//delay(5000);
|
||||
pinMode(sensor_fps, INPUT_PULLUP);
|
||||
pinMode(Enable, OUTPUT);
|
||||
pinMode(EN_M4, OUTPUT);
|
||||
digitalWrite(EN_M4, HIGH);
|
||||
analogWriteResolution(8);
|
||||
digitalWrite(Enable, LOW);
|
||||
sr.setAllLow(); // set all pins LOW
|
||||
ini_motors();
|
||||
secure_stop(FORWARD);
|
||||
attachInterrupt(digitalPinToInterrupt(sensor_fps), fps_count_state, RISING);
|
||||
|
||||
#if PID_ENABLE
|
||||
outMax = 255.0; // Límite máximo del controlador PID.
|
||||
outMin = 128.0; // Límite mínimo del controlador PID.
|
||||
|
||||
tmp = 5; // Tiempo de muestreo en milisegundos.
|
||||
|
||||
kp = 10.0; // Constantes PID iniciales. Los valores son los adecuados para un encoder de 334 ppr,
|
||||
ki = 3.5; // pero como el lector de encoder está diseñado como x4 equivale a uno de 1336 ppr. (ppr = pulsos por revolución.)
|
||||
kd = 30.0;
|
||||
|
||||
myPID.SetSampleTime(tmp); // Envía a la librería el tiempo de muestreo.
|
||||
myPID.SetOutputLimits(outMin, outMax);// Límites máximo y mínimo; corresponde a Max.: 0=0V hasta 255=5V (PWMA), y Min.: 0=0V hasta -255=5V (PWMB). Ambos PWM se convertirán a la salida en valores absolutos, nunca negativos.
|
||||
myPID.SetTunings(kp, ki, kd); // Constantes de sintonización.
|
||||
myPID.SetMode(AUTOMATIC); // Habilita el control PID (por defecto).
|
||||
Setpoint = 24; // Para evitar que haga cosas extrañas al inciarse, igualamos los dos valores para que comience estando el motor parado.
|
||||
#endif
|
||||
|
||||
#if DEBUG_M4
|
||||
RPC.println("M4 Inicializado.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
#if PID_ENABLE
|
||||
/*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.
|
||||
*/
|
||||
#endif
|
||||
refresh_position_motors();
|
||||
refresh_interval_motors();
|
||||
RPCRead();
|
||||
if(force_stop)
|
||||
{
|
||||
//config_speed_motor(FPS_MOTOR, !motorDirection, MIN_SPEED);
|
||||
//delay(20);
|
||||
stop(FPS_MOTOR);
|
||||
force_stop = false;
|
||||
}
|
||||
}
|
348
CraterLab_camera/include/main_m7.cpp
Normal file
348
CraterLab_camera/include/main_m7.cpp
Normal file
|
@ -0,0 +1,348 @@
|
|||
//#include <SPI.h>
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "interface.html"
|
||||
#include "constants.h"
|
||||
#include <RPC.h>
|
||||
|
||||
#define DEBUG_M7 false
|
||||
#define AP_MODE false
|
||||
|
||||
// Inicializando RTOS
|
||||
using namespace rtos;
|
||||
Thread sensorThread;
|
||||
|
||||
// Configuración de red WiFi
|
||||
const char *ssid = "Analogue_Hyperlapse_Camera";
|
||||
const char *password = "CraterLab";
|
||||
|
||||
IPAddress ip(192, 168, 8, 4);
|
||||
IPAddress remote_ip(192, 168, 8, 3);
|
||||
IPAddress gateway(192, 168, 8, 1);
|
||||
IPAddress subnet(255, 255, 255, 0);
|
||||
IPAddress dns(192, 168, 8, 1); //primaryDNS
|
||||
|
||||
// Crear el servidor en el puerto 80
|
||||
WiFiServer server(80);
|
||||
// Crear conexion UDP para enviar datos
|
||||
WiFiUDP Udp;
|
||||
unsigned int remotePort = 2390; // local port to send
|
||||
unsigned int localPort = 2392; // local port to read
|
||||
char packetBuffer[255]; //buffer to hold incoming packet
|
||||
char ReplyBuffer[] = "acknowledged"; // a string to send back
|
||||
|
||||
// Motor
|
||||
int motorSpeedValue = 25;
|
||||
bool motorIsSpeedActive = false;
|
||||
int motorIntervalFrames = 1;
|
||||
int motorIntervalSeconds = 1;
|
||||
bool motorIsIntervalActive = false;
|
||||
int motorDirection = 1;
|
||||
|
||||
// Shutter
|
||||
int shutterFadePercent = 0;
|
||||
int shutterFadeFrames = 50;
|
||||
bool shutterSyncWithInterval = false;
|
||||
bool shutterFadeInActive = false;
|
||||
bool shutterFadeOutActive = false;
|
||||
|
||||
// Óptica
|
||||
int zoomValue = 50;
|
||||
int focusValue = 50;
|
||||
float diaphragmValue = 1.8;
|
||||
bool syncWithIntervalOptics = false;
|
||||
|
||||
// Dispositivo 360
|
||||
int x0Degrees = 0;
|
||||
int x0Duration = 0;
|
||||
int x1Degrees = 0;
|
||||
int x1Duration = 0;
|
||||
int y0Degrees = 0;
|
||||
int y0Duration = 0;
|
||||
bool syncWithInterval360 = false;
|
||||
|
||||
//Sensores
|
||||
float motorSpeedRead = 0;
|
||||
float FadePercentRead = 0;
|
||||
int zoomValueRead = 0;
|
||||
int focusValueRead = 0;
|
||||
float diaphragmValueRead = 0;
|
||||
int x0DegreesRead = 0;
|
||||
int x1DegreesRead = 0;
|
||||
int y0DegreesRead = 0;
|
||||
|
||||
int read_value[10];
|
||||
int* decode_values(String inputString, int num_dec)
|
||||
{
|
||||
String str = inputString.substring(inputString.lastIndexOf(":") + 1);
|
||||
read_value[0] = str.substring(0, str.indexOf(',')).toInt();
|
||||
for(int i=1; i<num_dec; i++)
|
||||
{
|
||||
str = str.substring(str.indexOf(',')+1);
|
||||
read_value[i] = str.substring(0, str.indexOf(',')).toInt();
|
||||
}
|
||||
return read_value;
|
||||
}
|
||||
|
||||
char c_rpc;
|
||||
String inputString_rpc;
|
||||
|
||||
void RPCRead()
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
/////// RUTINA TRATAMIENTO DE STRINGS DEL UART ///////////
|
||||
////////////////////////////////////////////////////////////
|
||||
if (RPC.available())
|
||||
{
|
||||
c_rpc = RPC.read();
|
||||
if ((c_rpc == '\r') || (c_rpc == '\n'))
|
||||
{
|
||||
if (inputString_rpc.startsWith("/sensors:")) //Speed Motor
|
||||
{
|
||||
int* value = decode_values(inputString_rpc, 5);
|
||||
#if DEBUG_M4
|
||||
RPC.print("Recibido Speed M4: ");
|
||||
RPC.println(inputString_rpc);
|
||||
for(int i=0; i<5; i++) RPC.println(value[i]);
|
||||
#endif
|
||||
motorSpeedRead = value[0];
|
||||
FadePercentRead = value[1];
|
||||
zoomValueRead = value[2];
|
||||
focusValueRead = value[3];
|
||||
diaphragmValueRead = value[4];
|
||||
}
|
||||
else if(inputString_rpc.startsWith("/debug:"))
|
||||
{
|
||||
//int* value = decode_values(inputString_rpc, 5);
|
||||
//#if DEBUG_M7
|
||||
Serial.print("Recibido debug M4: ");
|
||||
Serial.println(inputString_rpc);
|
||||
//for(int i=0; i<5; i++) Serial.println(value[i]);
|
||||
//#endif
|
||||
|
||||
}
|
||||
inputString_rpc = String();
|
||||
}
|
||||
else
|
||||
inputString_rpc += c_rpc;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long time_refresh_sensors = millis();
|
||||
|
||||
void refresh_sensors()
|
||||
{
|
||||
if((millis()-time_refresh_sensors)>=500)
|
||||
{
|
||||
time_refresh_sensors = millis();
|
||||
RPC.println("/sensors:1");
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(1000000);
|
||||
RPC.begin(); //boots M4
|
||||
#if AP_MODE
|
||||
int status = WL_IDLE_STATUS;
|
||||
// Create open network. Change this line if you want to create an WEP network:
|
||||
WiFi.config(ip, dns, gateway, subnet);
|
||||
status = WiFi.beginAP(ssid, password);
|
||||
if (status != WL_AP_LISTENING) {
|
||||
Serial.println("Creating access point failed");
|
||||
// don't continue
|
||||
while (true)
|
||||
;
|
||||
}
|
||||
#else
|
||||
WiFi.config(ip, dns, gateway, subnet);
|
||||
WiFi.begin(ssid, password);
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
delay(1000);
|
||||
Serial.print(".");
|
||||
}
|
||||
#endif
|
||||
|
||||
Serial.println();
|
||||
Serial.println("Conectado a WiFi!");
|
||||
Serial.print("Dirección IP: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
// Enable Server
|
||||
server.begin();
|
||||
// Enable UDP
|
||||
Udp.begin(localPort);
|
||||
}
|
||||
|
||||
bool flag_send[10] = {false ,false ,false ,false ,false ,false ,false ,false ,false ,false};
|
||||
|
||||
void handlePostRequest(String body) {
|
||||
// Parseamos el cuerpo del JSON
|
||||
StaticJsonDocument<1000> doc;
|
||||
deserializeJson(doc, body);
|
||||
int save = true;
|
||||
//DeserializationError error = deserializeJson(doc, body);
|
||||
/*if (error) {
|
||||
Serial.println("Error al parsear el JSON");
|
||||
return;
|
||||
}*/
|
||||
|
||||
Serial.println("Procesando JSON...");
|
||||
String type = doc["type"];
|
||||
if ((type=="save_motor")||(type=="test_motor"))
|
||||
{
|
||||
Serial.println(type);
|
||||
if (type=="save_motor") save = true;
|
||||
else save = false;
|
||||
|
||||
/*motorSpeedValue = doc["speedValue"];
|
||||
motorIsSpeedActive = doc["isSpeedActive"];
|
||||
motorIntervalFrames = doc["intervalFrames"];
|
||||
motorIntervalSeconds = doc["intervalSeconds"];
|
||||
motorIsIntervalActive = doc["isIntervalActive"];
|
||||
String Direction = doc["direction"];*/
|
||||
motorSpeedValue = doc["0"];
|
||||
motorIsSpeedActive = doc["1"];
|
||||
motorIntervalFrames = doc["2"];
|
||||
motorIntervalSeconds = doc["3"];
|
||||
motorIsIntervalActive = doc["4"];
|
||||
String Direction = doc["5"];
|
||||
if (Direction=="forward") motorDirection = FORWARD;
|
||||
else if (Direction=="backward") motorDirection = BACKWARD;
|
||||
if(motorIsSpeedActive)
|
||||
{
|
||||
RPC.println("/s_motor:" + String(FPS_MOTOR) + "," + String(motorDirection) + "," + String(motorSpeedValue) + "," + String(save));
|
||||
}
|
||||
else if(motorIsIntervalActive)
|
||||
{
|
||||
RPC.println("/i_motor:" + String(FPS_MOTOR) + "," + String(motorDirection) + "," + String(motorIntervalFrames) + "," + String(motorIntervalSeconds) + "," + String(save));
|
||||
}
|
||||
/*Clave: type, Valor: motor
|
||||
Clave: speedValue, Valor: )25
|
||||
Clave: isSpeedActive, Valor: false
|
||||
Clave: intervalFrames, Valor: 1
|
||||
Clave: intervalSeconds, Valor: 1
|
||||
Clave: isIntervalActive, Valor: false
|
||||
Clave: direction, Valor: forward*/
|
||||
}
|
||||
else if ((type=="test_shutter")||(type=="save_shutter") )
|
||||
{
|
||||
Serial.println(type);
|
||||
if (type=="save_shutter") save = true;
|
||||
else save = false;
|
||||
/*shutterFadePercent = doc["fadePercent"];
|
||||
shutterFadeFrames = doc["fadeFrames"];
|
||||
shutterSyncWithInterval = doc["syncWithInterval"];
|
||||
shutterFadeInActive = doc["fadeInActive"];
|
||||
shutterFadeOutActive = doc["fadeOutActive"];*/
|
||||
shutterFadePercent = doc["0"];
|
||||
shutterFadeFrames = doc["1"];
|
||||
shutterSyncWithInterval = doc["2"];
|
||||
shutterFadeInActive = doc["3"];
|
||||
shutterFadeOutActive = doc["4"];
|
||||
RPC.println("/fade:" + String(shutterFadePercent) + "," + String(shutterFadeFrames) + "," + String(shutterSyncWithInterval) + "," + String(shutterFadeInActive) + "," + String(shutterFadeOutActive) + "," + String(save));
|
||||
}
|
||||
else if ((type=="test_optics")||(type=="save_optics"))
|
||||
{
|
||||
Serial.println(type);
|
||||
if (type=="save_optics") save = true;
|
||||
else save = false;
|
||||
zoomValue = doc["zoomValue"];
|
||||
focusValue = doc["focusValue"];
|
||||
diaphragmValue = doc["diaphragmValue"];
|
||||
syncWithIntervalOptics = doc["syncWithInterval"];
|
||||
RPC.println("/optics:" + String(zoomValue) + "," + String(focusValue) + "," + String(diaphragmValue) + "," + String(syncWithIntervalOptics) + "," + String(save));
|
||||
}
|
||||
else if (type=="accion")
|
||||
{
|
||||
Serial.println(type);
|
||||
RPC.println("/action:" + String(1));
|
||||
Udp.beginPacket(remote_ip, remotePort);
|
||||
Udp.println("/action:" + String(1));
|
||||
Udp.endPacket();
|
||||
}
|
||||
else if (type=="corten")
|
||||
{
|
||||
Serial.println(type);
|
||||
RPC.println("/action:" + String(0));
|
||||
Udp.beginPacket(remote_ip, remotePort);
|
||||
Udp.println("/action:" + String(0));
|
||||
Udp.endPacket();
|
||||
}
|
||||
else if (type=="stop") RPC.println("/s_motor:4," + String(motorDirection) + "," + String(0) + ", 0");
|
||||
else Serial.println("No reconocido");
|
||||
}
|
||||
|
||||
unsigned long time_blink=millis();
|
||||
bool state = false;
|
||||
|
||||
void loop() {
|
||||
WiFiClient client = server.available();
|
||||
if (client) {
|
||||
#if DEBUG_M7
|
||||
Serial.println("Nuevo cliente conectado");
|
||||
#endif
|
||||
String request = "";
|
||||
bool isPostRequest = false;
|
||||
|
||||
while (client.connected()) {
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
request += c;
|
||||
|
||||
// Identificar si es una solicitud POST
|
||||
if (request.indexOf("POST") >= 0) {
|
||||
isPostRequest = true;
|
||||
}
|
||||
|
||||
// Si se encuentra el final de la solicitud
|
||||
if (c == '\n' && request.endsWith("\r\n\r\n")) {
|
||||
#if DEBUG_M7
|
||||
Serial.println("Solicitud recibida:");
|
||||
Serial.println(request);
|
||||
#endif
|
||||
|
||||
if (isPostRequest) {
|
||||
String body = "";
|
||||
while (client.available()) {
|
||||
body += (char)client.read();
|
||||
}
|
||||
#if DEBUG_M7
|
||||
Serial.println("Cuerpo del mensaje recibido:");
|
||||
Serial.println(body);
|
||||
#endif
|
||||
// Llamamos a la función para procesar la petición POST
|
||||
handlePostRequest(body);
|
||||
// Respuesta al cliente
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/plain");
|
||||
client.println();
|
||||
client.println("Datos enviados correctamente");
|
||||
} else if (request.indexOf("GET /sensors") >= 0) { // actualiza fps en interface
|
||||
// Respuesta para la ruta /motorSpeed
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-Type: application/json");
|
||||
client.println();
|
||||
String response = "{\"sensors\":[" + String(motorSpeedRead) + "," + String(FadePercentRead) + "]}";
|
||||
client.print(response);
|
||||
} else {
|
||||
// Respuesta para servir la interfaz HTML
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/html");
|
||||
client.println();
|
||||
client.print(htmlTemplate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
client.stop();
|
||||
#if DEBUG_M7
|
||||
Serial.println("Cliente desconectado");
|
||||
#endif
|
||||
}
|
||||
//Enviar datos a M4
|
||||
RPCRead();
|
||||
refresh_sensors();
|
||||
}
|
46
CraterLab_camera/lib/README
Normal file
46
CraterLab_camera/lib/README
Normal file
|
@ -0,0 +1,46 @@
|
|||
|
||||
This directory is intended for project specific (private) libraries.
|
||||
PlatformIO will compile them to static libraries and link into executable file.
|
||||
|
||||
The source code of each library should be placed in an own separate directory
|
||||
("lib/your_library_name/[here are source files]").
|
||||
|
||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||
|
||||
|--lib
|
||||
| |
|
||||
| |--Bar
|
||||
| | |--docs
|
||||
| | |--examples
|
||||
| | |--src
|
||||
| | |- Bar.c
|
||||
| | |- Bar.h
|
||||
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||
| |
|
||||
| |--Foo
|
||||
| | |- Foo.c
|
||||
| | |- Foo.h
|
||||
| |
|
||||
| |- README --> THIS FILE
|
||||
|
|
||||
|- platformio.ini
|
||||
|--src
|
||||
|- main.c
|
||||
|
||||
and a contents of `src/main.c`:
|
||||
```
|
||||
#include <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
PlatformIO Library Dependency Finder will find automatically dependent
|
||||
libraries scanning project source files.
|
||||
|
||||
More information about PlatformIO Library Dependency Finder
|
||||
- https://docs.platformio.org/page/librarymanager/ldf.html
|
33
CraterLab_camera/platformio.ini
Normal file
33
CraterLab_camera/platformio.ini
Normal file
|
@ -0,0 +1,33 @@
|
|||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:ARDUINO_GIGA_M7]
|
||||
;platform = https://github.com/dberlin/platform-ststm32.git#develop
|
||||
;platform = https://github.com/dberlin/platform-ststm32
|
||||
platform = ststm32
|
||||
board = giga_r1_m7
|
||||
framework = arduino
|
||||
monitor_speed = 1000000
|
||||
;upload_port = COM12
|
||||
board_build.arduino.flash_layout = 75_25 ;50_50, 75_25, 100_0
|
||||
lib_deps = https://github.com/br3ttb/Arduino-PID-Library
|
||||
bblanchon/ArduinoJson@^7.2.0
|
||||
|
||||
|
||||
[env:ARDUINO_GIGA_M4]
|
||||
;platform = https://github.com/dberlin/platform-ststm32.git#develop
|
||||
platform = ststm32
|
||||
board = giga_r1_m4
|
||||
framework = arduino
|
||||
monitor_speed = 1000000
|
||||
;upload_port = COM12
|
||||
board_build.arduino.flash_layout = 75_25 ;50_50, 75_25, 100_0
|
||||
lib_deps = https://github.com/Simsso/ShiftRegister74HC595
|
||||
https://github.com/br3ttb/Arduino-PID-Library
|
7
CraterLab_camera/src/main.cpp
Normal file
7
CraterLab_camera/src/main.cpp
Normal file
|
@ -0,0 +1,7 @@
|
|||
#if defined(ARDUINO_GIGA_M7)
|
||||
#include<main_m7.cpp>
|
||||
#elif defined(ARDUINO_GIGA_M4)
|
||||
#include<main_m4.cpp>
|
||||
#else
|
||||
#include<main_m7.cpp>
|
||||
#endif
|
11
CraterLab_camera/test/README
Normal file
11
CraterLab_camera/test/README
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
This directory is intended for PlatformIO Test Runner and project tests.
|
||||
|
||||
Unit Testing is a software testing method by which individual units of
|
||||
source code, sets of one or more MCU program modules together with associated
|
||||
control data, usage procedures, and operating procedures, are tested to
|
||||
determine whether they are fit for use. Unit testing finds problems early
|
||||
in the development cycle.
|
||||
|
||||
More information about PlatformIO Unit Testing:
|
||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Reference in a new issue