Serial read

Lihtelf
Offline
Зарегистрирован: 24.12.2012

Пытаюсь передать инфу с ардуино, ничего не получается(((
В конце концов начал посылать с ардуино "123" ,  но все равно процессинг выдает другие числа, причем не рандомно а с особой последовательностью

Processing:

import processing.serial.*;
Serial myPort;  // Create object from Serial class
int val;      // Data received from the serial port

void setup() 
{
  String portName = Serial.list()[0];
  myPort = new Serial(this, "COM3", 9600);
}

void draw()
{
  val = myPort.read();  
  println(val);
}

 

 

 
 
 
 
 
 
 
 
 
 
Display 0 does not exist, using the default display instead.
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
-1
-1
0
0
0
0
0
0
0
0
0
0
0
49
242
-1
-1
-1
-1
-1
-1
-1
-1
-1
165
17
144
138
88
90
12
74
196
165
17
144
138
88
90
12
74
196
165
17
144
138
88
90
12
74
196
165
17
144
138
88
90
12
74
196
165
17
144
138
88
90
12
74
196
165
17
144
138
 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Serial::available() \ Language (API) \ Processing 2+

>В конце концов начал посылать с ардуино "123"

Не предполагайте телепатов. Как показывает опыт это можно сделать десятками неправильных способов.

P.S. Логи тоже можно вставлять как код.

Lihtelf
Offline
Зарегистрирован: 24.12.2012

Arduino


void setup() {
  // initialize serial:
  Serial.begin(9600);

}

void loop() {

    Serial.println(1232); 
    delay (1000);
 
}

Processing

import processing.serial.*;
Serial myPort; 

void setup() 
{
  myPort = new Serial(this, "COM3", 9600);
}

void draw()
{
  while (myPort.available() >0) {
    int inByte = myPort.read();
    println(inByte);
  }

 

LOG

Display 0 does not exist, using the default display instead.
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
49
50
51
50
13
10
49
50
51
50
13
10

Windows 8, arduino ide 1.5.2, processing 1.5.1

leshak
Offline
Зарегистрирован: 29.09.2011

Ну вот, так гораздо лучше :) Теперь хоть что-то осмысленное можно сказать ;)

Вначале нужно понять "в чем проблема", а потом уже будем думать "что с этим делать".

Проблема в следующем:
Кратко: из ардуины вы шлете ТЕКСТОВУЮ СТРОКУ, а читаете как бинарный поток.

Подробней: ардуина и комп между собой могу обмениватся данными. весь обмен данных состоит из байтов. А вот какой смысл вкладывается в этим байты - решают передающай и принимающий скетч/программа. Один из наиболее распространенных "смыслов" - это когда каждый байт означает "код символа". Номер значка в шрифте который можно нарисовать на экране. Соотвествие кодов и символов можно посмотреть, к примеру тат http://www.asciitable.com/

Терминальный программы (и ардуиновский Serial Monitor в частности) именно такой "смысл" и вкладывают в байты. Например если из Serial пришел байт со значением 65, то он нарисует на экране букву 'A'.  Когда вы в коде пишите Serial.print("ABC"); то ардуина шлет три байта: 65,66,67, а уж сериал монитор выводить их именно как буквы.  (и сериал монтор, к сожалению, умеют только так интерпретировать/показывать входящую информацию. показать именно "занчение байтов" - он не умеет. нужно другие программы для этого брать).

Теперь смотри что шлеты вы. Serial.println(1232); Что он делает?  Для начала преобразую ваше число в строку. Из 1232 сделает "1232". То есть строку состоящуюи из СИМВОЛОВ '1','2','3','2' . А коды этих символов (см. табличку по ссылке) - 49,50,51,50
После чего, так как вы использовали println, а не print - добавить к ним еще два "спец символа", с кодами 13 (возврат каретки) и 10 (перевод строки). Итого ардуина "выплюнет" следующую серию байтов
49,50,51,50,13,10

Упс. Правда похоже на числа которые у вас были? А все потому что Serial.read читает именно цифровое значение байта. Ничего не зная код символа это или что-то другое. Что потом делать с этим значением - это уже ваша забота. Например вы можете отнять от полученных символов 48 (это код нуля) и получите числовые значения 1,2,3,4, а потом "собрать" их в одно число. 1*1000+2*100+3*10+4=1234. Вообщем занятся конвертацией строки в int. (почитайте доку, 99% что у процессинга уже есть готовая функция для подобного. как нибудь parseInt или int.Parse будет называтся).

Вообщем "шо делать?".  Тут сильно зависит от того что вы потом собираетесь делать с этими принятыми числами. Просто "выводить пользователю" или "использовать для каких-то вычислений".

Вы должны решить, в каком виде будут общатся между собой Arduino и Processing. В текстовом (что-бы вам удобно было читать в Serial мониторе) или в бинарном (компьютерном языке).
Если вы выбираете текстовое решение - то в процессинге вам нужно читать именно строки, потом конвертировать их числовые занчение, потом делать с ними какие-то вычисление. Все данные будут идти по цепочке число->строка->передача на комп->чтение строки->парсинг в число.
Если вы во главу угла ставите "удобство программы" - можно выбросить промежуточный "человекочитаемый" вариант (в Serial мониторе все будет выглядить как кракозяблы).

Простейшей реализацией "бинарного протокола" будет если вы на ардуине будете делать не Serial.print, а Serial.write. write - не делает никаких конвертаций в строку. Если вы написали Serial.print(5); - то он пошет КОД СИМВОЛА ПЯТЕРКА, то биш 53. А Serial.write(5) пошелт байт со значением 5-ть. И Serial.read() на процессинге вычитает именно 5-ть. Вообщем что послали - то и получили. Никаких промежуточныйх конвертаций.

Но... одно но. write/read оперируют одним байтом за раз. То есть Serial.write(245) вы можете послать. А Serial.write(300) - уже нет. Не влазит число в байт.... но это уже другая история. Вначале попруйбет с малыми числами (от 0 до  255).

Lihtelf
Offline
Зарегистрирован: 24.12.2012

Большое спасибо!) Теперь я понимаю как это работает) 

Но вместе с этим у меня возникает новый вопрос.

Почему все работает иначе на этом видео http://youtu.be/1TvNU2vxX2Q

leshak
Offline
Зарегистрирован: 29.09.2011

А с чего вы взяли что "работает иначе"?  Все ровно как я и описывал. ЧИТАЮТ СТРОКУ, потом конвертят ее в число

Цитата:

Вы должны решить, в каком виде будут общатся между собой Arduino и Processing. В текстовом (что-бы вам удобно было читать в Serial мониторе) или в бинарном (компьютерном языке).

Они решили "в текстовом виде гонять данные".

Важно что-бы и отправлялось и читалось в однаковом формате. Тогда будет работает. Они шлют в виде строк и читают в виде строк. Поэтому у них работает.
А вы слали строки, а читали как бинарные байты.

Поэтому у вас есть два варианта - либо начинать слать тоже бинарно (замена print на write), либо меня на стороне компа - начинать читать строки (как они делали).

Вообщем приемник и предатчик должны говорить на одном языке. У вас - разнобой. Кого менять что-бы "языки совпали" - сторону ардуины или сторону процессинга - вам решать.

Lihtelf
Offline
Зарегистрирован: 24.12.2012

Насколько я помню, пробовал сделать как у них и результат был тот же, в любом случае попробую еще. А в чем именно различие их приема инфы от( строчного) от того как у меня(бинарного)?

 

leshak
Offline
Зарегистрирован: 29.09.2011

В том что в одному случае поступающие из serial значения интерпретируются как байты-значения, отдельные, а во втором вычитывается сразу множество байтов (у них - пока не попадется символ новой строки) и интепретируются как коды символов.

Вообщем представте, кто-то позвонил вам и сказал: "48,49,50"

Вы записали все эти три числа, но не знаете связаны они между собой и что вообще означают.

А теперь вам сказали, что "сейчас тебе позвонят и продиктуют шифрограмму. расшифруешь ее с помощью asci таблицы" то что получится - это какое-то число.

Вам звонят и диктуют  "48,49,50,конец связи". Вы берете таблицу и переводите в символы, у вас выходит строка "123". Теперь вы берете кого-нибудь грамотного, кто умеет читать и спрашивает "что тут написанно?", он вам говорит "число 123".

Это как работает "текстовый вариант".

Бинарный: вам говорят, счас принесут бандерольку (один байт). в ней будут камушки. сколько камушков - это и есть код от сейфа. Тут в окно влетает коробка. Вы заглядываете в нее - видите 123 камушка. Ну и все. Вы знаете сразу "ЧИСЛО".

Lihtelf
Offline
Зарегистрирован: 24.12.2012

Большое спасибо))) Разобрался, все работает)

trium1983
Offline
Зарегистрирован: 16.04.2013

Ребят подскажите плис! Принимаю информация в таком виде:
(Отправлена при помощи Serial.print с контроллера)
28EFEDA803000074 Temp C: 25.00
285C1CA9030000CE Temp C: 25.00
28EFEDA803000074 Temp C: 25.00
285C1CA9030000CE Temp C: 25.00
с помощью processing:
while (myPort.available() > 0) {
myString = myPort.readStringUntil(lf);
if (myString != null) {
println(myString);
Теперь вопрос. Мне необходимо вывести на экран значение Temp C: 25.00 для устройства 28EFEDA803000074.
Как это сделать? т.е. мне необходимо вывести string значение для строки, начинающейся на 28EFEDA803000074.
Если прописать:
text(myString); то выводится все подряд т.е., как я понял, необходимо в text задать какоето условие....
В программировании я начинающий, так что вопрос может и глупый...

step962
Offline
Зарегистрирован: 23.05.2011

Для первого датчика что-то вроде:

if(strstr(myString,"28EFEDA803000074")!=NULL) {p=strstr(myString,"Temp C:"); println(p);}

Для второго - аналогично.

О функции strstr читаем, например, здесь.

trium1983
Offline
Зарегистрирован: 16.04.2013

Матюгается на 

if (strstr(myString,"28EFEDA803000074")!=NULL) 

Говорит - The function strstr(String, String) does not exist. Короче не поддерживается...:(

step962
Offline
Зарегистрирован: 23.05.2011

так это непосредственно processing? Ака жаба?

Ну, тогда попробуйте

if(myString.indexOf("28EFEDA803000074")>=0)  {
...
}

Подробнее читать здесь.

trium1983
Offline
Зарегистрирован: 16.04.2013

Процессинг...

Теперь он пишет NullPointerException

trium1983
Offline
Зарегистрирован: 16.04.2013

Уже близко.....выдает какую-то ерунду:

 

28EFEDA803000074 Temp C: 28.0 C: 28.00
28EFEDA803000074 Tem 28.00
28EFEDA803000074 Temp Cemp C: 28.00
28EFEDA803000074  C: 28.00
 
Отрывок кода:
while (myPort.available() > 0) {
   String myString = myPort.readString(); 
    if(myString.indexOf("28EFEDA803000074")>=0){
    print(myString); 
    }

Щас мозг закипит....

 
trium1983
Offline
Зарегистрирован: 16.04.2013

C этим кое-как справился. Появился другой вопрос.

Как убрать из строки вот это 28EFEDA803000074?

step962
Offline
Зарегистрирован: 23.05.2011

trium1983 пишет:

C этим кое-как справился. Появился другой вопрос.

Как убрать из строки вот это 28EFEDA803000074?

Вывод подстроки начиная с "Temp" (соответственно, без "28EFEDA803000074"):

while (myPort.available() > 0) {
   String myString = myPort.readString(); 
    if(myString.indexOf("28EFEDA803000074")>=0){
    print(myString.substring(myString.indexOf("Temp"))); 
    }

Позволю себе самоцитирование:

step962 пишет:

Подробнее читать здесь.

trium1983
Offline
Зарегистрирован: 16.04.2013

Огромное спасибо!!! Все заработало так, как и должно работать!

trium1983
Offline
Зарегистрирован: 16.04.2013

Еще один глупый вопрос, если не побьете.

Как теперь всю эту канитель в integer преобразовать? 

step962
Offline
Зарегистрирован: 23.05.2011
int Val;
...
Val = Integer.parseInt(s);

где s - подстрока, содержащая цифири.

Опять же, подробнее - тут (в Интернете).

trium1983
Offline
Зарегистрирован: 16.04.2013

Да я в программировании туп как пробка! Мой стаж программирования составляет неделю, поэтому для меня 

описание в интернете не о чем, мне нужен конкретный пример, только так что то становится понятно.

trium1983
Offline
Зарегистрирован: 16.04.2013

Короче что то я ни так делаю.....


val = Integer.parseInt(inString.substring(inString.indexOf("Temp C:")));

Результат: 

error, disabling serialEvent() for //./COM4
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at processing.serial.Serial.serialEvent(Serial.java:287)
	at gnu.io.RXTXPort.sendEvent(RXTXPort.java:732)
	at gnu.io.RXTXPort.eventLoop(Native Method)
	at gnu.io.RXTXPort$MonitorThread.run(RXTXPort.java:1575)
Caused by: java.lang.NumberFormatException: For input string: ": 26.50
"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
	at java.lang.Integer.parseInt(Integer.java:449)
	at java.lang.Integer.<init>(Integer.java:660)
	at sketch_130422a.serialEvent(sketch_130422a.java:46)
	... 8 more

Пробовал даже так:


val=new Integer(inString.substring(inString.indexOf("Temp C:")));

Результат тот же....

 

step962
Offline
Зарегистрирован: 23.05.2011

indexOf() - если прочитать описание по приведенной мной ссылке - возвращает позицию первого символа искомой подстроки, то есть в вашем случае позицию символа 'T'. А вам надо знать позицию первой цифры.

Которая стоит где?

Правильно - вслед за двоеточием и пробелом. То есть на 7 символов (длина строки "Temp C:") дальше уже упомянутого 'T'.

Теперь - в качестве упражнения - попробуйте догадаться, как нужно изменить вышеприведенный оператор. Знаний в программировании здесь в общем-то не требуется - простой арифметики достаточно.

trium1983
Offline
Зарегистрирован: 16.04.2013

Блин, дак как указать..., ... можно было так " " но в строке дво пробела т.е. это равносильно что " Temp C:"

"Temp C:"  +7 ?

 

Даже 3 пробела..

Добрался до цифр:

val = Integer.parseInt(inString.substring(inString.indexOf("", 25)));

Ошибка выскакивает та-же...

step962
Offline
Зарегистрирован: 23.05.2011

trium1983 пишет:

Блин, дак как указать..., ... можно было так " " но в строке дво пробела т.е. это равносильно что " Temp C:"

"Temp C:"  +7 ?

А вот так пробовали:


val = Integer.parseInt(inString.substring(inString.indexOf("Temp C:")+7));

а еще лучше вот так (естественно, с соответствующими объявлениями переменных):

idx =inString.indexOf("Temp C:");
print("idx: "); println(idx);
str = inString.substring(idx+7);
print("str: ["); print(idx); println("]");
val = Integer.parseInt(str);
print("val: "); println(val);

По крайней мере будет видно, из-за чего выскакивает ошибка.

 

trium1983
Offline
Зарегистрирован: 16.04.2013

1. Тоже самое.

2. 

idx=inString.indexOf("Temp C:");
print("idx: ");println(idx);
str = inString.substring(idx+7);
print("str: ["); print(idx); println("]");
//val = Integer.parseInt(str);
//print("val: "); println(val);

В таком виде бежит что то вроде:

 

idx: 17
str: [17]
 
Как только подключаеш Val - появляется таже самая ошибка....
leshak
Offline
Зарегистрирован: 29.09.2011

Так в строке 4-ре, вы опять выводите переменную idx, а не подстроку которую вы выделили str. Наверное print(str) лучше покажет что же именно вы "выкусили" :)

leshak
Offline
Зарегистрирован: 29.09.2011

 Кстати, еще и 

print("inString: ["); print(inString);println("]");

Можно сделать, что-бы четче видеть что именно мы пытаемся разобрать на части. Может там внутри лежит не то что мы думаем.

leshak
Offline
Зарегистрирован: 29.09.2011

Еще есть подозрение на то что parseInt ожидает разделителем целой/дробной части не точку, а запятую... но это потом проверив. Вначале - выведите inString и str и покажите тут.

trium1983
Offline
Зарегистрирован: 16.04.2013

leshak пишет:

 Кстати, еще и 

print("inString: ["); print(inString);println("]");

Можно сделать, что-бы четче видеть что именно мы пытаемся разобрать на части. Может там внутри лежит не то что мы думаем.

 

 

inString: [28EFEDA803000074 Temp C: 26.00]
 
leshak
Offline
Зарегистрирован: 29.09.2011

А 

print("inString: ["); print(str);println("]");

где вывод?

Мы увидители что именно мы пытаемся разобрать, но не увидели - какой-же именно кусок вы выкусили для кормления parseInt

leshak
Offline
Зарегистрирован: 29.09.2011

>Еще есть подозрение на то что parseInt ожидает разделителем целой/дробной части не точк

Проморгал слона в гостинной. parseInt вообще не ждет что там будут какие-то разделители. Откуда  дробная часть у целого числа?

Если у нас число может быть дробным, то навреное что-то типа parseFloat/parseDouble будет более подходящим. У нас же температура может быть не только целыми числами. И val, тогда тоже должна не Int-том быть, а соотвествующим типом.

trium1983
Offline
Зарегистрирован: 16.04.2013

Ребят огромное Вам спасибо!!! Все заработало в лучшем виде!!!

val = parseFloat(inString.substring(inString.indexOf("Temp C:")+7));
println(val);
if (val<28)
{println ("ok");}
else {println ("noOk");}




27.50
27.5
ok
29.00
28.00
28.0
noOk
29.00

 

ourlive
Offline
Зарегистрирован: 26.05.2012

Возникла проблемка, как проверить доступность нужного порта? Листинг портов строит список без учёта занят/свободен. Необходимо получать сообщение о занятости порта (на данный момент занятость порта другим приложением приводит к ошибке библиотеки).

leshak
Offline
Зарегистрирован: 29.09.2011

Самый "лобовой вариант", обернуть попытку открытия порта в try-catch блок.

ourlive
Offline
Зарегистрирован: 26.05.2012

тогда помощь далее нужна, взял пример по функции

  

BufferedReader reader;
String line;
 
void setup() {
  reader = createReader("positions.txt");    
}
 
void draw() {
  try {
    line = reader.readLine();
  } catch (IOException e) {
    e.printStackTrace();
    line = null;
  }
  if (line == null) {
    print("stop");
    // Stop reading because of an error or file is empty
    exit(); 
  } else {
    String[] pieces = split(line, TAB);
    int x = int(pieces[0]);
    int y = int(pieces[1]);
    print("+");
  }
}

по строкам 11-12 сразу вопрос, если файл есть, но пустой, все как описано работает. А вот если файла нет совсем, то ошибка снова на строке 10 и её не перехватывает (условие перехвата другое должно быть?). А строка 12 вообще непонятно что такое, вроде как печататься что то куда то должно, однако видимых результатов нигде нет.

Geronimo
Offline
Зарегистрирован: 06.05.2013

Попробуй не IOException а Exception ловить

ourlive
Offline
Зарегистрирован: 26.05.2012

Хм.. Поймалось.. Спасибо. На первое время такого варианта отлова ошибок мне за глаза хватит.

Geronimo
Offline
Зарегистрирован: 06.05.2013

ловя Exception ты поймаешь все ошшибки

ourlive
Offline
Зарегистрирован: 26.05.2012

Это я уже потестил, попихал туда разные косяки. Относительно ошибок ком-порта оно и не важно. Нет чтения данных, нет нормальной работы. Приложение можно закрывать записав ошибку в лог или вынуждать пользователя менять настройки если они доступны для изменения через само приложение (чего я не планирую, все вынесено в *.ini и только)

leshak
Offline
Зарегистрирован: 29.09.2011

ourlive пишет:

Приложение можно закрывать записав ошибку в лог или вынуждать пользователя менять настройки 

Можно изанчально пробежатся по всему списку портов и посмотреть кто открывается, а кто нет. И пользователю давать список уже "живых портов".

Собственно сама ArduinoIDE, по крайней мере в старых версиях, именно так и делала. Поэтому и были жалобы типа "долго дуплит когда открываю меню tools" если в системе много ком-портов (всякий телефонный софт любит заводить с десяток портов).