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.
Blog creado para describir el proceso de creación de un UAV teledirigido basado en plataformas .NET.
martes, 26 de abril de 2011
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/
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....
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:
- Micro Netduino, http://www.canakit.es/Netduino/Netduino.html
- Kit XBee de comunicacion inhalambrica Wifi, http://www.canakit.es/Arduino/Xbee-Kit-Inalambrico.html
- IMU de 6 grados de libertad, http://www.bricogeek.com/shop/medicion-inercial-imu/181-sensor-ardupilot-6-dof.html
- Componentes varios y utilleria... http://www.bricogeek.com/
- 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.
martes, 4 de enero de 2011
Fase de Investigación previa III
Una vez seleccionada la plataforma hardware y el propio vehiculo UAV, pasamos a la parte de sensores. Como primera fase dentro del proyecto he marcado el alcance en conseguir trasmitir, a traves de telemetria mediante Wifi, toda la informacion sobre la posicion, velocidad y estado del aeromodelo. Para ello emplearé:
- 3 Giroscopos, ejes X,Y,Z
- 3 Acelerometros, ejes X,Y,Z
- Posicionamiento y velocidad a traves de GPS
- Modulo de envio de informacion a traves de Wifi
- Modulo de recepcion de informacion.
- Modulo de aceso al receptor de RC, para determinar si el control del aeromodelo se realiza de forma manual a traves del equipo de radio control, o controlado por el micro de UAV.
Suscribirse a:
Entradas (Atom)