Go Down

Topic: Tty for serial port to Arduino from Linino (Read 27908 times) previous topic - next topic

scrot

All,

I'm trying to implement Firmata using pyfirmata on linino, and the Standard Firmata on the arduino.  I know on the Arduino side I need to use Serial1.

My question is: What /dev/tty to I use to talk to the arduino?  I know that the OS launches a terminal on that TTY which is how you can talk to the Linino over Serial1 from Arduino.  Simply want to treat the arduino as a dumb slave to my Python program running on the Linino.


priority

Needed this myself.  Just need to ask Linino "nicely". 

Code: [Select]
root@arduino:/# dmesg | grep tty
[    0.000000] Kernel command line:  board=Linino console=ttyATH0,250000 mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,14656k(rootfs),1280k(kernel),64k(nvram),64k(art),15936k@0x50000(firmware) rootfstype=squashfs,jffs2 noinitrd
[    0.620000] ar933x-uart: ttyATH0 at MMIO 0x18020000 (irq = 11) is a AR933X UART
[    0.630000] console [ttyATH0] enabled, bootconsole disabled


Found this by searching through the OpenWRT forums.

scrot

Excellent!  I didn't even think of using dmesg.  The next question is how to disable the console that runs on that serial port?  I spend some time looking through init.d and didn't find anything.  I'll need to dig some more.  If I can disable the console then I should have a nice clean connection from python to arduino.

priority

Edit /etc/inittab to disable the serial console.  Specifically, comment or delete:
Code: [Select]
ttyATH0::askfirst:/bin/ash --login

More info: https://forum.openwrt.org/viewtopic.php?id=15165

Looking forward to seeing how fast your clean connection python code runs.

Federico Fissore

Me too. Keep us posted. It looks like a much better approach
Have you upgraded the Yún? If you've just got it, then ***it needs to be upgraded!*** Check out the tutorial at http://is.gd/1jUPNF

wayoda

Hi,
with the tips in this thread I was able to do some very basic IO from python to the atmega:

I disabled the login on ttyATH0 by editing the the file /etc/inittab
Code: [Select]

::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
#disable the login console on this serial by commenting it out
#ttyATH0::askfirst:/bin/ash --login


[font=Verdana]I'm not sure if disabling the console will cause any  sideeffects, but as long as I can still ssh into the Yun I feel safe[/font]

Here is a very basic sketch to run on the atmega, which reads a character and if it is one of the digits 0-8 it echos the digit value +1, otherwise it simply echos the character just read.
Code: [Select]

void setup() {
  Serial1.begin(9600);
}

void loop() {
  char c;

  while (Serial1.available() > 0) {
    c=Serial1.read();
    if(c>='0' && c<'9')
      c++;
    Serial1.print(c);
   }
}

The I wrote the most basic python code to do some IO over serial: It opens the serial given on the first commandline argument and then sends the first 5 characters from the second argument. Then it reads 5 bytes from the serial and closes it.
Code: [Select]

#File st.py run like "python st.py /dev/ttyATH0 '123abc'
import serial
import sys

s=serial.Serial(sys.argv[1],9600,timeout=1)
data =sys.argv[2]
s.write(data[0:5])
result=s.read(5)
print result
s.close()


This is what I get, seems to work fine
Code: [Select]

root@YunYun:/mnt/sda1/python# python st.py /dev/ttyATH0 'ab3deohg'
ab4de
root@YunYun:/mnt/sda1/python#


Reference to PySerial : http://pyserial.sourceforge.net

scrot

I was able to reproduce your results.  This is exciting.  I'm working on making Firmata work.  My first experiment didn't succeed.  I think it just a matter of some tinkering.  I'll keep you in the loop.

Federico Fissore

Very well done wayoda. This is become really interesting. Out of curiosity: could you set up a stress test case?
Something like flooding the 32u4 with random chars (in a 1.000.000 rounds "for" loop) and checking if the output is the expected one
Have you upgraded the Yún? If you've just got it, then ***it needs to be upgraded!*** Check out the tutorial at http://is.gd/1jUPNF

robertofc

Great job!!! This is what I was looking for.
I'll try.

wayoda


Out of curiosity: could you set up a stress test case?
Something like flooding the 32u4 with random chars (in a 1.000.000 rounds "for" loop) and checking if the output is the expected one

I did some quick tests. In short...

  • The maximum baudrate is 115200 baud. Tests with 230400 baud  always failed on the first read attempt.

  • With the simple Arduino Sketch (see below) the IO-throughput is about 10kB/s.



[font=Verdana]The baudrate in the python script and the Arduino Sketch must (obviously) match to make this work[/font]

Here is the python script for testing
Code: [Select]

"""
Usage :
    python st.py PORT BAUDRATE KILO_BYTES

example :
python st.py /dev/ttyATH0 115200 10
Will send and receive 10kB of data

turn on profiling:
python -m cProfile st.py /dev/ttyATH0 115200 10
"""

import serial
import sys

data='01234567012345670123456701234567'
expected='12345678123456781234567812345678'

#one packet is 32 bytes so 1kByte is 32 packets
packets=int(sys.argv[3])*32
s=serial.Serial(sys.argv[1],sys.argv[2],timeout=5)
for i in range(packets):
    s.write(data)
    result=s.read(32)
    if result!=expected:
        raise ValueError('Mismatch on run : '+str(i)+'\ndata = "'+data+'"\nresult = "'+result+'"')
print "Done!"
s.close()


On the Arduino I run this Sketch. It blinks the Led after coming out of a reset.
Code: [Select]

void setup() {
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  delay(500);
  digitalWrite(13,LOW);
  delay(500);
  digitalWrite(13,HIGH);
  delay(500);
  digitalWrite(13,LOW);
  Serial1.begin(115200);
 
}

void loop() {
  char c;
 
  while (Serial1.available() > 0) {
    c=Serial1.read();
    c++;
    Serial1.print(c);
  }
 
}



Here is the output of the longest test I ran  (4MB of data).
Takes about 7 minutes to complete!
Code: [Select]

root@YunYun:/mnt/sda1/python# python -m cProfile st.py /dev/ttyATH0 115200 4096
Done!
         5392556 function calls in 431.015 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.005    0.005    0.026    0.026 __init__.py:8(<module>)
        1    0.017    0.017    0.022    0.022 serialposix.py:13(<module>)
        1    0.000    0.000    0.000    0.000 serialposix.py:163(Serial)
        1    0.000    0.000    0.001    0.001 serialposix.py:168(open)
        1    0.001    0.001    0.001    0.001 serialposix.py:192(_reconfigurePort)
        1    0.000    0.000    0.000    0.000 serialposix.py:321(close)
   131072  189.347    0.001  392.045    0.003 serialposix.py:340(read)
   131072   11.837    0.000   25.662    0.000 serialposix.py:359(write)
        1    0.001    0.001    0.001    0.001 serialutil.py:111(SerialBase)
        1    0.001    0.001    0.002    0.002 serialutil.py:123(__init__)
        1    0.000    0.000    0.000    0.000 serialutil.py:196(setPort)
        1    0.000    0.000    0.000    0.000 serialutil.py:221(setBaudrate)
        1    0.000    0.000    0.000    0.000 serialutil.py:240(setByteSize)
        1    0.000    0.000    0.000    0.000 serialutil.py:253(setParity)
        1    0.000    0.000    0.000    0.000 serialutil.py:266(setStopbits)
        1    0.000    0.000    0.000    0.000 serialutil.py:279(setTimeout)
        1    0.000    0.000    0.000    0.000 serialutil.py:298(setWriteTimeout)
        1    0.000    0.000    0.000    0.000 serialutil.py:30(SerialException)
        1    0.000    0.000    0.000    0.000 serialutil.py:317(setXonXoff)
        1    0.000    0.000    0.000    0.000 serialutil.py:328(setRtsCts)
        1    0.000    0.000    0.000    0.000 serialutil.py:339(setDsrDtr)
        1    0.000    0.000    0.000    0.000 serialutil.py:35(SerialTimeoutException)
        1    0.000    0.000    0.000    0.000 serialutil.py:355(setInterCharTimeout)
        1    0.000    0.000    0.000    0.000 serialutil.py:40(FileLike)
        1    0.003    0.003    0.004    0.004 serialutil.py:8(<module>)
        1   13.242   13.242  431.015  431.015 st.py:14(<module>)
        3    0.000    0.000    0.000    0.000 {_struct.pack}
        2    0.000    0.000    0.000    0.000 {chr}
        3    0.000    0.000    0.000    0.000 {getattr}
       21    0.000    0.000    0.000    0.000 {hasattr}
   131072    1.061    0.000    1.061    0.000 {isinstance}
  2565176   21.640    0.000   21.640    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 {method 'lower' of 'str' objects}
        1    0.000    0.000    0.000    0.000 {posix.close}
        1    0.000    0.000    0.000    0.000 {posix.open}
  1151516   62.691    0.000   62.691    0.000 {posix.read}
   131072   12.070    0.000   12.070    0.000 {posix.write}
        1    0.038    0.038    0.038    0.038 {range}
  1151516  119.062    0.000  119.062    0.000 {select.select}
        1    0.000    0.000    0.000    0.000 {termios.tcgetattr}
        1    0.000    0.000    0.000    0.000 {termios.tcsetattr}

Federico Fissore

Can you retry with 250000 baud? That's the speed we set for ttyATH0
Have you upgraded the Yún? If you've just got it, then ***it needs to be upgraded!*** Check out the tutorial at http://is.gd/1jUPNF

wayoda


Can you retry with 250000 baud? That's the speed we set for ttyATH0

Doesn't work. For some reason I get incomplete readings for all speeds above 115200 baud. (230400, 250000 etc.)
I also tried to write smaller data packets of 16 bytes instead of 32 bytes, but no luck. Every baudrate above 115200 baud fails on the first write/read cycle.

But 115200 baud (10kB/s) is fast enough for most usecases where data from the ATmega32u4 is  being forwarded to a webservice.
I can live with that limitation.

scrot

I got Firmata to work between a Python script running on Linino and the Arduino.  I was able to get about 400 messages per second which is sufficient for my needs.  I made the following changes to the StandardFirmata sketch "begin" section.

Code: [Select]
void setup()
{
 
  Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION);

  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  Serial1.begin(9600); // Set the baud.
  Firmata.begin(Serial1);
  systemResetCallback();  // reset to default config
}


On the python I installed PyFirmata and pyserial.  The following code turns on the LED:

Code: [Select]
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyATH0', baudrate=9600)
board.digital[13].write(1)

GreyCon

Hi Wayoda,

   when you say a BAUD rate of 250000 fails - do you get characters from Serial, or nothing at all? The Arduino UART should definitely do 250000 , and higher. And since the hard-wired serial connection is very short, there shouldn't be any signal degradation issues.

Maybe you have a marginal board. I will give it a go tonight and let you know results. If necessary we can look at the UART registers for over-run or parity errors....

Con

wayoda


Hi Wayoda,
   when you say a BAUD rate of 250000 fails - do you get characters from Serial, or nothing at all?


The python script writes 32 chars to the ATmega and then reads 32 bytes with a five second timeout.
When used with baudrates above 115200 the read returns unexpected characters and also too few of them.

Go Up