[[How2Computing]]
*How to use serial port on Mac OS X [#y0fdbfb6]
//http://gyazo.com/0060e9c32c4f010456ec13e205e77764.png
http://is.ocha.ac.jp/~siio/gyazo/20140726120153.png
http://is.ocha.ac.jp/~siio/gyazo/20140726120104.png
http://is.ocha.ac.jp/~siio/gyazo/20140726115840.png
MacOS Xで、RS232C型シリアルポートを使うためのメモ書きです。
実際には、すでにMacintoshには何年も前からシリアルポートが付いていません。
レガシー(遺産)な技術、すなわち失われた太古の技術と言ってもよいです。
とはいえ、RS232C風のシリアル通信は、簡単で便利なので、世の中ではあちこちで使われています。
それをMacintoshで読む場合には、USBシリアル変換器のようなものを使います。
また、現行のArduinoでは、USBシリアル変換器を内蔵していて、USB経由で、シリアル信号を送ってきます。
USBシリアル変換器やArduinoでは、FTDI社(http://www.ftdichip.com/) の
チップが使われていることが多く、ここのVirtual COM port (VCP)ドライバというのをインストールすると、
/dev以下に旧来のシリアルポートと互換のスペシャルファイルが出来上がります。
また、一部のUSBシリアル変換器 ( http://www.sun-denshi.co.jp/scc/products/mobile/vs60r/vs60r.htm ) や、最新のArduino (Arduino Uno, Arduino MEGA 2560)は、USBの標準のCDCクラス (Communications Device Class) として動作するので、
ドライバーをインストールしなくても、/dev/cu.usbmodemXXXXというようなスペシャルファイルが現れます。
ここでは、このようにUSBを経由して送られてきたシリアル信号を、Mac OS Xで読んでプログラムする方法を紹介します。
まずは、ネットでググった一般的なシリアルポートの情報をメモしておきます。
-http://linuxjf.sourceforge.jp/JFdocs/Serial-HOWTO.html
-http://0n0.fc2web.com/paso/serial/serial01.html
*Arduinoでシリアル通信(送信)するプログラム [#q0344560]
Arduinoで以下のプログラムを作ったとします。
int outpin=13;
int inpin=2;
void setup() {
// initialize the digital pin as an output.
// Pin 13 has an LED connected on most Arduino boards:
pinMode(outpin, OUTPUT);
pinMode(inpin, INPUT);
Serial.begin(9600);
}
void loop() {
if ( digitalRead(inpin) == HIGH) {
digitalWrite(outpin, HIGH); // set the LED on
Serial.print("H");
} else {
digitalWrite(outpin, LOW); // set the LED off
Serial.print("L");
}
delay(1000); // wait for a second
}
写真のように、2番ピンに押しボタンスイッチを付けると、
これを押すことで13番のLEDが消えます。
http://gyazo.com/63b7dd8b1468470eba4d5b5451114024.png
//http://gyazo.com/25e22833c7482de19c4580f9e0e85a3e.png
また、このプログラムは、9600baudでボタンの状態を知らせます。
ボタンが押されていないと'H'の文字が、押されると'L'の文字がシリアルポートに流れます。
*Arduinoからのシリアル情報をC言語で読み取る [#q062972d]
これをC言語で読むには、以下のようにします。
(逆スラッシュが化けているかもしれないです。コピペするときはお気をつけください)
// #include <sys/types.h>
// #include <sys/stat.h>
#include <unistd.h> //for open() close() read()
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <strings.h>
#include <signal.h> //to handle ctrl-c
#define BAUDRATE B9600
#define MODEMDEVICE "/dev/cu.usbmodem621"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
int fd;
struct termios oldtio, newtio;
int isrunning = TRUE;
int serialOpen() {
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {
printf("open error: %s\n",MODEMDEVICE);
return -1;
}
tcgetattr(fd,&oldtio); /* save current port settings */
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 0; /* inter-character timer unused */
newtio.c_cc[VMIN] = 1; /* blocking read until 1 chars received */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
return 0;
}
void serialClose() {
tcsetattr(fd,TCSANOW,&oldtio); //restore previous port setting
close(fd);
}
unsigned char serialReadChar() {
unsigned char result;
int length=0;
tcflush(fd, TCIFLUSH); //clear the receiving buffer
length = read(fd,&result,1); //blocked until reading 1 byte.
return result;
}
void interrupt(int sig) { isrunning = FALSE; } //ctrl-c handler
int main() {
int c, res;
unsigned char result;
if(serialOpen() != 0) return -1;
signal(SIGINT, interrupt); //set ctrl-c handler
while (isrunning) { /*endless loop until ctrl-c is typed */
printf("value is %c\n", serialReadChar());
}
serialClose();
return 0;
}
これを、gcc test.cなどしてコンパイルし、実行すると、
以下のように、読めていることがわかります。
ArduinoのIDEで
/dev/tty.usb..を使っている場合は、上記のように、
/dev/cu.usbl... で動きます.
ちなみに、このプログラムはLinuxなどでも動くと思われます。
http://gyazo.com/fa5ef8361553618306c70d46523ea1a7.png
*Arduinoにシリアル情報をC言語で書き込む(2015.05.29追加) [#q062972d]
上記のプログラムに下記の関数を追加する事でC言語でArduinoへ数字を1文字送信出来るようになります。
void serialWriteChar(int num){
unsigned char result;
int length = 0;
write(fd,&num,1);
}
*Arduinoからのシリアル情報をPythonで読み取る [#e96c175f]
簡単です。
**pyserialをインストールする [#cbdb2cd7]
+pyserialを入手する&br;
--http://pypi.python.org/pypi/pyserial
からpyserialを入手します。
今回は、
pyserial-2.5.tar.gz
を使いました。
+pyserialをインストールする&br;
ダウンロードした圧縮ファイルを開いて、
setup.pyを
sudo python setup.py install
として動かします。
**シリアルポートからデータを取得する [#u54bbc90]
つぎに、適当にこんなプログラムを書きます。
import serial
ser=serial.Serial('/dev/cu.usbmodem3a21',9600,timeout=2)
data = ser.read(10)
if len(data) != 0 :
print data
ser.close()
10個のデータを取得して、約10秒後に表示してくれます(Arduinoから毎秒1個のデータが来るため)。
http://gyazo.com/ca59528f454106a9df41b1cceaf55dbe.png
*Arduinoからのシリアル情報をProcessingで読み取る [#g5db712a]
こちらも簡単です。解説はこちらをみてください。 http://www.processing.org/reference/libraries/serial/
import processing.serial.*;
Serial myPort;
void setup(){
myPort = new Serial(this,"/dev/tty.usbmodem3a11",9600);
}
void draw(){
background(0);
while(myPort.available() > 0 )
println("value is " + myPort.readChar());
}
http://is.ocha.ac.jp/~siio/gyazo/20140726121616.png
*Arduinoからのシリアル情報をJavaで読み取る [#t78d8014]
Windowsなどではシリアル通信するクラスが配布されていたと思います。
Macなどには無かったように思います(最近はあるのかもしれない)。
ここでは面倒ですが、
Cでダイナミックライブラリを作って、JNAで読む方法を紹介します。
これができればCで作ったもののすべてがJavaから使えるので嬉しい場面があるかと思います。
ダイナミックライブラリとJNAについては以下をみてください。
-http://is.ocha.ac.jp/~siio/index.php?How2JNA
上記のCプログラムをダイナミックライブラリにします。
このプログラムの名前が、libserread.cだったとしたら、以下のようにコンパイルします。
cc -dynamiclib -o libserread.dylib libserread.c
このあと、JNAをインストールしたJavaの環境で、以下のプログラムをjavacでコンパイルしてjavaで動かせばokです。(確実にクローズするために60個データを表示してcloseするようにしました。)
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class TestSerial {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("serread", CLibrary.class);
int serialOpen();
void serialClose();
byte serialReadChar();
}
public static void main(String[] args) {
CLibrary arduino = CLibrary.INSTANCE;
arduino.serialOpen();
for(int i=0;i<60;i++) System.out.println((char)arduino.serialReadChar());
arduino.serialClose();
}
}
*ArduinoとJavaでシリアル通信をやり取りするためのクラス(2015.05.29更新) [#t78d8014]
上記の方法でCのダイナミックライブラリを作り、JavaとArduinoでシリアル通信(読み書き)できるようにするためのクラスです。
これは2014年に研究室有志メンバーで学祭に出店したリジョワーツ魔法魔術学校のアトラクション(薬草学・マンドラゴラ)の制御の為に作ったので、Classの名前がそれ仕様になっています。他で使う際には
クラス名とコンストラクタの部分の「SerialFromMNDR」を任意の名称に変更して使って下さい。
また、Arduinoから情報を読み込むread()はChar型1文字分を読み込みますが、Arduinoへ書き込むwrite()の方は1桁の数字を送るようになっています。それぞれ需要にあわせて、Char型やint型はカスタマイズ氏て下さい。
import java.io.UnsupportedEncodingException;
import com.sun.jna.Library;
import com.sun.jna.Native;
/*
* JavaでArduinoとシリアル通信をする
*/
public class SerialFromMNDR {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("serread", CLibrary.class);
int serialOpen();
void serialClose();
byte serialReadChar();
void serialWriteChar(int num);
}
CLibrary arduino;
public SerialFromMNDR(){
arduino = CLibrary.INSTANCE;
}
/* シリアル通信開始 */
void open(){
arduino.serialOpen();
}
/* シリアル通信終了 */
void close(){
arduino.serialClose();
}
/* Arduinoからの信号を読み取る */
String read(){
byte[] data= new byte[1];
data[0] = arduino.serialReadChar();
String strAscii = "";
try {
strAscii = new String(data, "US-ASCII");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return strAscii;
}
/* Arduinoに一文字送る */
void write(int i){
arduino.serialWriteChar(i);
}
}
このクラスを呼び出して使う際には、まず
SerialFromMNDR.open();
でシリアル通信を開始します。その後はread()やwrite()で自由にArduinoと通信できるようになります。