上位に戻る リニアモータ 自作 初版2025/9/28

意味なく、リニアモータを作ってみました。使い道今のところ無いです
パイプ内に、磁石を配置し、パイプの回りに、磁石を配置して、パイプを左右に動かしてみました。
制御には、ESP32を使ってみました

FETスイッチで、吸引のみの力で動作させています 右方向のみの動作です 3サイクルです



モータドライバを購入して反発もできるようにしました PWMで強度も操作できるようにしました 左右の方向に
動作できるように構成、6サイクルの予定でしたが、諸所の問題で出来ず、3サイクルで動かしています
仮称 [猫あそびボール射出機]
家内に実演して見せたら、「あほちゃうか!遊ぶわけないやろ」と一蹴されました。まあゴミになってしまいました







  1. どんな構成
    ブラシレスDCモータの動作原理を参考にしました。
    https://jp.aspina-group.com/ja/learning-zone/columns/what-is/014/

    磁石の位置をホールセンサーで検知して、コイルを切り替えて推力をえる 吸引と、反発を利用して6サイクルで切り替える
    イメージです。
    悩ましいのが、コイルの寸法と、磁石の間隔です。



    当初の6サイクルの予定


  2. 使った部品
    直径6mm
    厚さ3mm
    の磁石
    3個連結
    して
    使っています
    アルミパイプ
    内径6mm
    長すぎるの
    で半分に
    切断しまし
    た
    0.2mmの
    ウレタン線
    10mで、
    おおよそ
    5.5Ω
    スイッチタイプ
    アナログタイプ
    どちらか
    悩んだが
    失敗ス
    ESP32
    WROOM


  3. 作った詳細
    ■コイル
     直径10mmのアルミパイプに10mのポリウレタン線を巻きました。0.2mmで、10mで、5.5Ω モータドライバが2Aなので、
     10Vを印加しています
     12Vを印加すると、ホール素子が、コイルの磁界に反応して誤動作しました


    テスト的に作っているので、かなり適当ス

    ■回路図


    プログラムがすっきりするように、PWM信号用に、Enableの信号ピンを使いましたが、ピン数減らすならIN信号にPWMを入れる方法
    もあります

    ■外見
    モータドライバを持っていなかった
    ので、FETスイッチで、吸引のみ
    でテストしました
    吸引のみでも動作はしました
    力は弱いです
    完成したところ


  4. 問題点
    ■6サイクルに出来ませんでした
    最大の要因は、ホールセンサーの感度が良すぎてかなり手前で反応してしまいタイミングが合わない
    磁石からセンサーを離して、感度を下げると、コイルの励磁の影響を受けやすくなる
    で、センサーの感度を下げるのに、ニッケルストラップテープを持っていたので、切って巻いてみました
    (シールド効果) 感度は、バッチリいい感じになったのですが、ニッケルテープが磁化してしまい
    ヒステリシスが発生しました トホホ もううまく行かないぜ!



    ■右方向に比べて左方向への動きが力が弱い
     ホールセンサーには、極性があり若干タイミングがずれてしまう
     双極性のセンサーもあるみたいですが、どうだろうタイミング取れるか要検討ですね
     左用にセンサーを配置するかですね

    ■3サイクルのタイミング
    右方向


    左方向


    ■作り直すとしたら
    ホールセンサーの立ち上がり立下りで、チャタリングが発生するので、回避するのに、プログラムで、キャンセルタイミング
    取るか、回路で回避するか必要です

    コイルの磁界も強くしたいので、ホールセンサーの感度を調整できるものにする。アナログのホールセンサーとコンパレータ
    で感度調整できるものが売られていました


    まあアナログホールセンサーを直接ESP32で、A/D変換して判別する方法もあるかとは思います・・・・。
    現状のプログラムは、ホールセンサーの動作で割り込みを発生させています

    長いパイプを動かすには、両サイドにコイルを配置したほうがいいです 今回片側しか配置していないので、コイル内は、磁気の
    力で、摩擦無いですが、対側の受けパイプは、アルミパイプの重力で、摩擦が発生します

  5. 参考プログラム
    ホールセンサーの信号で、割り込みを発生させて 割り込み処理で、コイルを励磁させています 当初、割り込み関数の中に
    処理を詰め込んでいたのですが、チャタリングが発生して割り込み頻発でクラッシュすることがあり、loop内に処理を移しました
    割り込みの意味あるんかと、突っ込まれそうですが・・・・・。
    チャタリングですが、3サイクルなので、次のホールセンサーが感知するまで、コイルの励磁を保持させているので、チャタリング
    で、コイルの励磁がバタバタすることはありません

    配列変数 datacで、動作内容を記述しています  {方向,移動距離(磁石の数),PWMの値0〜255)}


    #include <Arduino.h>

    #define holes1   27 //ホールセンサー1
    #define holes2   14 //ホールセンサー2
    #define holes3   13 //ホールセンサー3
    #define sw1      12 //起動スイッチ
    #define md1_1    23 //モータドライバ2 IN1 コイル2
    #define md1_2    22 //モータドライバ2 IN2 コイル2
    #define md1_3    19 //モータドライバ2 IN3 コイル3
    #define md1_4    21 //モータドライバ2 IN4 コイル3
    #define md2_1    18 //モータドライバ1 IN1 コイル1
    #define md2_2    17 //モータドライバ1 IN2 コイル1

    const int cpwm1=A4;//GPIO32 モータドライバ2 ENA
    const int cpwm2=A5;//GPIO33 モータドライバ2 ENB
    const int cpwm3=A18;//GPIO25 モータドライバ1 ENA

    volatile int houkou=1; //0で右 1で左
    volatile int sensorEvent = 0;
    int flgg=0;
    int countt=0;
    int countc=0;
    int datac[6][3]={{0,3,200},{1,3,200},{0,3,200},{1,2,200},{1,2,200},{0,5,255}}; //動作データ{方向,距離,PWM}
    int datcount=0;
    int teishi=1; //1で停止 0で起動
    void setup() {
      // put your setup code here, to run once:
        // シリアル通信を開始
      Serial.begin(115200);
      pinMode(holes1,INPUT_PULLUP);
      pinMode(holes2,INPUT_PULLUP);
      pinMode(holes3,INPUT_PULLUP);
      pinMode(sw1,INPUT_PULLUP);
      attachInterrupt(holes1, ss1, FALLING);
      attachInterrupt(holes2, ss2, FALLING);
      attachInterrupt(holes3, ss3, FALLING);
      pinMode(md1_1, OUTPUT);
      pinMode(md1_2, OUTPUT);
      pinMode(md1_3, OUTPUT);
      pinMode(md1_4, OUTPUT);
      pinMode(md2_1, OUTPUT);
      pinMode(md2_2, OUTPUT);

      ledcAttach(cpwm1, 12800,8);
      ledcAttach(cpwm2, 12800,8);
      ledcAttach(cpwm3, 12800,8);

    }

    void ss1(){
      sensorEvent = 1;
    }
    void ss2(){
      sensorEvent = 2;
    }
    void ss3(){
      sensorEvent = 3;
    }

    void kidou(){
      if(digitalRead(sw1)==LOW){
        if (teishi==1){
          teishi=0;
          datcount=0;
          flgg=0;
          countt=0;
          houkou=datac[datcount][0];
          migi(2,200);
        }
      }
    }


    portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
    void loop() {
      kidou();
      if(teishi==1){
        digitalWrite(md2_1, LOW);digitalWrite(md2_2, LOW);//コイル1停止
        digitalWrite(md1_3, LOW);digitalWrite(md1_4, LOW);//コイル2停止
        digitalWrite(md1_1, LOW);digitalWrite(md1_2, LOW);//コイル3停止
      }
      int ev = 0;
      int cc=128;
      portENTER_CRITICAL(&mux);
      if (sensorEvent != 0) {
        ev = sensorEvent;
        sensorEvent = 0;
      }
      portEXIT_CRITICAL(&mux);
      if(teishi==0){
        if (ev != 0) {
          cc=datac[datcount][2];
          Serial.println(datac[datcount][1]);
         if (datac[datcount][1]>=countt){
            if (houkou==0) {
             migi(ev,cc);
           } else {
              hidari(ev,cc);
           }
         }else{
            datcount=datcount+1;
            if(datcount>5){teishi=1;}
            houkou=datac[datcount][0];
            countt=0;
            flgg=0;

          }
        }
      }
    }


    void migi(int ev,int cc){
      ledcWrite(cpwm1,cc);
      ledcWrite(cpwm2,cc);
      ledcWrite(cpwm3,cc);
      switch(ev){
        case 1: digitalWrite(md2_1, HIGH);digitalWrite(md2_2, LOW);//コイル1正転
                digitalWrite(md1_3, LOW);digitalWrite(md1_4, HIGH);//コイル2逆転
                digitalWrite(md1_1, LOW);digitalWrite(md1_2, LOW);//コイル3停止
                if(flgg==0){flgg=1;}
                break;
        case 2: digitalWrite(md1_3, HIGH);digitalWrite(md1_4, LOW);//コイル2正転
                digitalWrite(md1_1, LOW);digitalWrite(md1_2, HIGH);//コイル3逆転
                digitalWrite(md2_1, LOW);digitalWrite(md2_2, LOW);//コイル1停止
                if(flgg==1){
                  flgg=0;
                  countt=countt+1;
                }
                break;
        case 3: digitalWrite(md1_1, HIGH);digitalWrite(md1_2, LOW);//コイル3正転
                digitalWrite(md2_1, LOW);digitalWrite(md2_2, HIGH);//コイル1正転
                digitalWrite(md1_3, LOW);digitalWrite(md1_4, LOW);//コイル2停止
                break;
      }
    }

    void hidari(int ev,int cc){
      ledcWrite(cpwm1,cc);
      ledcWrite(cpwm2,cc);
      ledcWrite(cpwm3,cc);
      switch(ev){
        case 1: digitalWrite(md2_1, LOW);digitalWrite(md2_2, HIGH);//コイル1逆転
                digitalWrite(md1_3, HIGH);digitalWrite(md1_4, LOW);//コイル2正転
                digitalWrite(md1_1, LOW);digitalWrite(md1_2, LOW);//コイル3停止
                break;
        case 2: digitalWrite(md2_1, LOW);digitalWrite(md2_2, LOW);//コイル1停止
                digitalWrite(md1_3, LOW);digitalWrite(md1_4, HIGH);//コイル2逆転
                digitalWrite(md1_1, HIGH);digitalWrite(md1_2, LOW);//コイル3正転
                if(flgg==1){
                  flgg=0;
                  countt=countt+1;
                }
                break;
        case 3: digitalWrite(md2_1, HIGH);digitalWrite(md2_2, LOW);//コイル1正転
                digitalWrite(md1_3, LOW);digitalWrite(md1_4, LOW);//コイル2停止
                digitalWrite(md1_1, LOW);digitalWrite(md1_2, HIGH);//コイル3逆転
                if(flgg==0){flgg=1;}
                break;
      }

    }






    以上間違い等ありましたら、以下ご意見箱にお願いします

   

    ご意見箱