martes, 26 de abril de 2011

Siguientes pasos en el software de navegación

Tras otro largo período de inactividad vuelvo a la carga. Esta vez antes de probar el sistema de navegación en el avión lo montaré en un coche teledirigido que me permitirá ahorrar en accidentes. Para ello mi hermano  me ha prestado un cacharro que teníamos por casa al cual  he realizado algunas modificaciones para que entrase todo el equipo del netduino y compañía. En el siguiente post adjuntare algunas fotos.

domingo, 20 de febrero de 2011

Comunicación establecida!!!

Despues de un buen dia de programación... he conseguido comunicar el PC con el Netduino a traves del XBEE. La solución se compone de 5 proyectos, un cliente Windows, un cliente NetDuino, una libreria de acceso al modulo XBee que es compartida por 2 proyecto uno plataforma .NET 4.0 y otro MicroNET 4.1 y por ultimo una libreria comun con las trazas de comunicación entre ambas plataformas.

El proyecto NetDuino es sencillo:

    public class Program
    {
        private static OutputPort OnboardLED;
        private static XBEE _comm;

        public static void Main()
        {
            OnboardLED = new OutputPort(Pins.ONBOARD_LED, initialState: false);
            _comm = new XBEE("COM1");
            _comm.OnReciveData += new ReciveDataDelegate(_comm_OnReciveData);
           
            Thread.Sleep(Timeout.Infinite);
        }

        static void _comm_OnReciveData(CommunicationData data)
        {
            TestData _data = ((TestData)data);
            OnboardLED.Write(_data.BoolData);
            _comm.Write(new TestData(_data.BoolData));
        }
    }


El proyecto instancia la clase XBee y establece el delegado de lectura de datos. Con la lectura de datos se procede a enceder/apagar la luz de la placa y reenvia el mensaje al PC.

El proyecto de PC sigue la misma linea que el de NetDuino:

        XBEE _xbee;
        public frmPpal()
        {
            InitializeComponent();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            _xbee = new XBEE(cmbPorts.SelectedItem.ToString());
            _xbee.OnReciveData += new ReciveDataDelegate(_xbee_OnReciveData);
        }

        void _xbee_OnReciveData(CommunicationData data)
        {
            this.rtbLog.Invoke(new MethodInvoker(delegate() { this.rtbLog.Text += data.ToString() + Environment.NewLine; }));           
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            _xbee.Write(new TestData(rdbOn.Checked));
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cmbPorts.Items.AddRange(SerialPort.GetPortNames());
        }

        private void btnClearAll_Click(object sender, EventArgs e)
        {
            this.rtbLog.Clear();
        }


En este caso el proyecto instancia la clase XBee y establece el delagado de escucha. A traves de un boton y 2 radiobuttons se permite el envio de mensajes desde el PC a NetDuino.

La clase de XBee es la mas compleja:

        #region Members
        private readonly SerialPort _xbee;
        private int indexSentence = 0;
        private byte[] tempSentence = new byte[200];
        #endregion

        #region Construcctor
        public XBEE(string port)
        {
            _xbee = new SerialPort(port, 9600, Parity.None, 8, StopBits.One);
            if (_xbee.IsOpen)
                _xbee.Close();
            _xbee.Open();
            _xbee.DataReceived += new SerialDataReceivedEventHandler(_xbee_DataReceived);
        }
        #endregion

        #region Internal Methods
        void _xbee_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int numc = 0;
            byte data;
            numc = _xbee.BytesToRead;

            if (numc > 0)
            {
                for (int i = 0; i < numc; i++)
                { // Process bytes received
                    data = (byte)_xbee.ReadByte();
                    tempSentence[indexSentence] = data;
                    indexSentence++;

                    if (TestData.IsSecuenceComplete(tempSentence))
                    {
                        string tempData = new string(Encoding.UTF8.GetChars(tempSentence));
                        OnReciveData(TestData.TryParse(tempData));
                        indexSentence = 0;
                        tempSentence = new byte[200];
                        continue;
                    }
                }
            }
        }
        #endregion

        #region Public Methods
        public void Write(CommunicationData data)
        {
            byte[] _data = Encoding.UTF8.GetBytes(data.ToString());
            _xbee.Write(_data, 0, _data.Length);
        }
        #endregion

        #region Public Events
        public event ReciveDataDelegate OnReciveData;
        #endregion

        #region IDisposable
        public void Dispose()
        {
            _xbee.Close();
            _xbee.Dispose();
        }
        #endregion


Esta clase es la encargada de abrir el puerto con la configuracion preestablecida. La clase se encarga de realizar los envios y recepciones de datos. Los envios no tienen nada en particular, pero si la recepción en la cual hay que escuchar hasta que la trama que se recibe es la correcta. Para ello no es posible leer toda la informacion que existe en el buffer del puerto de golpe sino que hay que leer byte a byte y analizar la informacion existente para determinar si es una trama valida.

La ultima clase es la que define la trama a comunicar. Para ello he definido una clase abstracta de la que deriven el resto de tramas:

        #region Members
        public static byte ByteStartDelimiter = 33;
        public static byte ByteFinishDelimiter = 63;
        public static byte ParameterDelimiter = 15;
        private string version = "1.0.0";
        #endregion

        #region Properties
        public string Version
        {
            get { return version; }
            set { version = value; }
        }
        #endregion

        #region Overrided Methods
        public abstract override string ToString();
        #endregion

        #region Static Methods
        public static TestData TryParse(string sentence) { return null; }
        public static string RemoveDelimiters(string sentence)
        {
            string res = sentence;
            int inicio = res.LastIndexOf((char)TestData.ByteStartDelimiter) + 1;
            int fin = res.LastIndexOf((char)TestData.ByteFinishDelimiter) - 1;

            res = sentence.Substring(inicio, fin);
            return res;
        }
        public static bool IsSecuenceComplete(byte[] tempData)
        {
            bool res = false;
            int index = 0;
            while (!res && index < tempData.Length)
            {
                if (tempData[index] == TestData.ByteStartDelimiter)
                {
                    while (!res && index < tempData.Length)
                    {
                        if (tempData[index] == TestData.ByteFinishDelimiter)
                        {
                            res = true;
                            break;
                        }
                        else
                            index++;
                    }
                    break;
                }
                else
                    index++;
            }
            return res;
        }
        #endregion


Esta clase da acceso a los metodos basicos de definicion de tramas. Como metodos importantes destacar la implementacion obligatoria del metodo ToString que sera el encargado de serializar los datos a enviar por la linea y el metodo TryParse que sera el que encargado de realizar la conversion desde un string a la clase correspondiente.

La implementacion de la trama  de prueba es la siguiente:

        #region Construcctor
        public TestData() { }
        public TestData(bool data)
        {
            this.booldata = data;
        }
        #endregion

        #region Members
        private bool booldata=false;
        #endregion

        #region Properties
        public bool BoolData
        {
            get { return booldata; }
            set { booldata = value; }
        }
        #endregion

        #region Overrided Methods
        public override string ToString()
        {
            string res = string.Empty;
            res += (char)TestData.ByteStartDelimiter;
            res += booldata ? "ON" : "OFF";
            res += (char)TestData.ByteFinishDelimiter;
            return res;
        }
        #endregion

        #region Static Methods
        public new static TestData TryParse(string sentence)
        {
            TestData res = new TestData();
            sentence = sentence.Trim();
            sentence=RemoveDelimiters(sentence);
            if (sentence == "ON")
                res.BoolData = true;
            else
                res.BoolData = false;
            return res;
        }
        #endregion


Para los que querais acceder al codigo fuente lo teneis disponible en codeplex : http://netuav.codeplex.com/

Vuelta a la carga

Despues de unas semana de trabajo intenso, vuelo a la carga con el proyecto, pero despues del frenazo anterior al no poder enviar/recibir informacion a traves de los modulos de XBEE, he decidido crear un proyeto de test para poder establecer esta comunicacion.

sábado, 29 de enero de 2011

No me chilles que no te veo ....

Pues eso... de momento no hay forma de comunicar el Netduino con mi laptop.... La adquisicion de informacion desde el 6DOF es correcta, podeis ver el codigo aqui, pero a la hora de enviar los datos a traves del modulo de XBEE ... de momento no me es posible lograr la comunicacion correcta :(

lunes, 17 de enero de 2011

Fase 0: Trasmision de datos desde NetDuino a PC con XBEE

Como fase inicial del desarrollo me propongo poder enviar informacion de telemetria desde el avión a tierra empleando la adquisicion de datos de NetDuino y enviandolos a traves del modulo Xbee.
Para ello como primer punto del desarrollo sera implementar la capacidad de envio de datos desde NetDuino a Xbee. En siguientes entradas ire comentando el codigo....

viernes, 14 de enero de 2011

Cambio en el IMU.... error en la primera eleccion

Tras cacharrear e investigar un poco los sensores IMU de 6DOF no me valen para este proyecto, ya que unicamente dispone de sensores para 4 grados de libertad (que se pueden complementar en 2 grados más), 3 acelerometros y un giroscopo. Con lo que tras analizar un poco los componentes existentes me he decantado por emplear este IMU.

miércoles, 5 de enero de 2011

Lista de la compra

Bueno, pues con toda esta informacion ya he preparado la lista de la compra para comenzar con el montaje de la parte hardware del UAV:
  1. Micro Netduino, http://www.canakit.es/Netduino/Netduino.html
  2. Kit XBee de comunicacion inhalambrica Wifi,  http://www.canakit.es/Arduino/Xbee-Kit-Inalambrico.html
  3. IMU de 6 grados de libertad, http://www.bricogeek.com/shop/medicion-inercial-imu/181-sensor-ardupilot-6-dof.html
  4. Componentes varios y utilleria...  http://www.bricogeek.com/
  5. Multiplexor 74157 para multiplexar la señal de RC y del UAV a traves de hardware en vez de software para evitar posibles delay en la señal de RC.
Tengo pendiente adquirir el GPS y no se si el IMU 6DOF me servira para mi proposito, creo que necesitare un sistema AHRS como este http://www.sparkfun.com/products/9623. La diferencia entre el IMU y un AHRS es que el IMU unicamente son una serie de sensores que devuelven valores que ha de interpretarse y un sistema AHRS aisla de la complejidad de la interpretacion de los sensores ya que el propio circuito dispone de un microprocesador que realiza dicha tarea y unicamente devuelve roll, pitch, yaw y heading. Generalmente los IMU proporcionan una serie de puertos analogicos en los cuales podemos consultar los valores de los sensores, por otra parte los sistemas AHRS emprean una comunicacion Serie donde se devuelve un array de datos. Lo que tengo que comprobar es que despues de conectar el sensor GPS y el XBee Wifi es posible conectar un AHRS.