TP1 NIzza, Ponti, Pereyra
TP1 NIzza, Ponti, Pereyra
TP1 NIzza, Ponti, Pereyra
Equipo de Cátedra:
• Burgos Sergio
• Lencina Adrián
Integrantes Grupo:
• Pereyra, Agustín
• Nizza, Tomás
• Ponti, Pedro
if (ch == 0xFF) {
vTaskDelay(10 / portTICK_PERIOD_MS);
continue;
}
void app_main()
{
bool appClose = false;
bool cmdOk;
int argc;
unsigned k;
char line[120];
unsigned lineLength;
char * argv[60];
const cmd *c;
hardware_init();
vTaskDelay(500 / portTICK_PERIOD_MS);
printf("=========== Programa Iniciado ============\n");
c = getCommands();
while(!appClose){
printf(">");
getLine(line,119);
printf("\n");
argc = 1;
line[strlen(line)] = '\0';
argv[0] = line;
lineLength = strlen(line);
for(k = 0; (k < lineLength) && (argc < 60); k++){
if(line[k] == ' '){
line[k] = '\0';
argv[argc] = line + k + 1;
argc++;
}
}
cmdOk = false;
k = 0;
while(c[k].act){
if(strcmp(c[k].keyWord, argv[0]) == 0){
cmdOk = true;
if(c[k].act(argc, argv))
printf(" [%s Fail]\n", argv[0]);
}
k++;
}
if(!cmdOk && strlen(argv[0]))
printf("Comando inexistente\n");
}
esp_restart();
}
Como se puede notar no hay muchas diferencias entre este main con el que nos dio el profesor en el ejemplo de QT,
una diferencia seria el ingreso de los datos ya que se hace por medio de la función getLine (que lee caracteres del
teclado hasta encontrar una nueva línea, retorno de carro o alcanzar el tamaño máximo del buffer, maneja los
caracteres de retroceso y borrado, y almacena la entrada en un buffer proporcionado por el usuario, terminándola
con un carácter nulo), cuando en el ejemplo de QT era por un fgets
Menu.c:
#include "menu.h"
#include "hardware.h"
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
Para este menu.c agregamos la función multiplicar (que la pedía a fin de entender el funcionamiento) y la función led
(que tiene como fin utilizar el led de la ESP32). Para hacer la función led tomamos como referencia las funciones
anteriores, tiene que devolver un 1 (en caso de éxito en la implementación) o -1 (en caso de falla), como vemos
compara el segundo argumento(argv[1]) con las palabras “off”, “on” y “parpadear” ya que esos son los 3 comandos
solicitados, si es así ejecuta la función requerida, la función “ledOn()” y “ledOff()” las reutilizamos de los ejemplos de
las clase 3. Las demás funciones son las mismas utilizadas en el ejemplo de QT que nos dio el profe.
Hardware.c:
#include "hardware.h"
#include <driver/gpio.h>
void hardware_init(void){
gpio_config_t gpioLed =
{
.pin_bit_mask = 1ULL << ledPin,
.mode = GPIO_MODE_DEF_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
ESP_ERROR_CHECK(gpio_config(&gpioLed));
ledOff();
}
void ledOn(void){
ESP_ERROR_CHECK(gpio_set_level(ledPin, 1));
}
void ledOff(void){
ESP_ERROR_CHECK(gpio_set_level(ledPin, 0));
}
El campo pin bit mask contiene 64 posiciones, la primera corresponde con el pin 0 (GPIO NUM 0), la siguiente con el
pint 1 (GPIO NUM 1) y asi sucesivamente hasta el pin 39 (GPIO NUM 39). Cuando se ponen unos en esas posiciones,
se indica que esos pines recibiran la configuracion indicada. La función “hardware_init” configura un pin GPIO en la
ESP32 como una salida sin resistencias pull-up ni pull-down y sin interrupciones. Después de configurar el pin, apaga
el LED utilizando la función “ledOff”.
Hardware.h:
#ifndef hardware_h
#define hardware_h
void hardware_init(void);
void ledOn(void);
void ledOff(void);
#endif
Menú.h:
#ifndef MENU_H
#define MENU_H
#include <stdio.h>
#include <stdbool.h>
typedef int (*pAction)(int, char **);
typedef struct {
pAction act;
char *keyWord;
char *help;
} cmd;
int sumar(int argc, char * argv[]);
int multiplicar (int argc, char *argv[]);
int restar(int argc, char * argv[]);
int exitCmd(int argc, char * argv[]);
int help(int argc, char * argv[]);
int led(int argc, char * argv[]);
Lo primero que hicimos fue documentar los archivos de cabecera los ¨.h¨:
Menu.h:
/**
* @title menu.
* @file munu.h.
* @version 1.0.
* @date 14/06/2024.
* @author grupoinfo.
*/
#ifndef MENU_H
#define MENU_H
#include <stdio.h>
#include <stdbool.h>
/**
* @brief puntero a funcion
*/
typedef int (*pAction)(int, char **);
/**
* @brief hace funcionar el menu.
*/
typedef struct {
pAction act;
char *keyWord;
char *help;
} cmd;
/**
* @brief sumar la funcion suma
* @param argc dica la cantidad de argumentos en la llamada de línea de comandos.
* @param argv es una matriz de cadenas que contiene los argumentos en la llamada de
línea de comandos.
* @return Una descripción del valor de retorno de la función.
*/
int sumar(int argc, char * argv[]);
/**
* @brief multiplicar funcion multiplicar
* @param argc :Este es un parámetro de la función que indica la cantidad de argumentos
en la llamada de línea de comandos.
* @param argv :Este es un parámetro de la función que es una matriz de cadenas que
contiene los argumentos en la llamada de línea de comandos.
* @return devuelve el resultado de una operación.
*/
int multiplicar (int argc, char *argv[]);
/**
* @brief restar funcion de resta
* @param argc :Este es un parámetro de la función que indica la cantidad de argumentos
en la llamada de línea de comandos.
* @param argv :Este es un parámetro de la función que es una matriz de cadenas que
contiene los argumentos en la llamada de línea de comandos.
* @return Una descripción del valor de retorno de la función.
*/
int restar(int argc, char * argv[]);
/**
* @brief exitCmd la operación de salida del programa
* @param argc :Este es un parámetro de la función que indica la cantidad de argumentos
en la llamada de línea de comandos.
* @param argv :Este es un parámetro de la función que es una matriz de cadenas que
contiene los argumentos en la llamada de línea de comandos.
* @return retorno de la función.
*/
int exitCmd(int argc, char * argv[]);
/**
* @brief help proporcione ayuda al usuario.
* @param argc :Este es un parámetro de la función que indica la cantidad de argumentos
en la llamada de línea de comandos.
* @param argv :Este es un parámetro de la función que es una matriz de cadenas que
contiene los argumentos en la llamada de línea de comandos.
* @return retorno de la función.
*/
int help(int argc, char * argv[]);
/**
* @brief led maneje la operación de un LED
* @param argc :Este es un parámetro de la función que indica la cantidad de argumentos
en la llamada de línea de comandos.
* @param argv :Este es un parámetro de la función que es una matriz de cadenas que
contiene los argumentos en la llamada de línea de comandos.
* @return retorno de la función.
*/
int led(int argc, char * argv[]);
/**
* @brief getCommands devuelve un puntero a una matriz de estructuras
* @return retorno de la función.
*/
Hardware.h:
/**
*@title hardware.
* @file hardware.h.
* @version 1.0.
* @date 14/06/2024.
* @author grupoinfo.
*/
#ifndef hardware_h
#define hardware_h
/**
* @brief hardware_init :Esta función inicializa el hardware, habilitada para la
iluminación del LED.
*/
void hardware_init(void);
/**
* @brief ledOn :Esta función enciende el LED.
*/
void ledOn(void);
/**
* @brief ledOff :Esta función enciende el LED.
*/
void ledOff(void);
#endif
Después documentamos los archivos en doxygen, tuvimos que poner un título del proyecto,
también de que se trataba el código, después pusimos la ruta del código fuente y también ruta de
donde queríamos que se guarde el programa.
Pagina principal:
Clases:
Archivos:
Parte II: Resolución de ecuaciones
Para empezar con la explicación debemos tener en cuenta las funciones que nos da el enunciado.
Curva catenaria: Longitud del cable:
𝑥 𝑥
𝑓 (𝑥 ) = 𝑐 ∗ (cosh ( ) − 1) 𝑠 = 2 ∗ 𝑐 ∗ 𝑠𝑒𝑛ℎ ( )
𝑐 𝑐
Para este caso los valores usados son x = 50, que es la mitad de la distancia entre los postes y f(x) = 2, que es la
longitud de la catenaria, distancia entre el punto más bajo y más alto. Con lo cual la función de la catenaria dad es la
siguiente:
50
2 = 𝑐 ∗ (cosh ( ) − 1)
𝑐
Para poder realizar el método de punto fijo, hay que despejar “c”. A continuación, vamos a mostrar 2 formas en la
cual se puede expresar la ecuación para poder realizar el método de punto fijo.
Despeje 1 Despeje 2
50 Dividimos todo por “c”
2 = 𝑐 ∗ (cosh ( ) − 1) 50
𝑐
50 2 𝑐 ∗ (cosh ( 𝑐 ) − 1)
0 = 𝑐 ∗ cosh ( ) − 𝑐 − 2 =
𝑐 𝑐 𝑐
2 50
+ 1 = cosh ( )
50 𝑐 𝑐
𝑐 = 𝑐 ∗ cosh ( ) − 2 2 50
𝑐 𝑐𝑜𝑠ℎ−1 ( + 1) =
𝑐 𝑐
50
𝑐=
2
𝑐𝑜𝑠ℎ−1 ( + 1)
𝑐
De las 2 formas funciona, solo que usando el despeje 1 necesita muchas mas iteraciones para poder llegar al mismo
valor de c. Pero el inconveniente que tenemos es que, al usar la ecuación de menos iteraciones, el despeje 2, luego
no nos sirve para usar el método de la bisección, ya que el primer valor que retorna esta fuera del intervalo en el
cual el método de la bisección puede trabajar para obtener el mismo valor de c. Así que por ese motivo vamos a usar
la ecuación del despeje 1 para que puedan funcionar los otros 2 métodos.
Después de esa aclaración vamos al código, mostraremos primero los .h de cada clase y a continuación los .cpp de
las respectivas clases. Y por último el main.cpp:
MetodoNumerico.h:
#ifndef METODO_NUMERICO_H
#define METODO_NUMERICO_H
#include <cmath>
class MetodoNumerico {
protected:
double distPostesDiv2;
double longCatenaria;
double c; // Constante c
double longitudCable; // Longitud del cable
public:
MetodoNumerico(double distPostesDiv2, double longCatenaria);
double getConstanteC();
double getLongitudCable();
// Función con c despejada
double ecuacion(double c, double x, double fx);
// Función igualada a 0
double ecuacion2(double c, double x, double fx);
double calcularLongitudCable(double c);
};
#endif // METODO_NUMERICO_H
MetodoNumerico.cpp:
#include "metodonumerico.h"
double MetodoNumerico::getConstanteC(){
return c;
}
double MetodoNumerico::getLongitudCable(){
return longitudCable;
}
double MetodoNumerico::calcularLongitudCable(double c) {
return 2 * c * sinh(distPostesDiv2 / c);
}
Esta clase sirve como una base común para implementar diferentes métodos numéricos (PuntoFijo, Secante y
Bisección) que comparten funcionalidades comunes relacionadas con el cálculo de constante “c” y longitud del cable
“s”.
PuntoFijo.h:
#ifndef PUNTO_FIJO_H
#define PUNTO_FIJO_H
#include "metodonumerico.h"
public:
PuntoFijo(double x0, int maxIt, double epsilon, double* SegundoValor, double
distPostesDiv2, double longCatenaria);
void CalculoC();
double getConstanteC();
double getLongitudCable();
};
#endif // PUNTO_FIJO_H
PuntoFijo.cpp:
#include "puntofijo.h"
#include <iostream>
using namespace std;
void PuntoFijo::CalculoC() {
double x1 = x0;
int itCnt = 0;
bool finish = false;
cout << "Punto Fijo:" << endl;
cout << "Iteracion x0 x1" << endl;
cout << "---------------------------------------" << endl;
while ((itCnt < maxIt) && (!finish)) {
x1 = ecuacion(x0, distPostesDiv2, longCatenaria);
cout << itCnt + 1 << "\t\t" << x0 << "\t\t" << x1 << endl;
finish = fabs(x1 - x0) < epsilon;
if (itCnt == 0) {
*SegundoValor = x1; // Guarda el primer resultado para el metodo Secante y
Biseccion
}
itCnt++;
x0 = x1;
}
c = x1;
longitudCable = calcularLongitudCable(c);
}
double PuntoFijo::getConstanteC() {
return MetodoNumerico::getConstanteC(); // Llama al método de la clase base
}
double PuntoFijo::getLongitudCable() {
return MetodoNumerico::getLongitudCable(); // Llama al método de la clase base }
Secante.h:
#ifndef SECANTE_H
#define SECANTE_H
#include "metodonumerico.h"
class Secante : public MetodoNumerico{
private:
double x0;
double x1;
double epsilon;
int maxIt;
public:
Secante(double x0, double x1, double epsilon, int maxIt, double distPostesDiv2,
double longCatenaria);
void CalculoC();
double getConstanteC();
double getLongitudCable();
};
#endif // SECANTE_H
Secante.cpp:
#include "secante.h"
#include <iostream>
using namespace std;
void Secante::CalculoC() {
double x2;
int itCnt = 0;
bool finish = false;
cout << endl << "Secante:" << endl;
cout << "Iteracion x0 x1 x2" << endl;
cout << "-------------------------------------------------------" << endl;
do {
double f_x1 = ecuacion2(x1, distPostesDiv2, longCatenaria);
double f_x0 = ecuacion2(x0, distPostesDiv2, longCatenaria);
x2 = x1 - (f_x1 * (x1 - x0) / (f_x1 - f_x0));
cout << itCnt + 1 << "\t\t" << x0 << "\t\t" << x1 << "\t\t" << x2 << endl;
finish = (fabs(ecuacion2(x2, distPostesDiv2, longCatenaria)) < epsilon) ||
(fabs(x2 - x1) < epsilon);
x0 = x1;
x1 = x2;
itCnt++;
} while ((itCnt < maxIt) && (!finish));
c = x2;
longitudCable = calcularLongitudCable(c);
}
double Secante::getConstanteC() {
return MetodoNumerico::getConstanteC(); // Llama al método de la clase base
}
double Secante::getLongitudCable() {
return MetodoNumerico::getLongitudCable(); // Llama al método de la clase base }
Biseccion.h:
#ifndef BISECCION_H
#define BISECCION_H
#include "metodonumerico.h"
public:
Biseccion(double xi, double xd, double epsilon, int maxIt, double distPostesDiv2,
double longCatenaria);
void CalculoC();
double getConstanteC();
double getLongitudCable();
};
#endif // BISECCION_H
Biseccion.cpp:
#include "biseccion.h"
#include <iostream>
using namespace std;
void Biseccion::CalculoC() {
double xm;
int itCnt = 0;
bool finish = false;
cout << endl << "Biseccion:" << endl;
cout << "Iteracion xi xm xd" << endl;
cout << "-------------------------------------------------------" << endl;
do {
xm = (xd + xi) / 2;
cout << itCnt + 1 << "\t\t" << xi << "\t\t" << xm << "\t\t" << xd << endl;
finish = (fabs(ecuacion2(xm, distPostesDiv2, longCatenaria)) < epsilon) ||
(fabs(xd - xi) < epsilon);
if (!finish) {
if (ecuacion2(xi, distPostesDiv2, longCatenaria) * ecuacion2(xm,
distPostesDiv2, longCatenaria) > 0)
xi = xm;
else
xd = xm;
}
itCnt++;
} while ((itCnt < maxIt) && (!finish));
c = xm;
longitudCable = calcularLongitudCable(c);
}
double Biseccion::getConstanteC() {
return MetodoNumerico::getConstanteC(); // Llama al método de la clase base
}
double Biseccion::getLongitudCable() {
return MetodoNumerico::getLongitudCable(); // Llama al método de la clase base }
Las clases PuntoFijo, Secante y Biseccion contienen la implementación específica de cada método, aprovechando la
estructura y funcionalidad proporcionada por la clase base MetodoNumerico para realizar los cálculos numéricos
respectivos y obtener los correctos resultados.
Main.cpp:
#include <iostream>
#include "puntofijo.h"
#include "secante.h"
#include "biseccion.h"
int main() {
double SegundoValor;
double longCatenaria, distPostes, distPostesDiv2;
cout << "Ingrese la longitud de la catenaria [m](distancia del punto mas alto al
mas bajo): ";
cin >> longCatenaria;
// Método de la Secante
Secante metodoSecante(10, SegundoValor, 1E-5, 25, distPostesDiv2, longCatenaria);
metodoSecante.CalculoC();
// Método de Bisección
Biseccion metodoBiseccion(10, SegundoValor, 1E-5, 25, distPostesDiv2,
longCatenaria);
metodoBiseccion.CalculoC();
return 0; }
El main del programa solicita al usuario la longitud de la catenaria y la distancia entre los postes, esto lo hicimos así
para que sea una aplicación útil y que se pueda calcular con diferentes valores, no solo con los valores propuestos
por el ejercicio.
UML explicativo donde se pueden observar las diferentes clases utilizadas con sus relaciones, atributos y métodos.
Para realizar el programa decidimos utilizar los puntos que nos daba el enunciado, que forman la siguiente malla:
Después de estas aclaraciones, mostraremos los .h y los .cpp de cada clase. Y finalmente el main.cpp:
PUNTOS.H:
#ifndef PUNTOS_H
#define PUNTOS_H
class puntos
{
private:
int x;
int y;
public:
puntos(int x, int y);
int getX(void);
int getY(void);
};
#endif // PUNTOS_H
PUNTOS.CPP:
#include "puntos.h"
int puntos::getX(){
return x;
}
int puntos::getY(){
return y;
}
Como podemos observar la clase puntos consta de dos coordenadas, un constructor que sirve para introducir sus
valores, y dos métodos “get” para obtener cada una de estas.
TRIANGULOS.H:
#ifndef TRIANGULOS_H
#define TRIANGULOS_H
#include <cmath>
#include "puntos.h"
class triangulos
{
private:
puntos *punto1;
puntos *punto2;
puntos *punto3;
float area;
public:
triangulos(puntos*punto1,puntos*punto2,puntos*punto3);
void setArea();
float getArea();
};
#endif // TRIANGULOS_H
TRIANGULOS.CPP:
#include "triangulos.h"
triangulos::triangulos(puntos*punto1,puntos*punto2,puntos*punto3)
{
this->punto1=punto1;
this->punto2=punto2;
this->punto3=punto3;
}
void triangulos::setArea(){
float ladoA,ladoB,ladoC;
//para sacar lados de el triangulo
//1-2 , 2-3 , 3-1
ladoA=sqrt(pow(punto1->getX()-punto2->getX(),2)+pow(punto1->getY()-punto2-
>getY(),2));
ladoB=sqrt(pow(punto2->getX()-punto3->getX(),2)+pow(punto2->getY()-punto3-
>getY(),2));
ladoC=sqrt(pow(punto3->getX()-punto1->getX(),2)+pow(punto3->getY()-punto1-
>getY(),2));
//heron
float s=(ladoA+ladoB+ladoC)/2;
area=sqrt(s*(s-ladoA)*(s-ladoB)*(s-ladoC));
}
float triangulos::getArea(){
return area;
}
Esta clase contiene tres direcciones de memoria de puntos, que se ingresan mediante su constructor. También
consta de un área, que se puede calcular y obtener mediante dos métodos.
El área de los triángulos la calculamos mediante la formula de Heron, que sirve para calcular el área de triángulos
que no necesariamente son rectángulos a partir de los lados de el triángulo. A estos lados, los calculamos haciendo
el modulo de la resta de sus puntos.
MALLA.H:
#ifndef MALLA_H
#define MALLA_H
#include "triangulos.h"
struct nodo{
triangulos *triangulo;
nodo* sig;
};
class malla
{
private:
nodo* inicio;
float superficieTotal;
int cantTriangulos;
public:
malla();
void agregarTriangulo(triangulos *triangulo);
void setSupTotal();
float getSupTotal();
int cantTriangulosMayoresA(float c);
~malla();
};
#endif // MALLA_H
MALLA.CPP:
#include "malla.h"
malla::malla(){
cantTriangulos=0;
inicio=nullptr;
}
nodo *trianguloNuevo;
trianguloNuevo= new(nodo);
trianguloNuevo->triangulo=triangulo;
trianguloNuevo->sig=nullptr;
if(inicio==nullptr){
inicio=trianguloNuevo;
cantTriangulos=1;
}
else {
while(actual!=nullptr){
anterior=actual;
actual=actual->sig;
}
anterior->sig=trianguloNuevo;
cantTriangulos=cantTriangulos+1;
}
}
void malla::setSupTotal(){
nodo*actual=inicio;
float suptotal=0;
while (actual!=nullptr) {
actual->triangulo->setArea();
suptotal=suptotal+actual->triangulo->getArea();
actual=actual->sig;
}
superficieTotal=suptotal;
}
float malla::getSupTotal(){
return superficieTotal;
}
malla::~malla(){
nodo*actual=inicio;
nodo*anterior;
while (actual!=nullptr) {
anterior=actual;
actual=actual->sig;
delete (anterior);
}
}
Esta clase guarda la dirección de inicio de una lista enlazada de triángulos, a esto lo realizamos de esta forma para
que sea sencillo cambiar la malla.
Esta clase también permite mediante un método de calcular la superficie total de la malla completa, sumando la
superficie de cada triangulo.
Otro atributo que contiene es la cantidad de triángulos de la malla, esto lo agregamos porque es una información
que podría llegar a ser útil en algunas posibles ocasiones.
Finalmente consta de un método al que el usuario le entrega un número y este devuelve la cantidad de triángulos
que tienen un área superior a este número.
Por ultimo el destructor de este elimina la lista enlazada, para que no quede memoria dinámica guardada.
MAIN.CPP:
#include <iostream>
#include "malla.h"
int main()
{
puntos p1(1,5), p2(2,3), p3(3,7), p4(5,5),p5(5,2),p6(6,7),p7(7,3);
triangulos
t1(&p1,&p2,&p4),t2(&p1,&p3,&p4),t3(&p2,&p4,&p5),t4(&p3,&p4,&p6),t5(&p4,&p5,&p7),t6(&p4,
&p6,&p7);
malla m;
int n;
m.agregarTriangulo(&t1);
m.agregarTriangulo(&t2);
m.agregarTriangulo(&t3);
m.agregarTriangulo(&t4);
m.agregarTriangulo(&t5);
m.agregarTriangulo(&t6);
m.setSupTotal();
cout<<"area total: "<<m.getSupTotal()<<endl;
cout<<"ingrese un numero para saber cuantas areas hay superior a este:"<<endl;
cin>>n;
cout<<"cant areas mayores a "<<n<<" :"<<m.cantTriangulosMayoresA(n)<<endl;
return 0;
}
En el main creamos todos los puntos, introduciendo en ellos sus coordenadas. Después, con estos puntos creamos
los triángulos correspondientes. Luego de esto, añadimos cada triangulo a la malla.
Finalmente devolvemos el área de la malla y le preguntamos al usuario un área para comunicarle cuantos de estos
triángulos son mayores a esta.