2013年5月14日火曜日

pwmの実験

Python 版の WiringPi をインストールしたときに使った WiringPi-Python ディレクトリにサンプルプログラムがあるので、それを実行してみる。
次のディレクトリに移動し、make してから実行する。
これは、Python 版ではなく C のプログラムなので、その実行には root 権限が必要となる。
$ cd WiringPi-Python/WiringPi/examples
$ make pwm
$ sudo ./pwm

ソースを見ればわかるが、enter キーを押すことで、ひとつずつ LED を点灯し、次に enter キーを押すと今度は消していって、最後はすべての LED の明るさを変える。
12個の LED を software pwm により輝度制御を行うサンプルプログラミになっている。

Raspberry Pi はソフトウェアによる PWM 生成の他にハードウェアでも、1ch だけであるが PWM を生成できるようになっている。

ハードウェアによる PWM 生成の例は test2.c だが、「PWM on Raspberry Pi」にもある。
ここに記載されている C のソースコードは、このままでは動かないので、修正したものを次に示す。
修正箇所は、ハードウェアによる生成は「pwmWrite(HARD_PWM_PIN, down);」で、ソフトウェアによる場合は「softPwmWrite(SOFT_PWM_PIN, down);」を使っている。
どちらも pwm のパルス幅を down という変数にしているが、この初期値が設定されていなかった。
変数 down の宣言部分で、このように「int down = kMaxVal;」初期値を設定している。
念のために、この down が0以下なら0、kMaxVal を超えていたら kMaxVal にする if 分も追加している。

//////---------------------------------------------------------------------------
////// Name:                   pwm_hard.c
////// Compiled with:      gcc pwm_hard.c -I/usr/local/include -L/usr/local/lib -lwiringPi -lpthread -o pwm_hard
////// Schematic:              .------.
//////                         | o  o |
//////                     RPi | o  o |12
//////                         | o  o-|-----(->|)-----\/\/\/\--o GND
//////                         | o  o |11    LED1       220
//////                         | o  o-|-----(->|)-----\/\/\/\--o GND
//////                         | o  o |      LED2       220
//////                         | o  o-|
//////
////// Notes:
//////---------------------------------------------------------------------------
#include 
#include 
#include 
#include 
#include 

#define kMaxVal 99
void control_event(int sig);
int HARD_PWM_PIN = 1; //Hardware PWM Pin(GPIO18-12)
int SOFT_PWM_PIN = 0; //Software PWM Pin(GPIO0-11)
int DELAY_MS = 10;
int main(void)
{
  (void)signal(SIGINT, control_event);
  (void)signal (SIGQUIT, control_event);
  printf("Hardware and software based PWM test on LED\n");
  if (getuid() != 0) {
    // wiringPi requires root privileges
    printf("Error:wiringPi must be run as root.\n");
    return 1;
  }
  if (wiringPiSetup() == -1) {
    printf("Error:wiringPi setup failed.\n");
    return 1;
  }
  pinMode(HARD_PWM_PIN, PWM_OUTPUT); // setup hardware pwm
  softPwmCreate(SOFT_PWM_PIN, 0, 100); // setup software pwm pin
  int up;
  int down = kMaxVal;
  while (1) {
    for (up = 1; up = 5; down--) {
      if (down < 0) {
        down = kMaxVal;
      }
      if (down > kMaxVal) {
        down = kMaxVal;
      }
      pwmWrite(HARD_PWM_PIN, down);
      softPwmWrite(SOFT_PWM_PIN, down);
      delay(DELAY_MS * 2);
    }
    delay(DELAY_MS * 5);
  }
}
void control_event(int sig)
{
  printf("\b\bExiting...\n");
  pwmWrite(HARD_PWM_PIN, 0);
  softPwmWrite(SOFT_PWM_PIN, 0);
  delay(100); // wait a little for the pwm to finish write
  exit(0);
}

これを実行するとわかるが、ハードウェアによる PWM 出力の LED がソフトウェアのそれと比べて暗い。
調べると、ハードウェアは0〜1023の値をとることができるが、ソフトウェアは0〜99となっている。
このプログラムでは、ソフトもハードも99までとしているので、ソフトは最大値までいっているが、ハードによる PWM は 1/10 程度の値にしかなっていない。
そのため、ハードウェアによる PWM 生成の LED は暗く見えている。
ソフトウェアによる PWM は「softPwmCreate(SOFT_PWM_PIN, 0, 100);」により初期化している。この中で初期値(最小値?)を0、レンジを100にしている。
レンジが100ということで、とりうる値は0〜99でしょう。100はとりえない。
なので、「softPwmCreate(SOFT_PWM_PIN, 0, 1024);」と、100を1024にしてしまうだけでいけちゃう? 周期が長くなってしまう?


Better PWM on the Raspberry Pi では、DMA を使った PWM 生成を考えている。
ここでは、DMA を使って、8ch で 2000 ステップの PWM 出力を CPU パワーをほとんど使わずに生成していると記述されている。サンプルコードは無いけれど。
ほかには・・・
RPIO.PWM: Precise PWM via DMA for servos and more (1µs res) ここも Python ラッパあり。

PWM via DMA for the Raspberry Pi Python で DMA PWM。
Raspberry Pi PWM via DMA ここはよくわからない。



というわけで、RPIO のインストール。「python-setuptools」をインストール済みであれば1行目は不要。
$ sudo apt-get install python-setuptools
$ sudo easy_install -U RPIO
でも、これって python 動かすのに root 権限が必要?

easy_install ではなく、ソースからインストールする場合はこれ。
$ git clone https://github.com/metachris/RPIO.git
$ cd RPIO
$ sudo python setup.py install
そのあと、python インタプリタを立ち上げて・・・
$ sudo python
>>> from RPIO import PWM
>>> servo = PWM.Servo()
>>> servo.set_servo(18, 1200)
などと、する。ここで、18とあるのは GPIO の番号で、1200 とあるのはパルス幅uSec。
パルス幅は0から19990までの値をとることができる。10uSec 単位でパルス幅を決めることができる。
止めるときはこれ。
>>> servo.stop_servo(18)

ピン番号との対応表。右端の GPIO の番号で PWM のビットというかチャネルを決める。
set_servo(18, 10000) ならGPIO18で、bit 1、P1のピン12から出力されている。


bit
P1 pin
name
0
11
GPIO17
1
12
GPIO18
2
13
GPIO27
3
15
GPIO22
4
16
GPIO23
5
18
GPIO24
6
22
GPIO25
7
7
GPIO04
8
3
GPIO02
9
5
GPIO03
10
24
GPIO08
11
26
GPIO07
12
19
GPIO10
13
21
GPIO09
14
23
GPIO11
15
8
GPIO14
16
10
GPIO15




P5 pin

17
3
GPIO28
18
4
GPIO29
19
5
GPIO30
20
6
GPIO31

0 件のコメント:

コメントを投稿