lunes, 18 de mayo de 2015

Control experimental y pruebas de su comportamiento Parte 2

Finalmente, en lo que se refiere a las pruebas experimentales, se anulo el sistema de control y se hicieron más pruebas para definir cuál debería ser el ciclo de trabajo dependiendo de la velocidad recibida al inicio. En el eje ‘Y’ aparecen valores entre 0 y 255, los cuales determinan el ciclo de trabajo que irá a los drivers para que la velocidad corresponda con las pruebas realizadas a través de la ecuación que proporciona Excel con la línea de tendencia (esta ecuación se incluyó en la programación).


Esquemático

Para la conexión física, además del Teensy++, se utilizaron algunos módulos adicionales que ayudan al control de los motores del robot. En el esquemático que se presenta a continuación se pueden apreciar todas las conexiones del microcontrolador y en la tabla se describe cada entrada o salida utilizada del Teensy. 


PIN
Tipo de Señal
Descripción
PB7
PD0
Salida
Este pin manda una señal al Driver que controla el motor izquierdo/derecho la señal de PWM que determina la velocidad del motor correspondiente.
PC3
PD6
Entrada
Este pin recibe una señal cuadrada proveniente del Encoder indicado a través de su frecuencia, la velocidad de giro del motor izquierdo/derecho. Para controlar los picos de voltaje positivos y negativos se agregó una configuración de seguridad con un transistor que funciona como switch en serie con un buffer que conecta al Teensy.
PD2
Entrada
Es el pin de recepción (RX) del Teensy, que se conecta al pin de TX de la RaspBerry a través de un convertidor de voltaje (5v a 3.3v) para hacer una interfaz confiable entre ambos dispositivos.
PD3
Salida
Es el pin de transmisión (TX) del Teensy, que se conecta al pin de RX de la RaspBerry a través de un convertidor de voltaje (3.3v a 5v) para hacer una interfaz confiable entre ambos dispositivos.
PF0
Salida
Este pin se conecta al pin A del driver del motor izquierdo para controlar su dirección de giro.
PF1
Salida
Este pin se conecta al pin B del driver del motor izquierdo para controlar su dirección de giro.
PF2
Salida
Este pin se conecta al pin B del driver del motor derecho para controlar su dirección de giro.
PF3
Salida
Este pin se conecta al pin A del driver del motor derecho para controlar su dirección de giro.
PF4
Salida
Se conecta al pin de Trigger del sensor ultrasónico para comenzar la medición.
PF5
Entrada
Se conecta al pin de Echo del sensor ultrasónico para recibir la señal y hacer las mediciones.

Diseño de la página web y comunicación serial.

Para crear el archivo .html se utilizó el editor de texto Brackets (http://brackets.io/) y el framework Bootstrap (http://getbootstrap.com/), el archivo .zip con todo el proyecto se encuentra en el blog con el nombre de Página web. A continuación se presenta el diara de flujo y se explica el código más importante (Javascript) que permite la comunicación serial.



Encabezado
Declaración del formato de codificación de caracteres, librerías de Bootstrap, íconos, estilos y scripts en Javascript.
<head>
    <!-- Basic Page Needs
    ================================================== -->
    <meta charset="utf-8">
    <!--[if IE]><meta http-equiv="x-ua-compatible" content="IE=9" /><![endif]-->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Destructinador</title>   
    <!-- Favicons
    ================================================== -->
    <link rel="shortcut icon"       href="img/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon"    href="img/apple-touch-icon.png">
    <link rel="apple-touch-icon"    sizes="72x72"       href="img/apple-touch-icon-72x72.png">
    <link rel="apple-touch-icon"    sizes="114x114"     href="img/apple-touch-icon-114x114.png">

    <!-- Bootstrap -->
    <link rel="stylesheet" type="text/css"  href="css/bootstrap.css">
    <link rel="stylesheet" type="text/css" href="fonts/font-awesome/css/font-awesome.css">

    <!-- Slider
    ================================================== -->
    <link href="css/owl.carousel.css"   rel="stylesheet" media="screen">
    <link href="css/owl.theme.css"      rel="stylesheet" media="screen">

    <!-- Stylesheet
    ================================================== -->
    <link rel="stylesheet" type="text/css"  href="css/style.css">
    <link rel="stylesheet" type="text/css"  href="css/styles.css">
    <link rel="stylesheet" type="text/css" href="css/responsive.css">

    <link href='http://fonts.googleapis.com/css?family=Lato:100,300,400,700,900,100italic,300italic,400italic,700italic,900italic' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,700,300,600,800,400' rel='stylesheet' type='text/css'>
      <link href="https://gitcdn.github.io/bootstrap-toggle/2.2.0/css/bootstrap-toggle.min.css" rel="stylesheet">
      <script src="https://gitcdn.github.io/bootstrap-toggle/2.2.0/js/bootstrap-toggle.min.js"></script>

    <script type="text/javascript" src="js/modernizr.custom.js"></script>     
    <script type="text/javascript" src="/webiopi.js"></script>
    <script type="text/javascript"> 
   

Declaración del script en javascript principal que será usado para la validación de datos y el envío de datos de forma serial en la Raspberry.

La variable modo indicará si se encuentra en modo Manual o en Coordenadas.
                var modo = 0; // 0 = Modo manual-normal.

La función checkManual() revisa si actualmente se encuentra en modo Manual, regresa un tipo de dato bool.
        function checkManual(){
            var   manual = document.getElementById('manual').checked;
            return manual;
        }

La función checkModo() revisa si actualmente el manejo se encuentra en Manual o Demon del modo Manual.
                function checkModo(){
                                if (modo == 0) {
                                                return true; // Modo normal
                                } else {
                                                return false; // Modo Demon
                                }
                }
La función changeToNormal() cambia el tipo manejo en modo Manual a Normal.
                function changeToNormal(){
                                if (checkManual()) {
                                                modo = 0;
                                }
                }

La función changeToNormal() cambia el tipo manejo en modo Manual a Demon.
                function changeToDemon(){
                                if (checkManual()) {
                                                modo = 1;
                                }
                }

La función verify() revisa si los valores introducidos en modo de búsqueda de coordenadas cumplen con las siguientes características:
§  X<500 y X>-500
§  Y<500 y Y>-500
§  Velocidad>10cm/s y Vel<104 cm/s
                function verify(){
            if (!checkManual()) {
                var   X   = document.getElementById("X").value;
                var   Y   = document.getElementById("Y").value;
                var   vel = document.getElementById("vel").value;
                if        ((X == "") || (Y == "") || (vel == "")){
                     alert("Favor de introducir todos los datos requeridos");
                     return false;
                } else if ( (X > 500) || (X < -500)) {
                     alert("El valor de la coordenada X debe de encontrarse en un rango entre -500 y 500 cm.");
                     return false;
                } else if ( (Y > 500) || (Y < -500)) {
                     alert("El valor de la coordenada Y debe de encontrarse en un rango entre -500 y 500 cm.");
                     return false;
                } else if ( (vel > 104) || (vel < 10) ) {
                     alert("El valor de la velocidad debe de ser estar en un rango de 10 a 104 cm/s.");
                     return false;
                } else {
                     return true;
               }
            } else {
                alert("Favor de desactivar el modo manual antes de enviar algún dato");
                return false;
            }
        }
       
En esta función se hace la llamada a la aplicación WebIOPi que nos permitirá enviar datos de manera serial al Raspberry, es necesario mencionar que esta parte del código solo funcionará (se verá reflejada) cuando el archivo .html sea cargado al Raspberry, ya que de probarlo en un ordenador portátil no desplegará nada. La razón de esto es que el WebIOPi únicamente se encuentra cargado en la Raspberry.

        webiopi().ready(function() {

Acción de presionar la flecha superior con su validación de entrada.
            $("#up").mousedown(function(event){
                                if (checkManual()) {
                                                webiopi().Serial("serial0").write("2");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n")
                                                if (checkModo()) {
                                                                webiopi().Serial("serial0").write("3");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                } else {
                                                                webiopi().Serial("serial0").write("4");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                }
                                                webiopi().Serial("serial0").write("5");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                                webiopi().Serial("serial0").write("10");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n"); 
                                }
            });

Acción de presionar la flecha derecha con su validación de entrada.
            $("#right").mousedown(function(event){
                                if (checkManual()) {
                                                webiopi().Serial("serial0").write("2");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n")
                                                if (checkModo()) {
                                                                webiopi().Serial("serial0").write("3");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                } else {
                                                                webiopi().Serial("serial0").write("4");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                }
                                                webiopi().Serial("serial0").write("6");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                                webiopi().Serial("serial0").write("10");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                }
            });

Acción de presionar la flecha izquierda con su validación de entrada.

            $("#left").mousedown(function(event){
                                if (checkManual()) {
                                                webiopi().Serial("serial0").write("2");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n")
                                                if (checkModo()) {
                                                                webiopi().Serial("serial0").write("3");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                } else {
                                                                webiopi().Serial("serial0").write("4");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                }
                                                webiopi().Serial("serial0").write("7");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                                webiopi().Serial("serial0").write("10");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                }
            });

Acción de presionar la flecha inferior con su validación de entrada.

                    $("#down").mousedown(function(event){
                                if (checkManual()) {
                                                webiopi().Serial("serial0").write("2");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n")
                                                if (checkModo()) {
                                                                webiopi().Serial("serial0").write("3");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                } else {
                                                                webiopi().Serial("serial0").write("4");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                }
                                                webiopi().Serial("serial0").write("8");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                                webiopi().Serial("serial0").write("10");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n"); 
                                }
            });

Acción de presionar el botón de Alto con su validación de entrada.

                    $("#stop").mousedown(function(event){
                                if (checkManual()) {
                                                webiopi().Serial("serial0").write("2");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n")
                                                if (checkModo()) {
                                                                webiopi().Serial("serial0").write("3");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                } else {
                                                                webiopi().Serial("serial0").write("4");
                                                                webiopi().Serial("serial0").write("\r");
                                                webiopi().Serial("serial0").write("\n");
                                                }
                                                webiopi().Serial("serial0").write("9");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                                webiopi().Serial("serial0").write("10");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n"); 
                                }
            });

Acción de presionar el botón de modo Normal con su validación de entrada.

            $("#normal").mousedown(function(event){
                                changeToNormal();
            });

                    $("#demon").mousedown(function(event){
                                changeToDemon();
            });

Acción de presionar el botón de Enviar comando con las coordenadas requeridas y con su validación de entrada.

            $("#command").mousedown(function(event){
                var X   = $('#X').val();
                var Y   = $('#Y').val();
                var vel = $('#vel').val();
                                if (verify()){
                                                webiopi().Serial("serial0").write("1");
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                webiopi().Serial("serial0").write(X);
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                webiopi().Serial("serial0").write(Y);
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");
                                webiopi().Serial("serial0").write(vel);
                                                webiopi().Serial("serial0").write("\r");
                                webiopi().Serial("serial0").write("\n");      
                }
                return false;
            }); 

            $("#inputText").keyup(function(event){
                if(event.keyCode == 13){
                    sendData();
                }
            });
           
            $.get("/devices/*", function(data) {
                var devices = $("#devices");
                var added = false;
                for (i in data) {
                    if (data[i].type=="Serial") {
                        added = true;
                        devices.append($("<option>" + data[i].name + "</option>"))
                    }
                }
                if (added) {
                    readData();
                }
            });
        });

Función para leer información externa a las Raspberry.
        function readData() {
            webiopi().Serial($("#devices").val()).read(function(data) {
                if (data.length > 0) {
                    var d = $("#output").text() + data;
                    $("#output").text(d);
                }
            });
            setTimeout(readData, 500);
        }

Función para enviar información desde Raspberry.
        function sendData() {
            var data = $("#inputText").val() + "\n";
            webiopi().Serial($("#devices").val()).write(data);
            $("#inputText").val("");
        }

Indica el estado del dispositivo.
        function deviceChanged() {
            $("#output").text("");
        }
    </script>

Cuerpo.

En el cuerpo del archivo HTML se hace la definición de cada sección de la página, barras de navegación, imágenes, texto y efectos de diseño. En caso de tener alguna duda acerca de la sintaxis de esta sección se recomienda visitar las siguientes ligas y revisar la sección de Referencia o de Tutoriales.



Enseguida se muestran algunas capturas de la página web funcionando: