LusoRobótica - Robótica em Português
Software => C# => Tópico iniciado por: ivitro em 14 de Maio de 2015, 11:27
-
Olá a todos,
Estou a fazer um projeto pessoal que consiste em receber dados da porta serie para fazer um gráfico.
Os meus requisitos são:
- Os dados da porta série recebidos têm que vir em csv
- Desenhar o gráfico com os dados e o tempo em que foram recebido
- Mostrar os dados que estão a ser recebidos numa caixa de texto
- Poder enviar informação também pela porta série
A ideia é ter mais ou menos aquilo que está na imagem em anexo.
Neste momento já tenho os dados a serem impressos numa caixa de texto mas ainda não consegui desenhar no gráfico.
Deixo o que tá feito do projeto no seguinte link https://www.dropbox.com/sh/t39pctffom6b4z9/AADihedKxFOOcvUthHE94gAaa?dl=0 (https://www.dropbox.com/sh/t39pctffom6b4z9/AADihedKxFOOcvUthHE94gAaa?dl=0)
O código principal é este:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Windows.Forms.DataVisualization.Charting;
namespace serial_rx_tx_opt_chart
{
public partial class Form1 : Form
{
//delegate void SetTextCallback(string indata);
//delegate void SetTextCallback( );
double t = 0;
public string indata;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;//evita error de sobrecarga
chart1.Titles.Add("Informação Gráfica");
//preenchimento da combobox da velocidade
cboBaudRate.Items.Add(300);
cboBaudRate.Items.Add(600);
cboBaudRate.Items.Add(1200);
cboBaudRate.Items.Add(2400);
cboBaudRate.Items.Add(9600);
cboBaudRate.Items.Add(14400);
cboBaudRate.Items.Add(19200);
cboBaudRate.Items.Add(38400);
cboBaudRate.Items.Add(57600);
cboBaudRate.Items.Add(115200);
//preenchimento da combobox da data bits
cbDatabits.Items.Add(7);
cbDatabits.Items.Add(8);
//preenchimento da combobox paraidade
foreach (string s in Enum.GetNames(typeof(Parity)))
{
cbParity.Items.Add(s);
}
//preenchimento da combobox de controlo
foreach (string s in Enum.GetNames(typeof(Handshake)))
{
cbHandshake.Items.Add(s);
}
foreach (string s in Enum.GetNames(typeof(StopBits)))
{
cbStopbit.Items.Add(s);
}
string[] ArrayComPortsNames = SerialPort.GetPortNames();
if (!(ArrayComPortsNames.Length == 0))
{
// Display each port name to the console.
foreach (string port in ArrayComPortsNames)
{
cboPorts.Items.Add(port);
}
}
}
private void bConnect_Click(object sender, EventArgs e)
{
if (bConnect.Text == "Ligar")
{
try
{
// Allow the user to set the appropriate properties.
ComPort.PortName = cboPorts.SelectedItem.ToString();
ComPort.BaudRate = int.Parse(cboBaudRate.SelectedItem.ToString());
ComPort.Parity = (Parity)Enum.Parse(typeof(Parity), cbParity.SelectedItem.ToString());
ComPort.DataBits = int.Parse(cbDatabits.SelectedItem.ToString());
ComPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), cbStopbit.SelectedItem.ToString());
ComPort.Handshake = (Handshake)Enum.Parse(typeof(Handshake), cbHandshake.SelectedItem.ToString());
ComPort.ReadTimeout = 500;
ComPort.WriteTimeout = 500;
ComPort.Open();
bConnect.Text = "Desligar";
}
catch{
}
}
else {
try
{
ComPort.Close();
bConnect.Text = "Ligar";
}
catch { }
}
}
private void btRxClear_Click(object sender, EventArgs e)
{
tbRx.Text = "";
}
private void btTxSend_Click(object sender, EventArgs e)
{
if(ComPort.IsOpen){
ComPort.WriteLine(tbTx.Text);
tbTx.Text = "";
}
}
Boolean i = false;
private void ComPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//inicia el timer1 para que sea cero cuando se recibe el primer dato
if (i == false)
{
t = 0;
i = true;
}
indata = ComPort.ReadExisting();
chart1.Series[0].Points.AddXY(t, Math.Sin(t));
}
public void SetText(object sender, EventArgs e)
{
tbRx.AppendText(indata);
}
private void timer1_Tick(object sender, EventArgs e)
{
t = t + 0.1;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (ComPort.IsOpen) ComPort.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
}
}
Desde já obrigado pela ajuda.
-
Eu diria que a seguir a adicionares os dados ao gráfico deve existir uma função para redesenhar o gráfico, começa por tentar desenhar um gráfico com dados estáticos.
-
Segundo outra aplicação em que me baseio ao adicionar dados à série ele faz a atualização do gráfico sozinho.
Agora na outra aplicação está a funcionar, na minha não mostra as linhas do gráfico.
os dados estão a ser enviados de 1 em 1 ms.
-
Segundo outra aplicação em que me baseio ao adicionar dados à série ele faz a atualização do gráfico sozinho.
Agora na outra aplicação está a funcionar, na minha não mostra as linhas do gráfico.
os dados estão a ser enviados de 1 em 1 ms.
Tenta criar uma aplicacao em que apenas mostras um grafico.
-
Olha vê esta aqui:
https://www.dropbox.com/sh/t1e3ng7tcps28zt/AACOKyI1_GdkheOFxaXwwuCwa?dl=0 (https://www.dropbox.com/sh/t1e3ng7tcps28zt/AACOKyI1_GdkheOFxaXwwuCwa?dl=0)
-
Queres que veja o que?
-
Esse é o código de só apresentar o gráfico.
Se quiseres testar. ;)
-
Tu ja testaste?
-
Sim, claro...
E funciona... faz o gráfico que é o que interessa.
Mas na aplicação que eu quero que funcione não está a dar.
-
Pode ser tanta coisa....
Ou não lhe estão a chegar dados, estão a ser mal interpretados, tens um erro na parte do gráfico.
Dai o metro dizer, mete dados estáticos e vê se dá!
-
Já consegui resolver parte do problema.
Mas queria saber como faço o gráfico ter uma janela de tempo fixa.
Neste momento ao desenhar o gráfico ele vai acrescentando pontos infinitamente, queria que ele só tivesse o últimos 10 segundos de histórico.
-
Adicionas o "ultimo" ponto e apagas o primeiro.
Não faço ideia como funciona essa função do gráfico, mas basicamente podes usar um buffer circular e fazes só o plot desse gráfico.
-
Então crio o buffer e depois faço o update do gráfico de x em x tempo.
-
Boas,
O gráfico já funciona e desliza tal como eu queria.
Agora quanto à prestação da aplicação queria saber a vossa opinião sobre a periocidade de envio dos dados.
Ao enviar dados em intervalos de 1ms a aplicação chega a um ponto e deixa de funcionar bem (julgo que me falta qualquer coisa sobre libertação de memoria).
Mas o quero mesmo saber é que intervalo de tempo acham admissível para enviar dados?
PS: não vale dizer que depende da aplicação, preciso de um valor aceitável e que funcione bem em grande parte do casos.
-
Lol... Como é óbvio, depende da aplicação :) . 1ms parece-me mesmo muito muito muito frequente, só que eu não sei qual é a tua aplicação, pode justificar-se.
Libertação de memória? O C# não tem garbage colector?
-
Se estiver sempre a alocar memória e mantiver tudo no plot provavelmente o C# não vai lá chegar e tirar pontos do gráfico.
-
Lol... Como é óbvio, depende da aplicação :) . 1ms parece-me mesmo muito muito muito frequente, só que eu não sei qual é a tua aplicação, pode justificar-se.
Libertação de memória? O C# não tem garbage colector?
Então achas que se meter 1ms tá fixe? aplicação neste momento não há. A ideia é ter isto como um pequena ferramenta de trabalho... à pouco tempo fiz o controlo de um motor e senti a necessidade de ter algo que me fizesse um gráfico para optimizar o controlador.
Isso da libertação de memoria terei que ver não faço ideia só com mais testes.
Se estiver sempre a alocar memória e mantiver tudo no plot provavelmente o C# não vai lá chegar e tirar pontos do gráfico.
O gráfico tá a deslizar e não tem scroll bar horizontal por isso penso que não fique lá nada.
-
Então achas que se meter 1ms tá fixe? aplicação neste momento não há. A ideia é ter isto como um pequena ferramenta de trabalho... à pouco tempo fiz o controlo de um motor e senti a necessidade de ter algo que me fizesse um gráfico para optimizar o controlador.
Não sei se tá fixe, depende da aplicação. Para um gráfico com display em tempo real parece-me demasiado, 1ms são 1000 pixeis por segundo, um "ecran" inteiro por segundo, isso parece-me demasiado rápido para se ter tempo de tirar muita informação relevante visualmente. Se for para logar e ver depois (que é se calhar o que tu queres no caso do motor) não estranho o valor de 1ms. Também podes logar a 1ms e mostrar no gráfico apenas 1 em 100 amostras. Mas dizer que a aplicação é um gráfico para optimizar um controlador continua a ser muito vago. Tem que se usar a frequência de amostragem que capture aquilo que se quer ver; se for temperatura se calhar bastam 2Hz, se for corrente no motor se calhar 20Hz, se for as quedas de tensão nos condensadores se calhar 5MHz...