2019年05月08日

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

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

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

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

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

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

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

//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ビットに合成した値を返す
}



同じカテゴリー(エアガン)の記事画像
クエーサ ジェルブラスターのエアガン化(改造編その1)
クエーサ ジェルブラスターのエアガン化(検証編)
M14カービンカスタム
側面吸気ピストンヘッドの自作
ARES SOC SLR 分解
ARES SOC SLR(中古品)
同じカテゴリー(エアガン)の記事
 クエーサ ジェルブラスターのエアガン化(改造編その1) (2023-02-01 23:33)
 クエーサ ジェルブラスターのエアガン化(検証編) (2022-12-30 22:33)
 M14カービンカスタム (2022-06-26 20:51)
 側面吸気ピストンヘッドの自作 (2022-06-22 00:10)
 ARES SOC SLR 分解 (2019-06-14 23:54)
 ARES SOC SLR(中古品) (2019-06-11 22:26)
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。