スポンサーサイト

上記の広告は1ヶ月以上記事の更新がないブログに表示されます。
新しい記事を書くことで、こちらの広告の表示を消すことができます。  
Posted by ミリタリーブログ at

2019年05月08日

電子トリガーを作る その4

その3の続き。
ヒューズが飛ぶ問題への対処を行います。
どんな感じに飛ぶというと、撃っていると突然ショートしたようになってヒューズが飛びます。
色々と調べてみるとこういったページを見つけました。
ページに書いてあることによるとアンダーシュートが原因と思われます。


アンダーシュートによって2つのFETが同時にオンになりショートしてしまい、ヒューズが飛んでしまうようです。

そこで対策として、
1.ブートストラップコンデンサの容量を再計算、470μF→47μFへ変更。
2.Vcc端子とCOM端子の間に470μFの電解コンデンサを追加。
3.ゲート抵抗を33Ω→47Ωへ変更。
その他に、バッテリー電圧を測定する分圧抵抗を追加したり
センサー用の電源をマイコンと別にしました。
最終的な回路はこちらです。



マガジンに磁石を仕込んで、これを磁気センサーで検出してボルトストップするようにしました。


ボルトストップはチャージングハンドルを引くことで解除できるようにしています。


プログラムは以下の通り。

//F2000用FCUプログラムVer.1.03
//改訂記録============================================================================
//Ver.1.01 モーターロック保護処理の追加
//Ver.1.02 ボルトストップ時にピストンを前進位置で停止するよう変更
//Ver.1.03 ボルトストップ解除時に発射されてしまう不具合を修正
//入出力ピンの名称変更=================================================================
#define SEMI_SW A0 //セミオートスイッチ
#define VAL_IN A1 //電圧測定入力
#define FULL_SW 4 //フルオートスイッチ
#define SAFETY_SW 2 //セーフティスイッチ
#define CUTOFF_SW 3 //カットオフスイッチ
#define NO_AMMO_SW 6 //残弾無し検知スイッチ
#define COCKING_FOWARD_SW 7 //コッキングハンドル前進検知スイッチ
#define COCKING_BACK_SW 8 //コッキングハンドル後退検知スイッチ
#define MOTOR 9 //モーター制御出力
#define INDICATOR 10 //インジケーターLED
#define LED 13 //マイコンLED
//定数の宣言===========================================================================
const byte PWM = 254; //フルオートサイクル調整用定数、254まで
const unsigned int PRECOCK = 30;//プリコック時間(ミリ秒)
const unsigned int DECOCK = 0; //デコック時間(ミリ秒)
const unsigned int SW_ON = 280; //セミオートスイッチオン閾値
const unsigned int SW_OFF = 90; //セミオートスイッチオフ閾値
const unsigned int CHATA_SEMI = 0; //セミオートスイッチチャタリング防止(マイクロ秒、1/1000ミリ秒)
const unsigned int CHATA_FULL = 5000; //フルオートスイッチチャタリング防止(マイクロ秒、1/1000ミリ秒)
const unsigned int CHATA_CUTOFF = 0; //カットオフスイッチチャタリング防止(マイクロ秒、1/1000ミリ秒)
const bool ON = LOW, OFF = HIGH; //スイッチ用定数、混乱防止のため
const bool SEMI = false, FULL = true; //フル・セミ切り替え用定数
const unsigned int V_R1 = 1000;     //電圧検知VIN側抵抗値(Ω)
const unsigned int V_R2 = 1000;     //電圧検知GND側抵抗値(Ω)
const unsigned int LIMIT_VAL_S = 740; //待機時電圧下限値(V×100)
const unsigned int LIMIT_VAL_M = 610; //稼働時電圧下限値(V×100)
const unsigned int VF = 70; //ダイオード順方向降下電圧値(V×100)
//変数の宣言===========================================================================
volatile int Fire = 0; //発射制御用変数
volatile unsigned int Semi_Sw = 0; //セミオートスイッチ用変数
volatile bool Cutoff = LOW, Old_Cutoff = LOW; //カットオフセンサー用変数
volatile bool SemiTrg = OFF, Old_SemiTrg = OFF; //セミオート処理用変数
volatile bool FullTrg = OFF, Old_FullTrg = OFF; //フルオート処理用変数
volatile bool Shot_Mode = SEMI;//フル/セミ切り替え用変数
volatile bool No_Ammo = LOW;//残弾無し検知用変数
volatile bool Bolt_Stop = false;//ボルトストップ処理用変数
volatile bool Cocking_Fowad = LOW;//コッキングハンドル前進検知用変数
volatile bool Cocking_Back = LOW;//コッキングハンドル後退検知用変数
volatile bool Fast_Shot = true;//ファストショット処理用変数
bool Battery_Low = false;//バッテリー低下処理用変数
float Vcc = 0; //基準電圧(V)
unsigned int Val = 0;//測定電圧(V×100)
unsigned long Time = 0, Old_Time = 0; //電圧測定時間記録(ミリ秒)
unsigned long M_Time = 0 ,Old_M_Time = 0; //モーター駆動時間記録(ミリ秒)
//セットアップ=========================================================================
void setup() {
//入出力ピンの設定=====================================================================
  pinMode(FULL_SW,INPUT);
  pinMode(CUTOFF_SW,INPUT);
  pinMode(NO_AMMO_SW,INPUT);
  pinMode(COCKING_FOWARD_SW,INPUT);
  pinMode(COCKING_BACK_SW,INPUT);
  pinMode(SAFETY_SW,INPUT);
  attachInterrupt(digitalPinToInterrupt(SAFETY_SW),SAFETY_MODE,LOW);
  pinMode(LED,OUTPUT);
  pinMode(INDICATOR,OUTPUT);
//起動処理============================================================================
  digitalWrite(INDICATOR,HIGH);
  analogWrite(MOTOR,0);
  delay(1000);             //1秒待つ
}
//メインプログラム====================================================================
void loop() {
  digitalWrite(INDICATOR,LOW);
  Time = millis();        //現在の時間を取得(バッテリー電圧測定用)
  M_Time = millis();      //現在の時間を取得(モーターロック保護処理用)
//現在の各スイッチの状態を検知========================================================
  Cutoff = digitalRead(CUTOFF_SW);
  Semi_Sw = analogRead(SEMI_SW);
  /*セミオートスイッチに光センサーを使うため
   *オン・オフの処理を追加
   */
  if(Semi_Sw >= SW_ON){
    SemiTrg = ON;
    /*光センサーの数値が定数SW_ONの閾値以上の場合
     *セミオートスイッチをオンとする
     */
  }
  if(Semi_Sw <= SW_OFF){
    SemiTrg = OFF;
    /*光センサーの数値が定数SW_OFFの閾値以下の場合
     *セミオートスイッチをオフとする
     */
  }
  FullTrg = digitalRead(FULL_SW);
  No_Ammo = digitalRead(NO_AMMO_SW); 
  Cocking_Back = digitalRead(COCKING_BACK_SW);
   
  //カットオフスイッチの状態をLEDで表示
  if(Cutoff == HIGH){
    digitalWrite(LED,HIGH);
  }
  if(Cutoff == LOW){
    digitalWrite(LED,LOW);
  }
//モーター動作処理==================================================================== 
  if(Fire >= 1){
    //変数Fireが1以上のときモーター作動
    switch (Shot_Mode == FULL){
    //モーターの出力変更
      case FULL:
        if(Fast_Shot == true){
          analogWrite(MOTOR,254);
        }
        else{
          analogWrite(MOTOR,PWM);
        }
        break;
        /*フルオート時、最初の1発は最大出力
         *それ以降、変数PWMの値の出力
         */
        default:
        analogWrite(MOTOR,254);
        //セミオート時、最大出力
      }
//モーターロック保護処理================================================================
      while(M_Time - Old_M_Time >= 200){
        analogWrite(MOTOR,0);
        digitalWrite(INDICATOR,HIGH);
        delay(100);
        digitalWrite(INDICATOR,LOW);
        delay(100);
        /*トリガーが押されてから、または
         *カットオフスイッチを検出してから200ミリ秒以上
         *新たなカットオフスイッチを検出しなかった場合
         *モーターを停止し、インジケーターLEDを点滅する
        */
      }
//残弾無し処理=========================================================================
      if(No_Ammo == HIGH){
         Fire = 1;
        /*残弾無し検知スイッチがオンの時、
         *変数Fireの値を1にする
         */
      }
  }
//カットオフ処理=======================================================================
  if(Fire > 1){
    if(Cutoff == HIGH && Old_Cutoff == LOW){
        Fire = Fire - 1;
        Fast_Shot = false;
        Old_M_Time = M_Time;                          //カットオフ検出の時間を記録(モーターロック保護処理用)
        Val = GetVal(analogRead(VAL_IN));             //電圧を取得
        if(Val < LIMIT_VAL_M){                        //稼働時下限値を下回ったとき
          Battery_Low = true;                         //変数Battery_Lowをtrueにし、
          Fire = 1;                                   //変数Fireの値を1にする
        }
        /*カットオフスイッチがLOWからHIGHなったときに
         *変数Fireの数字を1引き、変数Fast_Shotをfalseにする
         */
    }
    Old_Cutoff = Cutoff;
  }
  if(Fire == 1){
    if(Cutoff == HIGH && Old_Cutoff == LOW){
      analogWrite(MOTOR,254);
      Val = GetVal(analogRead(VAL_IN));               //電圧を取得
        if(Val < LIMIT_VAL_M){                        //稼働時下限値を下回ったとき
          Battery_Low = true;                         //変数Battery_Lowをtrueにする
        }
      if(Cocking_Back == ON || No_Ammo == HIGH){
        delay(DECOCK);
      }else{
        delay(PRECOCK);
      }
      analogWrite(MOTOR,0);
      Fire = 0;
      Shot_Mode = SEMI;
      Fast_Shot = true;
      Time = millis();
      Old_Time = Time;                               //モーターが停止した時間を記録(バッテリー電圧測定用)
      /*変数Fireが1に等しい場合、
       *カットオフスイッチがLOWからHIGHになった時に
       *コッキングハンドル検知スイッチがオフの時
       *定数PRECOCKミリ秒後、モーターを停止し、
       *コッキングハンドル検知スイッチがオンの時、
       *あるいは残弾無し検知スイッチがオンの時、
       *定数DECOCKミリ秒後、モーターを停止する
       */
       
      if(No_Ammo == HIGH){
        //残弾無し処理
        Bolt_Stop = true;
        /*残弾無し検知スイッチがオンの時、
         *ボルトストップを行う
         */
      }
    }
    Old_Cutoff = Cutoff;
  }
  if(Cutoff == LOW && Old_Cutoff == HIGH ){
    delayMicroseconds(CHATA_CUTOFF);
    /*カットオフスイッチがONからOFFになったとき
     *チャタリング防止のため
     *定数CHATA_CUTOFFマイクロ秒停止する
     */  
  }
    
//トリガー処理=========================================================================
  /* 変数Bolt_Stopがfalseの時
   * かつ、変数Battery_Lowがfalseの時のみ
   * トリガー入力を受け付ける
   */
  if(Bolt_Stop == false && Battery_Low == false){
//セミオート処理=======================================================================
    if(Fire == 0 ){
      analogWrite(MOTOR,0);
      Shot_Mode = SEMI;
      /*変数Fireの値が0の時
       *セミオート入力を受け付ける
       */
      if(SemiTrg == ON && Old_SemiTrg == OFF){
        Fire = 1;
        Shot_Mode = SEMI;
        /*セミオートスイッチがOFFからONになったとき
         *変数Fireに1を代入する
         */
        Old_M_Time = M_Time;          //セミオートトリガーが押された時間を記録(モーターロック保護処理用)
      }
  
      if(SemiTrg == OFF && Old_SemiTrg == ON){
        delayMicroseconds(CHATA_SEMI);
        /*セミオートスイッチがONからOFFになったとき
         *チャタリング防止のため
         *定数CHATA_SEMIマイクロ秒停止する
         */
      }
    }   
//フルオート処理=======================================================================
    if(SemiTrg == ON && No_Ammo == LOW){
      if(FullTrg == ON){
        Fire = 2;
        Shot_Mode = FULL;
        /*セミオートスイッチがONのままの場合フルオートスイッチを受け付け
         *フルオートスイッチがONになっている間
         *変数Fireに2を代入し続ける
         */
        if(Old_FullTrg == OFF){
          Old_M_Time = M_Time;         //フルオートトリガーが押された時間を記録(モーターロック保護処理用)
         }
      }
      if(FullTrg == OFF && Old_FullTrg == ON){
        Fire = 1;
        delayMicroseconds(CHATA_FULL);
        /*フルオートスイッチがONからOFFになったとき
         *変数Fireに1を代入し、 
         *チャタリング防止のため
         *定数CHATA_FULLマイクロ秒停止する
         */
      }  
    }
  }
//フル・セミオートスイッチの状態を記録する=============================================
  Old_SemiTrg = SemiTrg;
  Old_FullTrg = FullTrg;
//待機時電圧測定処理===================================================================
  if(Fire == 0 && Time - Old_Time >= 500){        //Fireが0かつ、発射後500msおきに
    Val = GetVal(analogRead(VAL_IN));             //電圧を取得
    if(Val < LIMIT_VAL_S){                        //待機時下限値を下回ったとき
      Battery_Low = true;                         //変数Battery_Lowをtrueにする
    }
    Old_Time = Time;                              //測定した時間を記録
  }
//オートカット処理===================================================================== 
  while(Fire == 0 && Battery_Low == true){        //バッテリー電圧の低下を検出した場合、動作を停止し、
    analogWrite(MOTOR,0);                         //インジケーターLEDを点滅する
    digitalWrite(INDICATOR,HIGH);
    delay(100);
    digitalWrite(INDICATOR,LOW);
    delay(1000);
  }
  noInterrupts();
//ボルトストップ処理===================================================================
  while(Bolt_Stop == true){
    Fire = 0;
    SemiTrg = OFF, Old_SemiTrg = OFF;
    FullTrg = OFF, Old_FullTrg = OFF;
    analogWrite(MOTOR,0);
    digitalWrite(INDICATOR,HIGH);
    while(Cocking_Back == OFF){
      Cocking_Back = digitalRead(COCKING_BACK_SW);
    }
    Cocking_Fowad = digitalRead(COCKING_FOWARD_SW);
    if(Cocking_Fowad == ON){
      No_Ammo = digitalRead(NO_AMMO_SW);
      switch(No_Ammo == LOW){
        case true:
          Bolt_Stop = false;
          digitalWrite(INDICATOR,LOW);
          break;
        default:
          Cocking_Back = OFF;
      }
      
    }
    /*コッキングハンドル後退検知スイッチがオンになった後、
     *残弾無し検知スイッチがオフかつ、
     *コッキングハンドル前進検知スイッチがオンになった時、
     *ボルトストップを解除する
     *コッキングハンドル前進検知スイッチがオンになった時、
     *残弾無し検知スイッチがオンの場合はやり直し
     */
  }
  interrupts();
  if(Fire < 0){
    Fire = 0;
  }
}
//セーフティモード=====================================================================
void SAFETY_MODE() {
  analogWrite(MOTOR,0);
  Fire = 0;
  Semi_Sw = 0;
  Cutoff = LOW, Old_Cutoff = LOW;
  SemiTrg = OFF, Old_SemiTrg = OFF;
  FullTrg = OFF, Old_FullTrg = OFF;
  Shot_Mode = SEMI;
  Fast_Shot = true;
  Cocking_Fowad = LOW;
  Cocking_Back = LOW;
  /*セーフティスイッチがオンの時、
   *モーターを停止し、変数の初期化を行う
   */
}
//センサーの値から電圧を計算===========================================================
unsigned int GetVal(unsigned int A){
  float V,Vcc;
  Vcc = cpuVcc(); //基準電圧の取得
  V = A * Vcc / 1024.0 /V_R2 * (V_R1 + V_R2); 
  return(unsigned int)(V * 100.0+ VF);//100倍して整数にする
}
// 電源電圧(AVCC)測定関数==============================================================
float cpuVcc(){
  unsigned long sum=0;
  adcSetup(0x4E);                    // Vref=AVcc, input=internal1.1V
  for(int n=0; n < 10; n++){
    sum = sum + adc();               // adcの値を読んで積分
  }
  return (1.1 * 10240.0)/ sum;       // 電圧を計算して戻り値にする
}
// ADコンバーターの設定================================================================
void adcSetup(byte data){
  ADMUX = data;                      // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);            // ADC イネーブル
  ADCSRA |= 0x07;                    // AD変換クロック CK/128
  delayMicroseconds(500);            // 安定するまで待つ
}
// ADCの値を読む=======================================================================
unsigned int adc(){                  
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);            // AD変換開始
  while(ADCSRA & ( 1 << ADSC) ){     // 変換完了待ち
  }
  dL = ADCL;                         // LSB側読み出し 
  dH = ADCH;                         // MSB側
  return dL | (dH << 8);             // 10ビットに合成した値を返す
}
  

Posted by 名無しのナナシ at 22:24Comments(0)エアガンマイコン

2019年05月04日

電子トリガーを作る その3

その2の続き。
電動ガンへの実装を行います。

今回取り付けるのは、G&GのF2000。
ETUが搭載されていない旧式です。


テスト基板を少し変更した実装基板を作りました。



この基板はメカボックスのスイッチが付いていた所に取り付けました。


マイコン基板はバッテリースペース下に入れました。


トリガースイッチは、元の仕様通りフルセミの選択をトリガーストロークで行い、
セミをフォトリフレクタ、フルをマイクロスイッチで検出するようにしました。



そのほか、セーフティスイッチなどを取り付け。


これで実装完了ですが、テストしたところヒューズが飛ぶ問題が起こったので、
次回はその対処とプログラムの改良を行います。  

Posted by 名無しのナナシ at 22:22Comments(0)エアガンマイコン

2019年04月09日

電子トリガーを作る その2

その1の続き。
今回はセミオート射撃をできるようにします。

セミオート射撃のために、カットオフを検出できるようにします。
セクターギアに開いている穴に直径5mmの磁石を埋め込み、これをホールICで検出します。



メカボックス越しでは磁力を検出できなかったので、穴を開けます。


ユニバーサル基板にホールICを半田付けし、取り付けのためにメカボックスにネジを切りました。



プログラムは以下の通り。
//カットオフテスト用
//入出力ピンの名称変更
#define SEMI_SW 4 //セミオートスイッチ
#define CUTOFF_SW 3 //カットオフセンサー
#define MOTOR 9 //モーター制御出力
#define LED 13 //マイコンLED
//定数の宣言
const int Chata = 0; //チャタリング防止(マイクロ秒)
const bool ON = LOW; //スイッチ用定数、混乱防止のため
const bool OFF = HIGH;
//変数の宣言
int Fire = 0; //発射制御用変数
bool Coff = LOW; //カットオフセンサー用変数
bool Old_Coff = LOW;
bool SemiTrg = HIGH; //セミオートスイッチ用変数
bool Old_SemiTrg = HIGH;

void setup() {
   //入出力ピンの設定
   pinMode(SEMI_SW,INPUT);
   pinMode(CUTOFF_SW,INPUT);
   pinMode(LED,OUTPUT);
}
void loop() {

   //現在の各スイッチの状態を検知
   Coff = digitalRead(CUTOFF_SW);
   SemiTrg = digitalRead(SEMI_SW);
   
   //カットオフスイッチの状態をLEDで表示
   if(Coff == HIGH){
      digitalWrite(LED,HIGH);
   }
   if(Coff == LOW){
      digitalWrite(LED,LOW);
   }

   if(Fire >= 1){
      analogWrite(MOTOR,254); //変数Fireが1以上のときモーター作動
   }
   if(Fire > 1){
      //カットオフ処理
      if(Coff == HIGH && Old_Coff == LOW){
         Fire = Fire - 1;
         /*カットオフスイッチがLOWからHIGHなったときに
          *変数Fireの数字を1引く
          */
     }
     if(Coff == LOW && Old_Coff == HIGH){
        /*物理スイッチを使用する際のチャタリング防止用      
         */
     }
     Old_Coff = Coff;
   }
   if(Fire == 1){
      if(Coff == HIGH && Old_Coff == LOW){
         analogWrite(MOTOR,0);
         Fire = 0;
         /*変数Fireが1に等しい場合、
          *カットオフスイッチがLOWからHIGHになったとき
          *モーターを停止する
          */
      }
      if(Coff == LOW && Old_Coff == HIGH ){
        /*物理スイッチを使用する際のチャタリング防止用      
         */
      }
      Old_Coff = Coff;
   }
    
   if(Fire == 0){
      /*トリガー処理、変数Fireの値が0の時のみ
       *トリガー入力を受け付ける
       */
      analogWrite(MOTOR,0);
      if(SemiTrg == ON && Old_SemiTrg == OFF){
         Fire = 1;
         /*トリガーがOFFからONになったとき
         *変数Fireに1を代入する
         */
      }
      
      if(SemiTrg == OFF && Old_SemiTrg == ON){
         delayMicroseconds(Chata);
         /*トリガーがONからOFFになったとき
          *チャタリング防止のため
          *変数chataマイクロ秒停止する
          */
      }
      Old_SemiTrg = SemiTrg;
   }
    
   if(Fire < 0){
      Fire = 0;
   }
}
動かすとこんな感じ。
  

Posted by 名無しのナナシ at 22:11Comments(0)エアガンマイコン

2019年04月08日

電子トリガーを作る その1

電子トリガーに興味を持ち、色々と調べてみたら
こんなものを見つけて、自分でも作れそうだったので
作ってみることにしました。

以前、ガスガン内蔵ヒーター制御装置を作る際、テストに使ったArduino Nano互換機。
これを使います。
プログラム用のソフト他はこちらを参照してください。


まずはモーターを動かすモータードライバを作ります。
見つけた回路図をほぼそのまま流用して作りました。
詳細についてはこちらを参照してください。


回路図のマイコンVINと出力PINの所をスイッチで繋ぐとそのまま動かせます。


次はマイコンを繋いでテストします。
プログラムは以下の通り。

//モータードライバーテスト用
void setup() {
  pinMode(2,INPUT);
  pinMode(3,INPUT);
  pinMode(4,INPUT);
}

void loop() {
 if(digitalRead(2)==HIGH){
    analogWrite(5,255);   //出力100%、しばらくすると動かなくなる
 }
 else if(digitalRead(3)==HIGH){
    analogWrite(5,123);   //出力50%
 }
 else if(digitalRead(4)==HIGH){
    analogWrite(5,254);   //出力99%、連続使用できる限界
 }
 else{
 analogWrite(5,0);
 }
}
このプログラムをマイコンに書き込み、マイコンのD2,D3,D4にスイッチ、D5に出力PINの所を繋ぎ
動かすとこんな感じです。
このモータードライバーは連続して動かすことができないので、
PWM出力でブートストラップコンデンサを充電する時間を作る必要があります。


次回から電動ガンへの実装を行います。  

Posted by 名無しのナナシ at 23:26Comments(0)エアガンマイコン

2018年11月25日

ガスガン内蔵ヒーター制御装置を作る その4

ヒーター制御装置の実装をします。




マイコンボードは更に小型のものを使います。

Digisparkというマイコンボードの互換機で
マイコンの仕様についてはこちら

このマイコンを使うときは、こちらの手順にしたがって開発環境を インストールする必要があります。
ただ、不具合があるようなのでインストールパッケージ定義をこちらのものに変更してください。

プログラムは入出力関係を少し変更する必要があります。

//ヒーター制御プログラムテスト(Digispark用)
//入出力ピンの名称変更
#define HEATER 0          //ヒーター制御出力
#define Temp_Input A1    //サーミスタ入力
#define Val_Input A2     //電圧測定入力
#define LED 1            //マイコンLED

//定数の宣言
const int V_R1 = 1000;     //電圧測定VIN側抵抗値(Ω)
const int V_R2 = 1000;     //電圧測定GND側抵抗値(Ω)
const int B = 4100;       //サーミスタB定数
const long T_R1 = 10000;   //サーミスタ基準抵抗値[Ω]
const long T_R2 = 10000;    //サーミスタバランス抵抗[Ω]
const int T0 = 298;       //サーミスタ基準温度[K]
const int Limit_Val = 740;    //測定電圧下限値[V×100]
const int Limit_L_Temp = -200,Limit_H_Temp = 400;  //正常温度閾値[℃×10]
const int L_Temp = 280;  //温度下限値[℃×10]
const int H_Temp = 300;  //温度上限値[℃×10]
//変数の宣言
float Vcc = 0;            //基準電圧[V]
int Val = 0;              //測定電圧[V×100]
int Temp = 0;             //測定温度[℃×10]

void setup () {
  //入出力ピンの設定
  pinMode(HEATER, OUTPUT);
  pinMode(LED, OUTPUT);
}

void loop () {
  Vcc = cpuVcc();                                //基準電圧の取得
  Temp = GetTemp(analogRead(Temp_Input));        //温度の取得
  Val = GetVal(analogRead(Val_Input));           //電圧を取得

  while (Temp > Limit_H_Temp || Temp < Limit_L_Temp){   //測定温度が正常な範囲内から外れると
    digitalWrite(HEATER, LOW);                          //ヒーターをオフにし、マイコンLEDが短い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
  }
  while (Val < Limit_Val) {                      //測定電圧が下限値を下回るとヒーターをオフにし、
    digitalWrite(HEATER, LOW);                   //マイコンLEDが長い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(1000);
  }
  
  if (Temp <= L_Temp) {                         //測定温度が下限値以下になると
    digitalWrite(HEATER, HIGH);                 //ヒーターをオンにする
  }
  
  if (Temp >= H_Temp) {                         //測定温度が上限値以上になると
    digitalWrite(HEATER, LOW);                  //ヒーターをオフにする
  }
  delay(100);                                    //0.1s待つ
}
//センサーの値から温度を計算
float GetTemp (int raw) {
  float V_R2 ;
  float R ;
  float t;

  V_R2 = raw * Vcc / 1.024;                                         //バランス抵抗の消費電圧を算出
  R = Vcc * 1000.0 / V_R2 * T_R2 - T_R2;                            //サーミスタの抵抗値を算出
  t = (1000 / (1 / (0.001 * T0) + log(R / T_R1) * 1000 / B) - 273); //温度の計算
  return (int)(t * 10.0);                                           //10倍にして整数にする
}
//センサーの値から電圧を計算
int GetVal(int A) {
  float V;
  V = A * Vcc / 1024.0 / V_R2 * (V_R1 + V_R2);                      //電圧の計算
  return (int)(V * 100.0);                                //100倍して整数にする
}

float cpuVcc() {                     // 電源電圧(AVCC)測定関数
  long sum = 0;
  adcSetup(0x0C);                    // Vref=Vcc, input=internal1.1V
  for (int n = 0; n < 10; n++) {
    sum = sum + adc();               // adcの値を読んで積分
  }
  return (1.1 * 10240.0) / sum;      // 電圧を計算して戻り値にする
}

void adcSetup(byte data) {           // ADコンバーターの設定
  ADMUX = data;                      // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);            // ADC イネーブル
  ADCSRA |= 0x07;                    // AD変換クロック CK/128
  delayMicroseconds (500);             // 安定するまで待つ
}

unsigned int adc() {                 // ADCの値を読む
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);            // AD変換開始
  while (ADCSRA & ( 1 << ADSC) ) {   // 変換完了待ち
  }
  dL = ADCL;                         // LSB側読み出し
  dH = ADCH;                         // MSB側
  return dL | (dH << 8);             // 10ビットに合成した値を返す
}




アナログ入力に干渉するため、
マイコンボードについているツェナーダイオードを取り外しています。



前回試した回路に取り付けて問題ないか確認しました。



実装する回路図はこちら。
ヒューズと電源スイッチ、プログラムを書き込むときに回路を切り離すスイッチを追加しました。





これをケースの中に入れて完成です。

最終的なプログラムはこちら。

//ヒーター制御プログラムVer.1.00(Digispark用)
//入出力ピンの名称変更=================================================================
#define HEATER 0          //ヒーター制御出力
#define Temp_Input A1    //サーミスタ入力
#define Val_Input A2     //電圧測定入力
#define LED 1            //マイコンLED
//定数の宣言===========================================================================
const int V_R1 = 1000;     //電圧測定VIN側抵抗値(Ω)
const int V_R2 = 1000;     //電圧測定GND側抵抗値(Ω)
const int B = 4100;       //サーミスタB定数
const long T_R1 = 10000;   //サーミスタ基準抵抗値[Ω]
const long T_R2 = 10000;    //サーミスタバランス抵抗[Ω]
const int T0 = 298;       //サーミスタ基準温度[K]
const int Limit_Val_S = 740;    //待機時電圧下限値[V×100]
const int Limit_Val_M = 730;    //稼働時電圧下限値[V×100]
const int Limit_L_Temp = -200,Limit_H_Temp = 400;  //正常温度閾値[℃×10]
const int L_Temp = 280;  //温度下限値[℃×10]
const int H_Temp = 300;  //温度上限値[℃×10]
//変数の宣言===========================================================================
float Vcc = 0;            //基準電圧[V]
int Val = 0;              //測定電圧[V×100]
int Temp = 0;             //測定温度[℃×10]
bool Battry_Low = false;  //オートカット用変数
bool Heater_sw = LOW;     //ヒータースイッチ
//セットアップ=========================================================================
void setup () {
//入出力ピンの設定=====================================================================
  pinMode(HEATER, OUTPUT);
  pinMode(LED, OUTPUT);
//起動処理============================================================================
  digitalWrite(HEATER, LOW);
  digitalWrite(LED, LOW);
}
//メインプログラム=====================================================================
void loop () {
//各センサーの数値を取得===============================================================
  Vcc = cpuVcc();                            //基準電圧の取得
  Temp = GetTemp(analogRead(Temp_Input));    //温度の取得
  Val = GetVal(analogRead(Val_Input));       //電圧を取得
//温度異常セーフティ処理===============================================================
  while (Temp > Limit_H_Temp || Temp < Limit_L_Temp){   //測定温度が正常な範囲内から外れると
    digitalWrite(HEATER, LOW);                          //ヒーターをオフにし、マイコンLEDが短い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
  }
//オートカット判定=====================================================================
  switch(Heater_sw == HIGH){
    case true:
      if (Val < Limit_Val_M){          //ヒーターがオンの時、稼働時下限値以下の時、
        Battry_Low = true;             //変数Battry_Lowをtrueにする
      }
      break;
    default:
      if (Val < Limit_Val_S){            //ヒーターがオフの時、待機時下限値以下の時、
        Battry_Low = true;             //変数Battry_Lowをtrueにする
      }
  }
//オートカット処理=====================================================================
  while (Battry_Low == true){         //変数Battry_Lowをtrueの時、ヒーターをオフにし、
    digitalWrite(HEATER, LOW);         //マイコンLEDが長い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(1000);
  }
//ヒーター制御処理=====================================================================
  if (Temp <= L_Temp) {               //測定温度が下限値以下になると
    Heater_sw = HIGH;                 //ヒーターをオンにする
  }
  
  if (Temp >= H_Temp) {               //測定温度が上限値以上になると
    Heater_sw = LOW;                  //ヒーターをオフにする
  }
  digitalWrite(HEATER,Heater_sw);
  delay(100);                         //0.1s待つ
}
//センサーの値から温度を計算===========================================================
float GetTemp (int raw) {
  float V_R2 ;
  float R ;
  float t;

  V_R2 = raw * Vcc / 1.024;                                         //バランス抵抗の消費電圧を算出
  R = Vcc * 1000.0 / V_R2 * T_R2 - T_R2;                            //サーミスタの抵抗値を算出
  t = (1000 / (1 / (0.001 * T0) + log(R / T_R1) * 1000 / B) - 273); //温度の計算
  return (int)(t * 10.0);                                           //10倍にして整数にする
}
//センサーの値から電圧を計算===========================================================
int GetVal(int A) {
  float V;
  V = A * Vcc / 1024.00 / V_R2 * (V_R1 + V_R2);            //電圧の計算
  return (int)(V * 100.0);                                //100倍して整数にする
}
//電源電圧(AVCC)測定関数===============================================================
float cpuVcc() {
  long sum = 0;
  adcSetup(0x0C);                    // Vref=Vcc, input=internal1.1V
  for (int n = 0; n < 10; n++) {
    sum = sum + adc();               // adcの値を読んで積分
  }
  return (1.1 * 10240.0) / sum;      // 電圧を計算して戻り値にする
}
//ADコンバーターの設定===================================================
void adcSetup(byte data) {           
  ADMUX = data;                      // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);            // ADC イネーブル
  ADCSRA |= 0x07;                    // AD変換クロック CK/128
  delayMicroseconds (500);          // 安定するまで待つ
}
//ADCの値を読む==========================================================
unsigned int adc() {
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);            // AD変換開始
  while (ADCSRA & ( 1 << ADSC) ) {   // 変換完了待ち
  }
  dL = ADCL;                         // LSB側読み出し
  dH = ADCH;                         // MSB側
  return dL | (dH << 8);             // 10ビットに合成した値を返す
}

稼働時間を少しでも延ばすため、
ヒーター稼動時と待機時で電圧下限値を変えてあります。



使うときはベルトに取り付けたラジオポーチに入れて使います。  

Posted by 名無しのナナシ at 23:50Comments(0)エアガンマイコン

2018年11月11日

ガスガン内蔵ヒーター制御装置を作る その3

前回テストした回路を実装していきます。
まずはガスガン側から。



ガスガン~制御回路の配線は4芯カールコードを使います。



ガスガンと制御回路を切り離せるようにコネクターを取り付けます。



サーミスタはフィルムヒーターに直接接着します。
これはマガジンが装着されていない状態でも温度が上がり過ぎないようにするためです。




万が一の保険に72℃の温度ヒューズを取り付けました。



テストして問題ないか確認。
次回は制御回路の実装を行います。  

Posted by 名無しのナナシ at 23:35Comments(0)エアガンマイコン

2018年11月10日

ガスガン内蔵ヒーター制御装置を作る その2

ヒーター制御装置の回路とプログラムを作っていきます。

まずテスト用の回路図を作成しました。



NTCサーミスタを使った分圧回路で温度を検知し、FETでヒーターのオン・オフを行います。
バッテリーの電圧は固定抵抗を使った分圧回路を用いて検知します。



これをブレッドボード上で組み立て、テストを行います。

プログラムの方は、まず温度と電圧を読み取り、シリアルモニタに表示するプログラムを作成しました。

//ヒーター制御入力テスト用
//定数の宣言
const int V_R1 = 1000;     //電圧測定VIN側抵抗値[Ω]
const int V_R2 = 1000;     //電圧測定GND側抵抗値[Ω]
const int B = 4100     //サーミスタB定数
const int T_R0 = 10000;     //サーミスタ基準抵抗値[Ω]
const int T_R1 = 10000;     //バランス抵抗[Ω]
const int T0 = 298;     //サーミスタ基準温度[K]
//変数の宣言
float Vcc = 0;     //基準電圧[V]
int Val = 0;     //測定電圧[V×100]
int Temp = 0;     //測定温度[℃×10]

void setup () {
  Serial.begin(9600);     // 9600 bpsで接続
  Serial.println("READ_START");     // 最初に1度だけ Start を表示

void loop () {
  Vcc = cpuVcc();      //基準電圧の取得
  Temp = GetTemp(analogRead(A0));     //温度の取得
  Val = GetVal(analogRead(A1));      //電圧を取得
  Serial.print("Vcc=");     //基準電圧の表示
  Serial.print(Vcc);
  Serial.print(" TEMP=");     //温度の表示
  Serial.print(Temp);
  Serial.print(" V=");     //電圧の表示
  Serial.println(Val);
  delay(50);     // 0.05s 待つ
}
//センサーの値から温度を計算
float GetTemp (int raw){
  float V_R0 ;
  float R ;
  float t;
   
  V_R0 = raw * Vcc / 1.024;     //回路内抵抗の消費電圧を算出
  R = Vcc * 1000.0 / V_R0 * T_R1 - T_R1;     //サーミスタの抵抗値を算出
  t = (1000 / (1 / (0.001 * T0)+log(R / T_R0)*1000 / B) - 273);     //温度の計算
  return(int)(t * 10.0);     //10倍にして整数にする
}
//センサーの値から電圧を計算
int GetVal(int A){
  float V;
  V = A * Vcc / 1024.0 /V_R2 * (V_R1 + V_R2);     //電圧の計算
  return(int)(V * 100.0);     //100倍して整数にする
}

float cpuVcc(){     // 電源電圧(AVCC)測定関数
  long sum=0;
  adcSetup(0x4E);     // Vref=AVcc, input=internal1.1V
  for(int n=0; n < 10; n++){
    sum = sum + adc();     // adcの値を読んで積分
  }
  return (1.1 * 10240.0)/ sum;     // 電圧を計算して戻り値にする
}
 
void adcSetup(byte data){     // ADコンバーターの設定
  ADMUX = data;     // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);     // ADC イネーブル
  ADCSRA |= 0x07;     // AD変換クロック CK/128
  delayMicroseconds (500);     // 安定するまで待つ
}
 
unsigned int adc(){     // ADCの値を読む
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);     // AD変換開始
  while(ADCSRA & ( 1 << ADSC) ){     // 変換完了待ち
  }
  dL = ADCL;     // LSB側読み出し 
  dH = ADCH;      // MSB側
  return dL | (dH << 8);     // 10ビットに合成した値を返す
}

以上のプログラムを書き込み、バッテリーを接続後、シリアルモニタを表示すると下のように表示します。
(このプログラムを使う際、マイコンVINの接続を切っておかないと、バッテリー電圧が高く表示されてしまいます。)


うまく表示できたら、今度はヒーターを動かしてみます。



プログラムは以下の通り。

//ヒーター制御プログラムテスト
//入出力ピンの名称変更
#define HEATER 2     //ヒーター制御出力
#define Temp_Input A0     //サーミスタ入力
#define Val_Input A1     //電圧測定入力
#define LED 13     //マイコンLED

//定数の宣言
const int V_R1 = 1000;     //電圧測定VIN側抵抗値(Ω)
const int V_R2 = 1000;     //電圧測定GND側抵抗値(Ω)
const int B = 4100;     //サーミスタB定数
const int T_R0 = 10000;     //サーミスタ基準抵抗値[Ω]
const int T_R1 = 10000;     //サーミスタバランス抵抗値[Ω]
const int T0 = 298;     //サーミスタ基準温度[K]
const int Limit_Val = 740;     //測定電圧下限値[V×100]
const int Limit_L_Temp = -200,Limit_H_Temp = 400;     //正常温度閾値[℃×10]
const int L_Temp = 280;     //温度下限値[℃×10]
const int H_Temp = 300;     //温度上限値[℃×10]
//変数の宣言
float Vcc = 0;     //マイコン電源電圧[V]
int Val = 0;     //測定電圧[V×100]
int Temp = 0;     //測定温度[℃×10]

void setup () {
  //入出力ピンの設定
  pinMode(HEATER, OUTPUT);
  pinMode(LED, OUTPUT);
  delay(1000);     //電源投入時1s待つ
}

void loop () {
  Vcc = cpuVcc();     //マイコン電源電圧の取得
  Temp = GetTemp(analogRead(Temp_Input));     //温度の取得
  Val = GetVal(analogRead(Val_Input));      //電圧を取得

  while (Val < Limit_Val) {     //測定電圧が下限値を下回るとヒーターをオフにし、
    digitalWrite(HEATER, LOW);     //マイコンLEDが長い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(1000);
  }

  while (Temp > Limit_H_Temp || Temp < Limit_L_Temp){     //測定温度が正常な範囲内から外れると
    digitalWrite(HEATER, LOW);     //ヒーターをオフにし、マイコンLEDが短い間隔で点滅する
    digitalWrite(LED, HIGH);
    delay(100);
    digitalWrite(LED, LOW);
    delay(100);
  }

  digitalWrite(13, LOW);
  
  if (Temp <= L_Temp) {     //測定温度が下限値以下になると
    digitalWrite(HEATER, HIGH);     //ヒーターをオンにする
  }
  
  if (Temp >= H_Temp) {     //測定温度が上限値以上になると
    digitalWrite(HEATER, LOW);     //ヒーターをオフにする
  }
  delay(100);     //0.1s待つ
}
//センサーの値から温度を計算
float GetTemp (int raw) {
  float V_R0 ;
  float R ;
  float t;

  V_R0 = raw * Vcc / 1.024;     //バランス抵抗の消費電圧を算出
  R = Vcc * 1000.0 / V_R0 * T_R1 - T_R1;     //サーミスタの抵抗値を算出
  t = (1000 / (1 / (0.001 * T0) + log(R / T_R0) * 1000 / B) - 273);     //温度の計算
  return (int)(t * 10.0);     //10倍にして整数にする
}
//センサーの値から電圧を計算
int GetVal(int A) {
  float V;
  V = A * Vcc / 1024.0 / V_R2 * (V_R1 + V_R2);     //電圧の計算
  return (int)(V * 100.0);     //100倍して整数にする
}

float cpuVcc() {     // 電源電圧(AVCC)測定関数
  long sum = 0;
  adcSetup(0x4E);     // Vref=AVcc, input=internal1.1V
  for (int n = 0; n < 10; n++) {
    sum = sum + adc();     // adcの値を読んで積分
  }
  return (1.1 * 10240.0) / sum;     // 電圧を計算して戻り値にする
}

void adcSetup(byte data) {     // ADコンバーターの設定
  ADMUX = data;     // ADC Multiplexer Select Reg.
  ADCSRA |= ( 1 << ADEN);     // ADC イネーブル
  ADCSRA |= 0x07;     // AD変換クロック CK/128
  delayMicroseconds (500);     // 安定するまで待つ
}

unsigned int adc() {     // ADCの値を読む
  unsigned int dL, dH;
  ADCSRA |= ( 1 << ADSC);     // AD変換開始
  while (ADCSRA & ( 1 << ADSC) ) {     // 変換完了待ち
  }
  dL = ADCL;     // LSB側読み出し
  dH = ADCH;     // MSB側
  return dL | (dH << 8);     // 10ビットに合成した値を返す
}

プログラムの動きとしては、
電源接続後、1秒待ってから動作開始。

温度、電圧の取得。

電圧が下限値(7.4V)を下回ると無限ループで停止、LEDを1秒間隔、0.1秒点灯させる。

温度が異常な値(40℃を超え、-20℃を下回る)を示すと無限ループで停止、LEDを0.1秒間隔、0.1秒点灯させる。

温度が下限値(28℃)以下になるとヒーターをオンにする。

温度が上限値(30℃)以上になるとヒーターをオフにする。

以下繰り返し。

テストの結果うまくいったので、次からは実装を行います。  

Posted by 名無しのナナシ at 21:13Comments(0)エアガンマイコン

2018年11月10日

ガスガン内蔵ヒーター制御装置を作る その1

以前、このようなものを作りましたが、
問題があり、改良することにしました。

問題点としては、
1.モバイルバッテリーを使用しているので準備に手間と資金がかかる。
2.電圧が5Vでは25℃前後の保温が精一杯。

これらを解決するため、電動ガン用の7.4V LiPoバッテリーを使用したいと思いますが、
これの問題点として、
1.現状のままLiPoバッテリーを繋ぐと非常に高温となり危険。
2.バッテリーが過放電してしまい使用不能になってしまう。

これを解決するためヒーターの制御装置を作ることにしました。



初めはこのような既存の温度センサースイッチとオートカットを使うつもりでしたが、
この回路は動作電圧が12Vで、扱いが難しく頓挫していましたが、
いいものを見つけたのでそれを使います。




Amazonで売っていたマイコンボードです。
Arduino Nanoというマイコンボードの互換機で、
7V~12Vで動作するので7.4V LiPoバッテリーで使うことが出来ます。
これにセンサー類を取り付け、プログラムを書き込めばヒーターの制御装置を作ることが出来ます。



先ほどの温度センサースイッチと比べてとても小型です。

プログラムを書き込むにはArduino IDEという物が必要です。
こちらからダウンロードできます(英語のページ)。
インストール方法などの詳細はこちらから 互換機をそのままPCに接続しても認識しないので、CH340Gというドライバが必要です。
こちらからダウンロードできます(中国語のページ)。



とりあえずLEDを光らせることは出来たので、これから制御回路やプログラムを作っていきます。  

Posted by 名無しのナナシ at 00:15Comments(0)エアガンマイコン