PCからステッピングモータを制御

更新日 2021-10-01 (金) 14:58:35
作成日 2021年9月28日

PC上のプログラムからステッピングモータ(+28BYJ-48)とドライブ用IC(ULN2003)の回転を制御する

仕様

  1. コントロール画面のボタンを押すことで、右回転、左回転をする
  2. 初期ボタンを押すと電源投入時の個所に戻る
  3. PC上のプログラムの開発はProcessingを使用する

Ardiunoプログラム

内容

初期設定

p_countに0をセットする。これが回転位置を示す。0が起点

シリアルから文字「r」が送られると、右回転に設定
p_countが-2048になるまで転変数num_stepを-1(右回転)にセットする
PIN13をHighにしてPWB上のLEDを点灯
p_countが-2048になるまで(右に1回転するまで)デクリメントする

シリアルから文字「l」が送られると、左回転に設定
p_countが2048になるまで転変数num_stepを1(右回転)にセットする
PIN13をHighにしてPWB上のLEDを点灯
p_countが2048になるまで(右に1回転するまで)インクリメントする

シリアルから文字「s」が送られると、num_stepを0(回転停止)にセットする
PIN13をLowにしてPWB上のLEDを消灯
モータに電流を流さないように、モータ制御PINをLowにする

シリアルから文字「a」が送られると、初期位置まで戻す
初期位置から回転位置を示すp_count分とは逆方向に回す
戻すスピードは通常回転速度の4倍に設定
初期位置に戻ったら、モータに電流を流さないように、モータ制御PINをLowにする

指定スピード(rpm)と、指定ステップ数(num_step)でモータを動かす
「s,a」はnum_step=0のため動かない

回転位置(p_count)が3ステップより大きく変化したときシリアルポートにデータを送信する

電源OFF時のため、現在の位置(起点からのステップ数)をEEPROMに2Byte書きこんでおく

プログラム

  • M_CTRL2.ino
//---------------------------------------------
// ステッピングモータの制御2
// 左右にボタンで回転
//     ( Rev. 002 )
//
//   2021/09      DE JE2ISM
//----------------------------------------------
//ライブラリインクルード
#include <Stepper.h>
#include <EEPROM.h>

#define DATA_PIN 13 //回転中の状態表示

// ステッピングモータが1回転するのに必要なステップ数を定義
//2相励磁方式で制御するため2048 step で1回転
const int MOTOR_STEPS = 2048; 

//1回転あたりのステップ数と接続するピンの設定
Stepper myStepper(MOTOR_STEPS, 8, 10, 9, 11);

char data = 's'; //回転方向 r:右 l:左 s:停止
int num_step = 0 ; //一命令のステップ数
String str_num_step;

//回転したステップ数
int p_count;
int old_p_count;
String str_p_count;

int i;
int interval = 50; //シリアルに送信するタイミングのステップ数のインターバル
int rpm = 3;  //1分あたりの回転数

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode( DATA_PIN, OUTPUT );
  myStepper.setSpeed(rpm); // 1分の回転スピードの設定 rpm(1分あたりの回転数)
  
  //ポジションをEEPROMから2byte読み出し
  EEPROM.get(0x000, p_count);
  str_p_count =String(p_count);

  Serial.print(str_p_count);
  old_p_count = p_count;
}

void loop() {
  // put your main code here, to run repeatedly:
    
    if (Serial.available() > 0) {
       data = Serial.read();
    }
  //モータの制御
  //右回転
    if (data == 'r'){     
        num_step = -1;
        digitalWrite(DATA_PIN, HIGH);     

        if (p_count > -2048 ) {
           p_count--;
          rpm = 3;          
        }else{
          num_step = 0;
        }
    }
    
    //左回転
    if (data == 'l'){    
        num_step = 1;
        digitalWrite(DATA_PIN, HIGH);

        if (p_count < 2048 ){
          p_count++; 
           rpm = 3 ;
        }else{
          num_step = 0;   
        }
    }
    
    //停止
    if (data == 's'){   
        num_step = 0;
        digitalWrite(8,  LOW); 
        digitalWrite(9,  LOW); 
        digitalWrite(10, LOW); 
        digitalWrite(11, LOW);       
        digitalWrite(DATA_PIN, LOW);
    }
    
    
    //開始点に戻す
    if (data == 'a'){   
        digitalWrite( DATA_PIN, HIGH );
        
        if (p_count != 0 ){
          p_count = -1 * p_count;
          rpm = 12;
          myStepper.setSpeed(rpm);  
          myStepper.step(p_count);
          rpm = 3;
          
        }
        p_count = 0;
        num_step = 0;
        if (p_count == 0) {
          digitalWrite(8,  LOW); 
          digitalWrite(9,  LOW); 
          digitalWrite(10, LOW); 
          digitalWrite(11, LOW);
        }       
        digitalWrite(DATA_PIN, LOW);
      }
    myStepper.setSpeed(rpm);  
    myStepper.step(num_step);  

 // 電源OFF時にポジションを記録
    EEPROM.put(0x000, p_count);//アドレス「0x000」に2byteデータを書き込み
    
    //回転位置をシリアルに転送
    
  //p_countの値が0のときはカウントのインターバルが時間稼ぎにならないので別途待ち時間を設定

  //p_countの値が変わったらシリアル転送
  //「1」では制御プログラム(Windows側)を再起動すと位置表示がうまく表示しない
  //I2Cの通信がおかしくなるのかは不明
   if (abs(old_p_count - p_count) > 3) {
    str_p_count = String(p_count);      
    Serial.print(str_p_count);
    old_p_count = p_count;
  }
}

動作の様子

Step1.png

Processingプログラム

内容

「右回転」ボタンを押し続けるとシリアルに「r」を送り続ける

「左回転」ボタンを押し続けるとシリアルに「l」を送り続ける

「初期位置」ボタンを押し続けるとシリアルに「a」を送り続ける

ボタンを離すとシリアルに「s」を送り続ける

シリアルからデータが送られてくるとその数値(回転位置)を表示する

「シリアルリセット」を押すとシリアルポートのコミュニケーションのリセットを行う
本プログラム起動中にArudinoの電源再投入時シリアルポートのコミュニケーションに不具合が発生するよう。原因不明

プログラム

  • M_CTRL2.pde
//-----------------------------------------------
// ステッピングモータの制御サンプルプログラム2
//
// マウスのDown Up を検出してモータ制御
//
//    2021/09              DE JE2ISM
//------------------------------------------------

import processing.serial.*;

Serial port;

final int X = 40;
final int Y = 100;  
final int W = 100;
final int H = 36;
final int d = 8;

int m_flag = 0; //ボタンを押したら 1 / 離したら 0

String str_p_conut ;  //Arduinoから送られて来るステップ数(文字列)

void setup() {

  size(450, 150); 
  
 //日本が利用できるようにフォント指定
 PFont font = createFont("Meiryo",12);
 textFont(font);


  port = new Serial(this, "COM3", 9600); 
  
  background(255);
  
  fill(192,255,192); 
  rect(20, 5, 350, 20);
  fill(0);
  text("ステッピングモータコントローラ(Rev.002)   DE JE2ISM", 30, 20);
  
 //日本が利用できるようにフォント指定
 font = createFont("Meiryo",20);
 textFont(font);

//右回転ボタン
  fill(0, 255, 255);
  rect(20, 30, 100, 50);
  fill(0);
  text("右" , 20 + 4 * d  , 30 + 4 * d);
  
//左回転ボタン
  fill(90, 255, 128);
  rect(150, 30, 100, 50);
  fill(0);
  text("左" , 150 + 4 * d  , 30 + 4 * d);

//開始点に移動ボタン
  fill(255, 128, 128);
  rect(280, 30, 100, 50);
  fill(0);
  text("初期位置" , 260 + 4 * d  , 30 + 4 * d);
  
 //シリアルポートリセット
 
  fill(255, 128, 0);
  rect(280, 90, 120, 50);
  fill(0);
  font = createFont("Meiryo",12);
  textFont(font);
  text("シリアルリセット" , 260 + 4 * d  , 90 + 4 * d);
  font = createFont("Meiryo",20);
  textFont(font);

}

void draw() {    

 
  if( mousePressed == true ){
  //右回転
      if(mouseX > 20 && mouseX < 120 && mouseY > 30 && mouseY < 80){
       
          right();
          
       
      }
      
    //左回転
       if(mouseX > 150 && mouseX < 250 && mouseY > 30 && mouseY < 80){
       
          left();
          
      }
    //初期の位置に戻す
       if(mouseX > 280 && mouseX < 380 && mouseY > 30 && mouseY < 80){
      
         
          adjust();
      }
     
     //シリアルポートリセット
     //本プログラム起動中にArudinoの電源再投入時シリアルポートのコミュニケーション
     //が不具合になるようなので、リセットを行う
      if(mouseX > 280 && mouseX < 400 && mouseY > 90 && mouseY < 140){
      
          
          port_reset();
      }
    
 }
  
  if( mousePressed == false ){
    
      stop();
      
  }
 
  // Arduino から 送られてくるステップ数を受信と表示
      if (port.available()> 0){  //データを受信したときの処理
        str_p_conut = port.readString();
        
          fill(255);
         rect(X + 100, Y, 1* W, H);
          
          fill(0);
          text (int(str_p_conut), X + 100  + d, Y + d *  3);
        
          // text ("JE2ISM", X + 100 +  d, Y + d * 3);        
      
        //画面描画のための時間待ち 適当
        //if (m_flag == 0) delay( 1000 );          
        
      }
     
}  


void right() {
  if (m_flag == 0 ) port.write('r');
  fill(192,255,192); 
  rect(X, Y, W, H);
  fill(0);
  text ("右回転", X + d, Y + d * 3);
  m_flag = 1;
}

void left() {
  if (m_flag == 0 ) port.write('l');
  fill(192,255,192);
  rect(X, Y, W, H);
  fill(0);
  text ("左回転", X + d, Y + d * 3);
  m_flag = 1;
}

void adjust() {
  if (m_flag == 0 ) port.write('a');
  fill(192,255,192);
  rect(X, Y, W, H);
  fill(0);
  text ("初期位置", X + d, Y + d * 3);
  m_flag = 1;
}

void port_reset(){
   port.clear(); 
   port.stop();
   port = new Serial(this, "COM3", 9600);
}

void stop() {
  if (m_flag == 1 ) port.write('s');
  fill(192,255,192);
  rect(X, Y, W, H);
  fill(0);
  text ("停止",  X + d, Y + d * 3);
  
  m_flag = 0 ;
}

起動画面

コントローラ.png

注)ボタンは描画しているので押してもボタンに変化がないので押したことが分かりにくい(手抜きプログラム)

参考

  • EEPROM関数

添付ファイル: fileコントローラ.png 2件 [詳細] fileStep1.png 2件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-10-01 (金) 14:58:35 (15d)