目次

安全機構

 ファームウエアを検討し、雛形となるコードも作成したので
 ハードウエアとソフトウエアで安全機構を入れます。

 安全機構なしでも走行に問題はありませんが、フライングや
 コースアウト時のメカ損傷等を防ぐために必須と考えました。

 最初に次の安全機構を用意。

 円滑な競技運営のため、150秒程度の時間規定が設けられています。
 スタートしてから120秒後にモータを停止するタイマーを用意。

 スタートゲートが開いてから、タイマーに対してトリガーを与え
 120秒後にパルスで知らせる回路を考えました。

 タイミングチャートでは、次のようにします。



 システムの一部として使えるように、PIC12F1501を利用して実現。

 マシンのメカは複数あるので、制御基板とは別基板にします。
 制御基板に接続して利用できるため、予備マシンを使う場面
 でも着脱で対応できます。

 テスト用に半田付け基板で動作実験しました。



 テスト用基板の回路は、以下。



 プログラムは、次のように短くしています。

/* redefine data type */
typedef unsigned char UBYTE ;
typedef unsigned int  UWORD ;

#define TXOUT PORTA.F0
#define TICK  PORTA.F1

#define OFF 0
#define ON  OFF+1

#define MASKFF 0xff

#define XMAX 120 /* 120 seconds */

typedef union {
  struct {
    unsigned B7:1;
    unsigned B6:1;
    unsigned B5:1;
    unsigned B4:1;
    unsigned B3:1;
    unsigned B2:1;
    unsigned B1:1;
    unsigned B0:1;
  } BIT ;
  unsigned char DR ;
} FLAGSP ;

volatile FLAGSP xflags ;

#define DFLAG xflags.BIT.B0
#define EFLAG xflags.BIT.B1
#define OFLAG xflags.BIT.B2
#define XFLAG xflags.BIT.B3

volatile UBYTE xcnt ;
volatile UWORD ycnt ;
volatile UBYTE xinterval ;

/* function prototype */
void init_usr(void);

/* interrupt handler */
void interrupt(void)
{
  /* generate 1ms */
  if ( INTCON.TMR0IF == ON ) {
    /* clear flag */
    INTCON.TMR0IF = OFF ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* set flag */
    XFLAG = ON ;
  }
  /* LTRG PORTA.F5 rising edge interrupt */
  if ( INTCON.IOCIF == ON ) {
    /* clear flag */
    IOCAF.IOCAF5 = OFF ;
    /* set event flag */
    EFLAG = ON ;
  }
}

void delay_ms(UBYTE x)
{
  UBYTE xlast ;

  xlast = xcnt + x ;
  while ( xcnt < xlast ) ;
}

void main(void)
{
  /* initialize */
  init_usr();
  /* endless loop */
  while ( ON ) {
    /* counter increment */
    if ( XFLAG == ON ) {
      /* clear flag */
      XFLAG = OFF ;
      /* increment */
      xcnt++ ;
      /* monitor */
      TICK = OFF ;
      if ( xcnt & ON ) { TICK = ON  ; }
      /* increment */
      if ( DFLAG == ON ) { ycnt++ ; }
      /* judge */
      if ( ycnt == 1000 ) {
        ycnt = 0 ;
        xinterval++ ;
        if ( xinterval == XMAX ) { OFLAG = ON ; }
      }
    }
    /* timer out */
    if ( OFLAG == ON ) {
      /* clear flag */
      OFLAG = OFF ;
      /* disable */
      DFLAG = OFF ;
      /* send pulse */
      TXOUT = ON ;
      delay_ms(10);
      TXOUT = OFF ;
    }
    /* wait trigger */
    if ( EFLAG == ON ) {
      /* clear flag */
      EFLAG = OFF ;
      /* clear counter */
      ycnt = 0 ;
      xinterval = 0 ;
      /* enable increse counter */
      DFLAG = ON ;
    }
  }
}

/* define function body */
void init_usr(void)
{
  /* select 16MHz */
  OSCCON = (0xf << 3) | 0x03 ;
  /* disable A/D converter */
  ADCON0.ADON = OFF ;
  ADCON2      = 0 ;
  ANSELA      = 0 ;
  /* disable D/A converter */
  DACCON0 = 0 ;
  DACCON1 = 0 ;
  /* disable compare module */
  CM1CON0.C1ON = OFF ;
  CM1CON0.C1OE = OFF ;
  /* I/O state */
  PORTA = 0x00 ;
  /* I/O directions */
  TRISA = 0x38 ; /* bit0,1,2 as output , others as input */
  /* PIN change interrupt */
  {
    /* PORTA.5 rising edge */
    IOCAP.IOCAP5 = ON ;
    /* enable compare match interrupt */
    INTCON.IOCIE = ON ;
  }
  /* initialize timer 0 */
  {
    /*
       16MHz/4 = 4MHz (Fosc)
       Fosc/4 = 1MHz
       1MHz/4 = 250kHz prescaler = 1:4
    */
    OPTION_REG = 0x01 ;
    /* 256 - 250 = 6 */
    TMR0 = 6 ;
    /* enable timer0 overflow interrupt */
    INTCON.TMR0IE = ON ;
  }
  /* enable general interrupt */
  INTCON.GIE = ON ;
  /* clear flags */
  xflags.DR = 0 ;
  /* initialize variables */
  xcnt = 0 ;
  ycnt = 0 ;
  xinterval = 0 ;
}

 スタートゲートが開くまでは、モータを回さないようにと
 DCDCコンバータからの出力をカットします。

 DCDCコンバータの出力では、GND側をフローティングにするか
 0Vのラインに接続するかを制御できるようにしました。

 回路は簡単。



 スタートゲートが開いたときに、タイマーにトリガーを与え
 同時に'H'レベルを上の回路に与えます。基板に実装すると
 次のようになります。



 制御基板からは、電源と制御信号を接続し、DCDCコンバータ
 基板とは2本のGND制御を接続。


 DCDCコンバータ出力に安全機構をつけると
 以下のようになりました。



 ハードウエアに加えて、ソフトウエアの安全機構を用意。

 システムタイマーを設定し、いつでも参照できるように
 します。システムタイマーのカウンタを1ms単位とし
 32ビットサイズで扱います。

 1msで32ビットのカウンタをインクリメントしていけば
 約49日程度の時間を扱えます。MCR大会の会場で制御
 基板の電源を間違って入れても、1時間程度で自動で
 電源オフにします。

 電源投入から1時間でパワーオフするには、3600x1000ms
 をカウント。これをタイマー割込みルーチンの中に入れて
 対応。

 具体的なコードは、以下。

volatile ULONG syscnt ;
volatile UBYTE sysflag ;

void IRQ_Handler(void) __irq
{
  /* judge timer0 interruption (100us) */
  if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
    /* clear timer0 interrupt flag */
    T0CLRI = 0xff ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( (timcnt & 0xfff) == 0 ) { GP4DAT ^= (1 << 23); }
    /* system timer */
    if ( timcnt & 0x3ff) == 1000 ) {
      syscnt++;
      if ( syscnt == 3600000L ) { sysflag = ON ; }
    }
  }
}

 フラグsysflagでイベントを通知し、モータに接続したDCDCコンバータ
 の電源出力をカットするように信号を出力。

    if ( sysflag == ON ) {
      /* clear flag */
      sysflag = OFF ;
      /* power off */
      turn_bit(OFF,CONDC_BIT);
    }

 DCDCコンバータの電力制御は、次の関数で扱います。

void turn_bit(UBYTE which,UBYTE bx)
{
  if ( which ) { GP1DAT |=  (1 << bx); }
  else         { GP1DAT &= ~(1 << bx); }
}

 タイマー割込みでは、120秒経過したことを外部回路が
 通知しているかを監視します。シフトレジスタに外部
 回路の出力信号を取り込んで、レジスタの全ビットが
 1になったら、通知します。

volatile UBYTE tsft ;
volatile UBYTE toutflag ;

void IRQ_Handler(void) __irq
{
  /* judge timer0 interruption (100us) */
  if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
    /* clear timer0 interrupt flag */
    T0CLRI = 0xff ;
    /* increment */
    timcnt++ ;
    /* judge */
    if ( (timcnt & 0xfff) == 0 ) { GP4DAT ^= (1 << 23); }
    /* system timer */
    if ( timcnt & 0x3ff) == 1000 ) {
      syscnt++;
      if ( syscnt == 3600000L ) { sysflag = ON ; }
    }
    /* time out handling */
    if ( (GP1DAT & 0x00040000 ) {
      tsft <<= 1;
      tsft |= ON;
    }
    if ( tsft == 0xff ) { toutflag = ON ; }
  }
}

 イベント通知フラグtoutflagの論理値を判断し
 DCDCコンバータの出力をカットしてモータ停止
 とする操作を追加します。

    if ( toutflag == ON ) {
      /* clear flag */
      toutflag = OFF ;
      /* power off */
      turn_bit(OFF,CONDC_BIT);
    }
    if ( sysflag == ON ) {
      /* clear flag */
      sysflag = OFF ;
      /* power off */
      turn_bit(OFF,CONDC_BIT);
    }

 制御基板上のプロセッサは、2つのタイムアウト処理を
 2つのイベント通知フラグで検知できます。

 単純なハードウエアとソフトウエアの追加ですが、動く物体を
 停止させて、コースアウトして壁に激突あるいは観測者に衝突
 するようなときに対応できるようになりました。

 スタートしてから120秒後に自動停止、パワーオンから1時間後
 に自動停止だけですが、大きな質量をもつ物体の暴走事故の発生
 確率を下げられます。

目次

inserted by FC2 system