サーボモーターを使ってみた-その2(ハードウェアPWM編)

前回に引き続き、サーボモータの制御をRaspberryHabuで試します。
今回はハードウェアPWMを試しましょう。

DSC01521

基本的にはソフトウェアPWMの回と同じつなぎ方ですが、RaspberryPiのハードウェアPWMが使えるのはRaspberryHabuのデジタル出力1番ピンにつながっているところだけなので白(PWM)をRaspberryHabuのデジタル出力1ピン、赤をVCC、黒をGNDにつなぎました。
ソフトウェアPWMの信号は0から99の値で設定しますが、ハードウェアPWMの信号は0から1023の値で設定します。

/*
servo-hardpwm.c
Lisence CC0.
*/

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"
int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
   pinMode(1, PWM_OUTPUT);
   while(1){
    pwmWrite(1,700);
    printf("channel 1:pwm 70\n");
    sleep(2);
    pwmWrite(1,100);
    printf("channel 1: pwm 10\n");
    sleep (2);
  }
}

今回はWiringPiライブラリの関数であるhardPWMを使ってみました。

pinModeでPWM出力の設定をし、pwmWriteで出力します。

DSC01522PWM出力約10%時

DSC01523PWM出力約70%時

動いているのがわかります。基本的にはソフトウェアPWMと同じです。出力を0→1023に変えていくと右回りに角度が変化します。
ソフトウェアPWMはCPUの負荷によってはガタ付きなどが発生するため、安定して動かすにはハードウェアPWMのほうが望ましいと思われます。

次回はソフトウェアPWMとハードウェアPWMを比較してみます。

モーター制御してみた

今回はDCモータをRaspberryPiで制御してみます。ミニ四駆でおなじみのFA130モータを用意しました。

DSC01529

DCモータの回転を制御しながら駆動させる回路にはトランジスタやFETを使ったフルブリッジ回路がよく使われます。今回はフルブリッジ回路が内蔵されているモータドライバIC TA7291P を使いました。

DSC01530

TA7291Pは小電力モータ用で内部にフルブリッジと保護回路が入っています。このICを使うとDCモータの「正転」、「逆転」、「ブレーキ」、「ストップ」、「電圧の制御」の制御がでます。このICで使えるモータの電流は平均0.4A、ピーク1.0A、モータ電圧は20Vまで、ICの電源は4.5Vから20Vです。
モータドライバICと電池、モータをつなぎます。画像では電池が入っていませんが、実験ではアルカリ単3乾電池を2本使用しました。

DSC01527

モータードライバICへの信号はすべてRaspberryHabuのデジタル出力につなぎます。TA7291Pの4ピンに電圧をかけたりPWM信号を送ることでモータの速度を調整できます。今回は電圧制御ではなくPWM信号を試します。ハードウェアPWMを使うのでRaspberryHabuのデジタル出力1ピンにICのモータ出力制御ピン(ICの4ピン)、モータ回転制御ピン(ICの5ピンと6ピン)はRaspberryHabuのデジタル出力2ピンと3ピンにつなぎます。ICの5ピンにLOW、6ピンにHIGHを入力すると正転、5ピンにHIGH、6ピンにLOWを入力すると逆転、両方にHIGHを入力するとブレーキ、両方にLOWを入力すると停止の信号を送ることができます。

DSC01528

とりあえず回すだけのプログラム。PWM信号は約50%(512)に設定しました。正転と逆転を切り替えるときに一度停止した状態を作らないと逆起電力で回路が壊れることがあるので注意です。

 // Licence CC 0 ( Public Domain )

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"

#define MOTORPWM 1
#define MOTOROUT1 2
#define MOTOROUT2 3

int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
  pinMode(MOTOROUT1,OUTPUT);
  pinMode(MOTOROUT2,OUTPUT);
  pinMode(MOTORPWM,PWM_OUTPUT);

  digitalWrite(MOTOROUT1,0);
  digitalWrite(MOTOROUT2,0);
  digitalWrite(MOTORPWM,0);
  while(1){
    printf("foward\n");
    digitalWrite(MOTOROUT1,1);
    pwmWrite(MOTORPWM,512);
    sleep(5);
    pwmWrite(MOTORPWM,0);
    digitalWrite(MOTOROUT1,0);
    usleep(50000);
    printf("back\n");
    digitalWrite(MOTOROUT2,1);
    pwmWrite(MOTORPWM,512);
    sleep(5);
    pwmWrite(MOTORPWM,0);
    digitalWrite(MOTOROUT2,0);
    printf("STOP\n");
    sleep(5);
  }
  return 0;
}

DSC01531正転

DSC01532逆転

DSC01533停止

動きました。正転5秒、一瞬停止、逆転5秒、停止5秒の順で動いています。

モータ出力制御ピンに5V、モータ用電源に3.1Vの電圧をかけた場合、モータへの出力電圧は1.36Vでした。データシート(8p,左上の表)にもありますがIC内部ロスがあるため、モータ用電源はそのロスも加味したうえで決定する必要があります。

電池を直接モータにつなぎ可変抵抗などで電圧を変化させることで制御することもできますが、その場合電圧が下がるとトルクが小さくなるという欠点があります。TA7291Pを使って電圧で速度を制御する場合、制御端子にかける電圧とモータ用電源の電圧との差はIC内で熱に変換されるため、電圧差が大きければ大きいほどICの発熱が増えてしまうという欠点があるため制御用電圧はモーター電圧よりも少なくする必要があります。
それに対し、PWMで制御するとモータのトルクの変化が少ないことやモータとの電圧が少ないのでICの発熱も抑えることができるという利点があります。
いっぱい使えば、ロボットにも応用できます。無線を使えばラジコンカーも作れそうですね。

サーボモータを使ってみた-その1(softPWM編)

今回はサーボモータの制御をRaspberryHabuで試してみます。 用意したサーボモータは秋月電子通商で購入した台湾GWS社のPIC+F/BB/F(¥900)です。電圧は4.8から6V、トルクは0.79kg/cm(4.8V)から0.90kg/cm(6V)、スピードは0.12sec/60deg(4.8V)から0.10sec/60deg(6V)です。端子がフタバ配列(でっぱりのある端から白:PWM,赤:VCC,黒:GND)になっています。 DSC01516s 今回は白(PWM)をRaspberryHabuのデジタル出力1ピン、赤をVCC、黒をGNDにつなぎました。サーボにかかる負荷が大きい時や電圧を安定させたい場合は電源を別途用意することをおすすめします。 RaspberryPiで使えるPWMにはハードウェアで発生させる方法とソフトウェアで発生させる方法がありますが、今回はソフトウェアPWMを試します。

/*
servo-softpwm.c
Lisence CC0.
*/

#include "stdio.h"
#include "stdlib.h"
#include "wiringPi.h"


int main()
{
  if (wiringPiSetup() == -1)
    {
      printf("setup error!");
      exit(1);
    }
    softPwmCreate(0,0,100);
  while(1){
    softPwmWrite(0,70);
    printf("channel 0:pwm 50\n");
    sleep(2);
    softPwmWrite(0,10);
    printf("channel 0: pwm 10\n");
    sleep (2);
  }


今回はWiringPiライブラリの関数であるsoftPWMを使ってみました。 softPwmCreateでPWM出力の設定をし、spftPwmWriteで出力します。 DSC01517PWM出力10%時 DSC01518PWM出力70%時 動いているのがわかります。出力を0→100に変えていくと右回りに角度が変化します。 今後このサーボモータといろいろなセンサを組み合わせて試作をしていきたいと思います。

温度計作ってみた

今回は熱電対を使って温度計を作ってみます。

異なる2種類の金属線をつないで、二つの接した部分に温度差を与えると電圧が発生します。この現象をゼーベック効果といいます。熱電対とはこの現象を利用したセンサで、一端の温度が分かれば発生する電圧と既知の金属の特性からもう一方の接点の温度を求めることができます。

絶対的な温度を計る場合は熱電対の測定に使う接点を温接点、端子側を基準接点とし、その温度(基準接点温度)を測り測定点の温度を求める必要があります。基準接点温度を測定するときはサーミスタや測温抵抗体などを使います。

試作には秋月電子で購入したK型熱電対ステンレス管タイプを使いました。この熱電対は-200℃~+600℃の広範囲の温度を測定することができます。温度差1℃当たり約40.7μVの起電力が発生します。

RaspberryHabuのアナログポートに入力するには電圧変化が小さすぎるのでオペアンプで増幅します。一般的に信号を増幅するためによく使われるLM358では誤差が大きすぎるので今回は精度の高いオペアンプNJM2119Dの1回路分を使い、1kΩと100kΩの抵抗で100倍に増幅し、RaspberryHabuのアナログ1番ピンに入力しました。NJM2119Dは秋月電子で手に入ります。

2V2A6612

熱電対の端子は商品では樹脂の端子がついていますが、ブレッドボードに指すために分解してあります。ケーブルは単芯なので被膜を取るだけでブレッドボードにさせます。
写真は2か所の温度を計るため熱電対を2つ使い、2チャンネル分の回路を作っています。

熱電対の出力はアナログなのでRaspberryHabuBasicのアナログ入力ピンからMCP3008を通してSPIでRaspberryPiに入力します。
以下のコードはサーミスタも使い室温を出したうえで熱電対で測定した結果の温度差を足して計測対象の温度を出しています。

 // thermocouple.c sample program for RaspberryHABU
 // Licence CC 0 ( Public Domain )
 
 
 #include "stdio.h"
 #include "stdlib.h"
 #include "wiringPi.h"
 #include "unistd.h"
 #define SPIBUFFSIZE 256
 #define THERMISTORCHANNEL 7
 #define THERMISTOR 10000 // 10k ohm
 #define B 3380 // 
 #define DIVR 10000 // 10k ohm
 
 unsigned char spidata[SPIBUFFSIZE];
 int MCP3008Read( int channel ){
   int spireturn,data;
   spidata[0]= 1; 
   spidata[1]= ( 0x80 | channel << 4 )  ;
   spidata[2]= 0;
   spireturn = wiringPiSPIDataRW( 0, spidata , SPIBUFFSIZE );
   data = ((spidata[1]&3) << 8) + spidata[2];
 return(data);
 }
 
 int main()
 {
   int spiresult,spiresult7;
   double thermistor_r,baseTemp,TCTemp,t1;
   if ( -1 ==  wiringPiSPISetup(0,1000000) )
   {
     printf("SPI setup error!");
     exit(1);
   }
   while (1){
     spiresult7=MCP3008Read(THERMISTORCHANNEL);
     thermistor_r = ( DIVR * spiresult7 )/ (1024 -spiresult7 );  // thermistor is lower
     t1 =   log( thermistor_r / THERMISTOR ) ;
     baseTemp = ((298*B) / ( B + ( 298 * t1 ))) - 273;
   
     spiresult=MCP3008Read(0);
     TCTemp = (3.3/1024.0*(double)spiresult*1.010)/0.00407;
 
     printf("temp: %3.f c  (room temp: %3.f c : A0 value0 %d)\n",TCTemp+baseTemp,baseTemp,spiresult);
     sleep(10);
   }
 
 }

入力した値はAD変換され10bitのデータとしてRaspberryPiに入力されます。その値は3.3Vを10bit(1024)分割された値なので1Vあたりの数値を出し、それを40.7μVで割ることで温度差を出しています。NJM2119Dは5V電源を試用していますが、出力は4V程度までしか出ないため、1.01をかけて補正してあります。

上記のプログラムとは出力が違いますが、別の実験で熱電対と基準接点温度を測定するためにサーミスタを使ったときの出力結果は以下のようになりました。この実験ではコップのお湯の温度を測ってみました。

IMG_20140326_141717

今回使ったK型熱電対は対温度性が1250℃(樹脂の端子カバーを残して使う場合は600℃)と高いのでオーブン作ったりリフロー機作ったりできそうですね。