INDEX(各項目ごとの目次)

[HOME]  [Processing関係]  [Arduino関係]  [マテリアル関係]  [秋葉原工作マップ]

2008年用ですが、部分的に内容を更新しています(2010/06/14)。
また、[建築農業工作ゼミ2009-2010]とも連動していますので、そちらにも幾つかサンプルがあります。
:

ラベル サーボ の投稿を表示しています。 すべての投稿を表示
ラベル サーボ の投稿を表示しています。 すべての投稿を表示

10/25/2008

Processing-Arduino ネットワーク制御

今回は、ProcessingのNetworkライブラリを使って、ネットワーク越しに複数のクライアントコンピュータから、サーバコンピュータに接続されたArduinoのサーボとLEDを操作することにします。ネットワーク上では、情報を提供する側となるサーバコンピュータに複数のクライアントコンピュータが接続されているような状態になります。



まず、上図のようにローカルネットワーク内での通信を行ってみます(後半にローカルネットワーク外からの通信サンプルを記載しておきました)。

ひとつのクライアントからサーバへ信号が送られると、サーボの角度やLEDの点灯状態が変化しますが、サーバはクライアントからの信号を受け取るだけではなく、現在のサーボの角度やLEDの状態(オン/オフ)についての情報も各クライアントへ送り返します。そうすることで、各クライアントは現在のサーボやLEDの状態を把握しながら制御することができます。
サーバコンピュータとクライアントコンピュータはインターネット越しに通信され、サーバコンピュータとArduinoはシリアル通信されます。


(Processingの画面:画面上半分がサーボ用スライダ、下半分がLED用ボタン)

Processingの画面には、上半分がサーボ用のスライダ、下半分にLED用のボタンを配置することにします。スライダは0~255の値を送信し、ボタンは押すとオン(緑)の状態になり、もう一度押すと白(オフ)に戻ります。あるクライアントがボタンを押せば、サーバとその他のクライアントのボタンの色も同時に変わります。サーバからのコントロールも可能です。

Arduinoでは、サーボの値とLEDの値をサーバコンピュータからシリアル通信を通してデータ受信します。以下のプログラムでは、サーボは3番ピンと接続しPWMで制御することにします(サーボ制御の方法については、「Arduino サーボ制御」を参照して下さい)。LEDは13番ピンに接続しデジタル出力でオン/オフ制御することにします。


Arduinoのプログラム:

//サーボ用変数を用意
int servoVal;
//LED用変数を用意
int ledVal;

void setup(){
//シリアル通信開始
Serial.begin(9600);
//13番ピンをデジタル出力に設定
pinMode(13,OUTPUT);
}

void loop(){
//データが二個きたら(1個より多ければ)
if(Serial.available()>1){
//サーボの回転値として読み込む(0~255)
servoVal=Serial.read();
//LEDの点灯状態(0:OFF,1:ON)
ledVal=Serial.read();
//合図用データ送信
Serial.print('A');
}
//3番ピン(PWM):アナログ出力(サーボ)
analogWrite(3,servoVal);
//13番ピン:デジタル出力(LED)
digitalWrite(13,ledVal);

//0.02秒周期にする
delay(20);
}



「サーバのプログラム」:
サーバ側のプログラムでは、ネットワークとシリアル通信の二つのライブラリが必要となります。スライダは横方向(X座標)に動かし256段階あるので、画面サイズの横幅も256ピクセルにしてあります。ドラッグのためのプログラムは、mouseDragged()を使わず、startDrag(名前は任意)というフラグを用意し、mousePressed()でマウスを押したときにフラグがtrueになり、ドラッグが開始されたことになり、mouseReleased()でマウスが放されたときにドラッグ終了になり、同時にフラグもfalseになるようにしておきます。つまりフラグstartDragによって、ドラッグしているかどうかを判別することになります。ドラッグしていなくてもマウスボタンを押し続けている限りドラッグ中と見なされるので、その間データを送信し続けます。
あまり高速での通信ができないためフレームレートを10にしています。環境に応じてフレームレートを調整してみて下さい(サーバとクライアントのプログラム両方)。
サーバとクライアントの間では、文字列で送受信しています。文字列に含まれるデータは:

サーボの値 + コンマ + LEDの値 + 改行コード

であり、たとえば

"155,1\n"

のような連続した文字列になります。サーボの値は0~255の数値、LEDの値は0か1になり、その間をコンマで区切り(デリミタ)、最後の部分に「\n」改行コードを付け加えて送信します。文字「\n」は、アスキーコード表で十進数の「10」に相当します。受信の際には、readStringUntil(10)を使うことで、改行コード「\n」つまり「10」までをひとまとまりのデータとして読み込み、その文字列データをtrim()で改行コードを取り除き、split()でコンマをもとに配列に分解し、int()で文字列の数値を整数化し、それぞれの値に代入します(文字列を分解して数値化する方法は「Arduino-Processing シリアル通信5」でも説明してあります)。
サーバのプログラムが開始したら、「s」キーを押してArduinoとのシリアル通信を開始します。

Processing サーバのプログラム:

//ネットワークライブラリの取り込み
import processing.net.*;
//シリアル通信ライブラリの取り込み
import processing.serial.*;

//サーバのインスタンス
Server server;
//クライアントのインスタンス
Client client;
//シリアル通信のインスタンス
Serial port;

//サーボの変数
int servoVal;
//LEDの変数
int ledVal;
//ドラッグ中かどうかのフラグ
boolean startDrag=false;

void setup(){
//画面サイズ
size(256,200);
//フレームレートを遅めに設定
frameRate(10);
//サーバの設定(ポート:12345)
server = new Server(this, 12345);
//シリアルポート設定
port=new Serial(this,"/dev/tty.usbserial-A4001Kjl",9600);
//矩形描画を中央配置に設定
rectMode(CENTER);
//外形線なし
noStroke();
}

void draw() {
//クライアントからのデータ受信
client = server.available();
//クライアント受信内容が空ではないとき
if (client != null) {
//文字列データの読み込み(改行コードまで)
String input=client.readStringUntil(10);
//文字列データの改行コードを取り除く
input=trim(input);
//文字列データを整数の配列に変換
int[] data = int(split(input, ','));
//配列の最初の値をサーボ変数に代入
servoVal=data[0];
//配列の次の値をLED変数に代入
ledVal=data[1];
}

//ドラッグ中
if(startDrag){
//サーボ変数にマウスX座標値を代入(最小値:0、最大値:255)
servoVal=constrain(mouseX,0,255);
//クライアント側へ送信(サーボの値、コンマ、LEDの値、改行コード)
server.write(servoVal+","+ledVal+"\n");
}

background(0);//背景(黒)

fill(80);//スライダ溝の塗色(グレー:80)
rect(width/2,50,width,50);//スライダ溝の矩形描画
fill(255);//スライダの塗色(白)
rect(servoVal,50,10,50);//スライダの矩形描画

//LEDボタンの色切替(0:オフ,1:オン)
if(ledVal==1){ //オンの場合
fill(0,255,0);//緑にする
}else{ //オフの場合
fill(255); //白にする
}
//LED用のボタン描画
rect(width/2,150,50,50);
}

//シリアル通信処理
void serialEvent(Serial p){
//合図用データが1個来た場合(0個より多い場合)
if(port.available()>0){
//合図用データを読込んバッファを空にする
port.read();
//サーボの値とLEDの値をシリアル通信で出力
port.write(servoVal);
port.write(ledVal);
}
}

//キーを押した場合
void keyPressed(){
//「s」キーの場合
if(key=='s'){
//シリアル通信開始用データ送信
port.write(servoVal);
port.write(ledVal);
}
}

//マウスボタンを押した場合
void mousePressed(){
//LED用のボタン矩形内にマウスがある場合
if(mouseX>width/2-25 && mouseX<width/2+25 && mouseY>125 && mouseY<175){
//LED点灯切替処理
if(ledVal==0){//オフの場合
ledVal=1; //オンにする
}else{ //オンの場合
ledVal=0; //オフにする
}
//クライアント側へ送信(サーボの値、コンマ、LEDの値、改行コード)
server.write(servoVal+","+ledVal+"\n");
}
//スライダ部分の場合
if(mouseY>25 && mouseY<75){
//ドラッグのフラグをtrueにする
startDrag=true;
}
}

//マウスを放した場合
void mouseReleased(){
//ドラッグのフラグをfalseにする
startDrag=false;
}




「Processing クライアント側のプログラム」:

//ネットワークライブラリを取り込む
import processing.net.*;
//クライアントのインスタンス
Client client;

//サーボ用変数を用意
int servoVal=127;
//LED用変数を用意
int ledVal=0;
//ドラッグ中かどうかのフラグ
boolean startDrag;

void setup() {
size(256, 200);
frameRate(10);
//サーバのIPアドレス、ポートの設定
//(「10.0.1.2」の部分は適宜変更)
client = new Client(this, "10.0.1.2", 12345);
rectMode(CENTER);
noStroke();
}

void draw(){
//サーバからのデータ受信
if (client.available() > 0) {
String input = client.readStringUntil(10);
input = trim(input);
int[] data = int(split(input, ','));
print(data);
servoVal=data[0];
ledVal=data[1];
}

//ドラッグ中の処理
if(startDrag){
servoVal=constrain(mouseX,0,255);
client.write(servoVal + "," +ledVal + "\n");
}

//描画処理
background(0);
fill(20);
rect(width/2,50,width,50);
fill(255);
rect(servoVal,50,10,50);
if(ledVal==1){
fill(0,255,0);
}else{
fill(255);
}
rect(width/2,150,50,50);
}


void mousePressed(){
if(mouseX>width/2-25 && mouseX<width/2+25 && mouseY>125 && mouseY<175){
if(ledVal==0){
ledVal=1;
}else{
ledVal=0;
}
//サーバへ送信(サーボの値、コンマ、LEDの値、改行コード)
client.write(servoVal + "," +ledVal + "\n");
}

if(mouseY>25 && mouseY<75){
startDrag=true;
}
}

void mouseReleased(){
startDrag=false;
}



クライアント側のプログラムでは、setup(){...}内でサーバのIPアドレスを指定する必要があります。上のプログラムでは「10.0.1.2」になっていますが、適宜変更してください。通常ローカルネットワークであれば「127.0.1.2」や「192.168.1.2」、あるいはルーターやAirMacなどを使っていれば、「10.0.1.2」などになっているかもしれません。サーバに設定したコンピュータのIPアドレスを調べるには、MacOSXであれば、「システム環境設定>ネットワーク」を開き、AirMacを使用している場合は「AirMac」を選択、ケーブル接続している場合は「内蔵Ethernet」を選択し、「TCP/IP」タグを選択すると2段目あたりに「IPアドレス:10.0.1.2」などと表示されています。Windowsの場合は、コマンドプロンプトを開いて、「ipconfig」と打ってリターンすれば、幾つかの情報が現れ「IP Address....10.0.1.2」などと表示されるはずです。



「外部からの接続方法」:
ルータを通してインターネットに接続している場合、ローカルネットワーク外から通信するには、ルータのポートマッピングやサーバコンピュータのファイヤーウォールの解除設定する必要がでてきます。
通常、インターネットプロバイダからグローバルIPアドレスがひとつ与えられています。各自のパソコンからグローバルIPアドレスを調べるには以下のようなサイトで調べることができます。
http://dog.tele.jp/lookup.php
「あなたのパソコンのグローバルIPアドレスは」と書かれている場所に表示されるはずです。
あるいは、
http://www.ugtop.com/spill.shtml
のサイトの「現在接続している場所(現IP)」の欄に同じアドレスが表示されるはずです。
このグローバルIPアドレスをメモしておきます。


「接続例」:
以下は、ローカルネットワーク内のひとつのコンピュータをサーバに設定し、ローカルネットワーク外から通信をするための接続例です。例えば、仕事場や学校のコンピュータから、自宅にあるサーバに設定したコンピュータにアクセスする方法です。



上画像では、ADSLモデム-ルータを使用してインターネットに接続しており、さらにそのADSLモデム-ルータにAirMacをケーブルで接続しています。そして複数あるコンピュータは、AirMacの無線通信でインターネットに接続しています。
このネットワークのグローバルIPアドレスは、先ほど調べた方法により「219.196.xxx.xxx」になっています(実際のアドレスに置き換えてください)。「モデム-ルータ」によって、グローバルIPアドレスがプライベートIPアドレスに変換され、複数のプライベートIPアドレスに分けられます(「192.168.xxx.xxx」のようなアドレス)。さらに、AirMacにおいてもルータ機能があるため、さらに細かなプライベートIPアドレスに分けられます(「10.0.1.xxx」のようなアドレス)。
ここでは、二つのルータによって二段階にIPアドレスが割り振られていますが、AirMacを「ブリッジモード」に切り替えることで、以下のようにAirMacのルータ機能を使わないネットワークに変更することができます。



「ブリッジモード」:
「ブリッジモード」は、コンピュータから「AirMacユーティリティ」を開いて変更することができます(ただし、変更できる権限が必要です)。「ブリッジモード」にすることで、AirMacはIPアドレス(「10.0.1.xxx」のようなアドレス)を割り振らなくなるので、元々の「モデム-ルータ」が割り振るアドレスを使うことにします(「192.168.xxx.xxx」のようなアドレス)。ただし、このままだと「モデム-ルータ」が自動的にプライベートIPアドレスをそれぞれのコンピュータに割り振ってしまうので、使用しないコンピュータなどがあるときは、プライベートIPアドレスが入れ替わってしまうことがあります。
そのため、サーバにしたいコンピュータには固定したIPアドレスを与えます。以下のように「コンピュータC」に固定のIPアドレス「192.168.3.10」を与えて、サーバとして機能させることにします。



「固定IPアドレスにする」:
各コンピュータ上のIPアドレス設定では、「DHCPサーバを参照」や「DHCPサーバを使用」というように、ルータから自動的にIPアドレスが割り振られる設定になっていることが多いと思います。MacOSXの場合、「システム環境設定>ネットワーク」へ行き、AirMac(あるいはEthernet:現在インターネットに接続している方法を選択)を選択し、「TCP/IP」の項目内で設定できます。サーバ用に使うコンピュータにおいては、このIPアドレス設定の部分を、「手入力」に変更し、指定したIPアドレスを使うように設定し直します。
Windows XPの場合は、「コントロールパネル>ネットワーク接続」で、使用しているネットワーク接続(「ワイヤレスネットワーク接続」など)のプロパティを右クリックで開き、「インターネットプロトコル(TCP/IP)」を選択しプロパティボタンを押し、「IPアドレスを自動的に取得する」に設定されている部分を「次のIPアドレスを使う」に切り替えて、以下の設定を入力していきます。

上図の場合は、ルータのIPアドレスが「192.168.3.1」になり、AirMacが「192.168.3.2」、以下に続く各コンピュータは「192.168.3.3」、「192.168.3.4」というように最後の数値がひとつずつ増えていきます。IPアドレスが重ならないように、固定するIPアドレスを「192.168.3.10」に設定しておきます(1~254まで可)。サブネットマスクは自動的に「255.255.255.0」になるはずです。ルータのIPアドレス(ゲートウェイ)は、「DHCPサーバを参照」の時と同じなので「192.168.3.1」を記入します。「DNS」あるいは「DNSサーバ」の項目については、先ほど調べたグローバルIPアドレスである「219.196.xxx.xxx」を記入します(グローバルIPアドレスは、実際に調べたアドレスを入れてください)。サーバ用のコンピュータの設定は以上です。


「ポートマッピング設定」:
もうひとつしなければならないことは、ポートマッピング(ポート転送/ポートフォワーディング)の設定です。回線に接続しているルータ自体の設定を変更する必要があります。通常コンピュータ上のブラウザからルータのアドレスにアクセスし操作するようになっています(各ルータのマニュアルを参照してください)。大抵の場合は、「詳細設定」のような項目に入っていると思います。
プロトコル、ポート、転送先のIPアドレス(先ほど固定したサーバ用のIPアドレス)を入力する必要があります。プロトコルは「TCP/UDP」を選択し、WAN側とLAN側のポートは同じものを入れておきますが、今回の場合Processingのコードでポートを「12345」に設定しておいたので、それを入力することにします(「12345」〜「12346」までというように範囲指定する入力にしておきます)。転送先IPアドレスは、固定した「192.168.3.10」を入力しておきます。ポートマッピングの設定は以上です。尚、ポートは、0~65535までの番号が入れられますが、0~1023までは使用目的が決められているので、あまりつかわない方がいいと思います。

ポートマッピングによって、ポート「12345」(あるいは「12346」)を通してローカルネットワーク外からグローバルIPアドレス「219.196.xxx.xxx」に送られた信号は、サーバ用コンピュータのプライベートIPアドレス「192.168.3.10」に転送されることになります。

Processingのクライアント用のプログラム内の、

client = new Client(this, "219.196.xxx.xxx", 12345);

IPアドレス部分をグローバルIPアドレス「219.196.xxx.xxx」(実際に調べたアドレスを入れてください)に書き換えればローカルネットワーク外から通信できるようになります。

参照:YahooBBのモデムのポート転送設定方法


「外部から通信できない場合」:
ファイヤーウォールによって、外部からの通信をブロックしている場合があるので、ファイヤーウォール設定を解除して通信してみてください。ただし、セキュリティ上危険になるので注意してください。

尚、同じローカルネットワーク内にある別のコンピュータからは通信できないので(例えば上図の「コンピュータA」とサーバの「コンピュータC」との通信はできない)、異なるグローバルIPアドレス(外部)から通信してください。「コンピュータA」と「コンピュータC」を通信させる場合は、前半で説明したローカルネットワーク内での通信方法を利用してください。



6/08/2008

Arduino サーボ制御



サーボモータは、信号を送ると指定した角度まで回転するので、ロボットの間接部分にもよく用いられています。通常のアナログサーボであれば、回転角の範囲は0〜180度程度です。種類によっては、回転範囲が180度以下のものや、360度回転(連続回転サーボ、あるいは0〜360度の範囲で回転するサーボ180度のサーボを改造する例、もうひとつの改造例)するものもありますが、今回は180度の回転が可能な一般的なサーボを制御します。サーボもDCモータ同様、Arduino基盤に対しては過電流となる恐れがあるので、別電源を用意したほうが無難ですが、一つくらいであれば直接つないでもそれほど問題でないでしょう。
サーボには大抵5V線(赤)、GND線(黒)、信号線(白)の3つの線があります。そのままArduino基盤につなぐ場合、5V線、GND線をそれぞれ基盤の5V端子、GND端子へ接続し、信号線をPWM端子へつないでanalogWrite()で制御することができます。



analogWrite()で動かす方法:(動くけど多少不安定)
今回はPWM端子である3番ピンにサーボの信号線を接続し、可変抵抗器で操作します。可変抵抗器からのanalogRead()による読み取り値0〜1023を4で割って、0〜255の範囲にスケールダウンします。analogWrite()は0〜255の値を出力しますが、サーボの動作角度においてはおよそ0〜180度に対応します。例えば、出力値を127としてanalogWrite(3,127)であれば、約90度のところで停止します。パルス信号の性質上、1ループを約20ミリ秒にすると動きが安定します。そのために、delay(20)を最後に加えておきます。

Arduinoのプログラム:

void setup(){
//特になし
}

void loop(){
//可変抵抗器の値を読み込み4で割る
int val=analogRead(0)/4;
//アナログ出力
analogWrite(3,val); //0~255
//0.05秒ループにする
delay(20);
}


analogWrite()が0〜255なので、180度の回転範囲を256段階の分解能で出力できるということになります。ただし、この方法だとガタガタと不安定な動きになるかもしれませんので、以下の方法をおすすめします。


ライブラリを利用する方法(Arduino0018):
Arduino0016まではPWMの9番ピンと10番ピンだけにサーボを接続可能でしたが、Arduino0017以降では、ソフトに含まれているライブラリを使うことで最大12個まで接続可能です(Megaの場合最大48個)。
ただし、このライブラリを使用すると9~10番ピンのPWM機能は使えなくなります(Megaの場合は12~23ピンをサーボに使用すると11~12ピンのPWMが機能しなくなります)。つまり、サーボとanalogWrite()を同時に使うプログラムの場合は、analogWrite()に使用するピンとして9~10のピンを避ける必要があります。
「メニューバー>Sketch>Import Library...>Servo」を選択すると「#include <Servo.h>」が自動的に挿入されライブラリを使用可能にします。以下はArduino0018に内包されているServoライブラリの使用例です。attach()でサーボを接続するピンを指定し、write()で0~180の角度の値(整数値)をいれます。プログラム内でmap()を使っていますが、センサから読み込まれる値val(変数)の範囲0~1023をサーボの角度出力値0~180度に変換する方法です。


#include <Servo.h>

Servo servo;//サーボのインスタンス

void setup(){
//サーボの信号線を3番ピンに接続
//(PWMピン以外のピンにも接続可)
servo.attach(3);
}

void loop(){
//センサの読み取り値
int val=analogRead(0);
//map()を使って0~1023のセンサ読取り値を0~180の角度に変換
int deg=map(val,0,1023,0,180);
//サーボ出力
servo.write(deg);//0~180まで
}



精度をあげて制御する方法:writeMicroseconds()を使う
write()を使う方法は0~180度を180段階の分解能でしか角度設定できませんが、新たに加わった機能writeMicroseconds()によって、より細かく角度を設定することが可能です。この場合サーボにパルス(パルス幅)の値を送って角度を決定します。
例えば:

writeMicroseconds(500)で0度
writeMicroseconds(1500)で90度(中間位置)
writeMicroseconds(2500)で180度

という感じになります。つまり0~180度の範囲を500~2500の範囲に変換すればいいことになります。
しかし、サーボによって受け入れるパルス幅が異なるので仕様書などで確認してください。
各サーボの最小値や最大値を超えたパルスを送ってもそれ以上回転しないか、負荷を与えることにもなるので注意して下さい。
ちなみに、
servo.attach(ピン番号,最小パルス幅,最大パルス幅);
というように()内に3つの値をいれることができます。最小パルス幅はデフォルトでは544、最大パルス幅は2400に設定されているようです。これらの値で動く範囲を調節できます。


#include <Servo.h>

Servo servo;//サーボのインスタンス

void setup(){
//サーボの信号線を3番ピンに接続
//(PWMピン以外のピンにも接続可)
servo.attach(3);
}

void loop(){
//センサからの読取り値
int val=analogRead(0);//0~1023
//map()を使って0~1023を544~2400に変換
int pulseWidth=map(val,0,1023,544,2400);
//サーボ出力
servo.writeMicroseconds(pulseWidth);//変換したパルス幅値を代入:544~2400
}


上記プログラムでは、writeMicroseconds()を使うことで、0~180度の範囲を544~2400の範囲の分解能で動かすことができます(180度の範囲を2400-544=1856分解能、約0.1度単位で角度を調節可能)。上の場合はanalogRead()を使っているので、その精度に左右されます(つまり1024分解能)。


以下は2008までの内容です。参考までに。

その他のライブラリの使用例:
ArduinoのPlaygroundというサイトには、サーボのライブラリがあります。このライブラリをダウンロードして、Arduinoのフォルダ内にあるlibraries(Arduino-0011>hardware>libraries)に入れれば、Arduinoの画面のメニューバー>sketch>Import Library>Servoを選んで利用することができます(#include <Servo.h>という一文が自動的に書き込まれます)。このライブラリを利用すれば、PWM端子以外のピンにもサーボを接続することができます。servo.write()の()内に0〜180の整数値を入れることで角度を制御するので、分解能は180(1度ずつ)となります。analogRead()の0〜1023の値に0.176を掛けて出力値を0〜180にスケールダウンします。小数点の計算なのでfloat型の変数valにしてから、servo.write()の()内にint()を用いて整数化しています。最後のServo::refresh()を、周期が20ミリ秒以下にならないように、少なくとも50ミリ秒に一回は呼び出す必要があります。

#include <Servo.h>

Servo servo;

void setup(){
//サーボの信号線を3番ピンに接続
//(PWMピン以外のピンにも接続可)
servo.attach(3);
}

void loop(){
//読み取り値をスケールダウン
float val=analogRead(0)*0.176;
//サーボ出力
servo.write(int(val));
//周期を更新
Servo::refresh();
}




パルスをつくって制御する方法:
analogRead()の読み取り値である0〜1023の1024段階で制御する方法があります。この場合は、プログラム上でdigitalWrite()のHIGHとLOWを交互に出力するパルスを生成して制御します。HIGHの継続時間とLOWの継続時間の合計が、パルスの周期である約20ミリ秒(20000マイクロ秒)になります。delayMicroseconds()で、HIGHとLOWの継続時間を変化させるプログラムで、サーボの動作角度を制御します。一般的なサーボにおいては、HIGHの継続時間は500〜2500マイクロ秒程度になります。500マイクロ秒で0度、2500マイクロ秒で180度という計算になります。約2000マイクロ秒の振り幅があるので、analogRead()で読み取った値を2倍するとほぼ0〜180度を1024段階の分解能で表現できます。digitalWrite()を使うのでPWM以外のピンにもサーボを接続することができます。

void setup(){
//パルス出力ピンの設定
//(デジタル出力なのでどのピンでも可)
pinMode(3,OUTPUT);
}
void loop(){
//可変抵抗器の読み込み値を2倍にする(振幅値:約2000)
int val=analogRead(0)*2;
//パルス:HIGHを出力
digitalWrite(3,HIGH);
//パルス最小値を500としvalを代入
delayMicroseconds(val+500);
//パルス:LOWを出力
digitalWrite(3,LOW);
//HIGHの継続時間を差引いて周期を20000usに調整
delayMicroseconds(10000-(val+500));
delayMicroseconds(10000);
}

パルスの周期は20000マイクロ秒なので、LOWの継続時間は20000マイクロ秒からHIGHの継続時間を差し引いた時間となります。尚、delayMicroseconds()の()内に入れられる最大値は16383なので(精度を保つことができる最大値)、20000-(val+500)とは書かずに、10000-(val+500)と10000に分けて書いてあります。


サーボによっては、パルスの最小値や最大値あるいは振幅値が多少異なるので、正確に制御したい場合はデータシートを参照するか、サーボごとにテストしてみる必要があります。


絵とき「サーボ制御」基礎のきそ (Mechatronics Series)
塩田 泰仁
日刊工業新聞社
売り上げランキング: 248872


[目次:Processing関係]  [HOMEへ戻る]  [目次:Arduino関係]