羽根愛好家

Blog Airplane Photo Bird Photo About Contact
とりあえず温度センサー:前の記事
そして完成へ:次の記事

とりあえずコーディング

2011年 11月 28日

 えっと,ざっくりと書いてみました。
 難しいというか,肝心なところは,ニクロム線に流す電力で使ってるPWM制御のデューティー比をどう変化させるかっていう部分。車は急に止まれない…じゃなくてニクロム線ヒーターは急に温度が下がったり,上がったりはしません。単純に「目標温度<現在温度ならデューティー比下げる,またはその逆」みたいな処理だと,どうしても目標温度との開きが大きい状態で推移してしまいます。で,センサーを読み取ったときに前回の読み取り結果との差から,現在の状態が上昇状態にあるのか下降状態にあるのかを記録しておいて,

現在の温度がターゲット温度より高い場合
→下降指示
 →下降中で温度差が大きい場合に大きく引き下げる
 →下降中で温度差が小さい場合には少し持ち上げる
 →上昇中に下降指示が出た場合は大きく引き下げる

現在の温度がターゲット温度より低い場合
→上昇指示
 →上昇中で温度差が大きい場合には大きく引き上げる
 →上昇中で温度差が小さい場合には少し引き下げる
 →下降中に上昇指示が出た場合は大きく引き上げる

という感じに,目標温度付近で足踏みさせるようなやり方を考えてみました。
 プログラムのほうは,↑の発想をそのまま条件分岐させただけっていうテキトー具合なんですが,まぁそこはそれで。もうちょっと美しいアルゴリズムがありそうなんだけど,ちゃっちゃっと作ってしまいたかったので,とりあえず書き切ることを優先しました。
 結果はまずまずで,この状態で家の中で試して見ると,目標温度±1℃以内の範囲で動いてくれてます。デューティー比を変化させるかどうかのルーチンを実行するインターバルや,デューティー比の変化量はざっくり設定してますが,悪くない設定っぽいです。もちろん,ベストかどうかは分からないですけど。
 あとは,屋外でレンズに巻いた状態だと違う結果になる可能性もあるんで,次はフィールドでテストして,必要なら調整しようと思ってます。一応,スイッチで目標温度を変えられるようにしてあるので,目標温度より大きく離れた位置で動きが止まるようなら,調整が終わるまでは目標温度を無理矢理引き上げ/引き下げてカバーしようとか思ってたりします。
 あと,ログ記録のための準備はしたんですが,ルーチンは書いてません。気が付いた方はえらい!(笑。あ,さらに,↓のコードで表示が乱れるのはウチのブログがデザインをちゃんとクロスプラットフォーム対応にしてないのが原因なので,気にしないでください。

 え? ハードウェアのほうはどうなったかって? 今度書きます。

#include "mbed.h" #include "TextLCD.h" #include "LinearTempSensor.h"

Serial pc(USBTX, USBRX);
TextLCD lcd(p24, p26, p27, p28, p29, p30, TextLCD::LCD16x2); // LCD(RS, E, DB4, DB5, DB6, DB7)
LinearTempSensor sensor[] = {p20,p19,p18}; // sensor([0][1]=heater, [2]=ambient)
PwmOut heat_pwm[] = {p22,p21};

InterruptIn sw[] = {p5, p6};
DigitalIn s_sw(p7);

Ticker sensor_timer, heater_timer, log_timer;

float target_temp = 35.0;
float Tav[3];
int current_direction[3];


// interrupt event - change target temperature
void switch0() {
  if(s_sw.read() == 1) {
    if(target_temp < 45) {
      target_temp += 0.5;
    }
    lcd.locate (10,1);
    lcd.printf ("%2.1f", target_temp);
  }
}
void switch1() {
  if(s_sw.read() == 1) {
    if(target_temp < 10) {
      target_temp -= 0.5;
    }
    lcd.locate (10,1);
    lcd.printf ("%2.1f", target_temp);
  }
}


// read temperature
void read_temp() {
  float Vout[3], previous_Tav[3];
  
  for(int i = 0; i < 3; i++) {
    previous_Tav[i] = Tav[i];
    Vout[i] = sensor[i].Sense();  // read sensor
    Tav[i]  = sensor[i].GetAverageTemp();  // calculate average temperature from 10 samples
    
    if((previous_Tav[i] - Tav[i]) > 0) {
      current_direction[i] = 0;
    } else {
      current_direction[i] = 1;
    }
  }
  
  // print temperature to LCD
  lcd.locate(2,0);
  lcd.printf("%2.1f", Tav[0]);
  lcd.locate(10,0);
  lcd.printf("%2.1f", Tav[1]);
  lcd.locate(2,1);
  lcd.printf("%2.1f", Tav[2]);
}


// change pwm duty cycle
void change_pwm_cycle(int heater_num, int recieve_direction) {
  float modified_cycle = heat_pwm[heater_num].read();
  float temp_difference = Tav[heater_num] - target_temp;
  
  if(temp_difference < 0) {
    temp_difference *= -1;
  }
  
  switch(recieve_direction) {
    case 0:
      if(current_direction[heater_num] == 0) {
        if(temp_difference > 5) {
          modified_cycle -= 0.2;
        } else if(temp_difference < 2) {
          modified_cycle += 0.05;
        }
      } else {
        modified_cycle -= 0.2;
      }
      break;

    case 1:
      if(current_direction[heater_num] == 1) {
        if(temp_difference > 5) {
          modified_cycle += 0.2;
        } else if(temp_difference < 2) {
          modified_cycle -= 0.05;
        }
      } else {
        modified_cycle += 0.2;
      }
      break;
    
    default:
      break;
  }
  
  if(modified_cycle < 0) {
    modified_cycle = 0;
  } else if(modified_cycle > 1) {
    modified_cycle = 1;
  }
  
  heat_pwm[heater_num].write(modified_cycle);
}


// control heater
void control_heater() {
  for(int i = 0; i < 2; i++) {
    if(Tav[i] > target_temp) {
      change_pwm_cycle(i ,0);
    } else if(Tav[i] < target_temp) {
      change_pwm_cycle(i, 1);
    } 
  }
  pc.printf("0:%1.3f 1:%1.3f \n",heat_pwm[0].read(), heat_pwm[1].read());
}


// main
int main() {
  // init LCD
  lcd.cls();         // clear LCD
  
  lcd.writeCommand(0x40);    // create Celsius symbol and write to CGRAM
  wait(0.000040f);
  lcd.writeData((int)0x08);
  lcd.writeData((int)0x14);
  lcd.writeData((int)0x08);
  lcd.writeData((int)0x06);
  lcd.writeData((int)0x09);
  lcd.writeData((int)0x08);
  lcd.writeData((int)0x09);
  lcd.writeData((int)0x06);
  wait(0.000040f);
  
  lcd.locate(0,0);   // print fixed char to LCD
  lcd.printf("1:");
  lcd.locate(8,0);
  lcd.printf("2:");
  lcd.locate(0,1);
  lcd.printf("a:");
  lcd.locate(8,1);
  lcd.printf("t:");
  
  lcd.locate(6,0);
  lcd.putc(0x00);
  lcd.locate(14,0);
  lcd.putc(0x00);
  lcd.locate(6,1);
  lcd.putc(0x00);
  lcd.locate(14,1);
  lcd.putc(0x00);
  
  lcd.locate(10,1);
  lcd.printf("%2.1f", target_temp);
  
  // set interrupt event
  sw[0].rise(&switch0);
  sw[1].rise(&switch1);
  
  // init PWM //
  heat_pwm[0].period_ms(10); // set pwm period 10ms=100Hz
  heat_pwm[1].period_ms(10);
  
  heat_pwm[0].write(1); //set default pwm duty cycle
  heat_pwm[1].write(1);  
  
  // read first temperature  
  read_temp();
  
  // set interval event
  sensor_timer.attach(&read_temp, 1);
  heater_timer.attach(&control_heater, 5);
}

 あー,貼り付けててピンときた。摂氏マイナスになったときのこと考えてないや,これ。LCDの桁数が足りない(笑。頑張って作ったけど,℃←を消すかな……。

タグ:
  • 天体
  • 雑感2011
|2011/11/28 23:42 |コメント(0)

コメントする

最近の記事

  • そして完成へ
  • とりあえずコーディング
  • とりあえず温度センサー
  • 次のプロジェクト
  • シャッター制御の手直し
  • 牛歩のごとく進展
  • 天体写真にはまってる話
  • えこぼんぼん
  • 世界一周から帰ってきた飛鳥II
  • いざ!セントレア!

カテゴリ

  • 日々雑感
    • 雑感2009 (28)
    • 雑感2010 (2)
    • 雑感2011 (9)
  • 飛行機 (26)
    • 成田 (9)
    • 国内 (6)
    • 海外 (13)
  • 自然散策 (1)
    • 鳥 (3)
  • 物欲 (1)
    • PC関連 (5)
    • カメラ (9)
  • 感想
    • テレビ (11)
    • 映画 (2)
    • 書籍 (1)
  • Web管理 (14)

アーカイブ

タグ

タグリスト表示

検索

このブログについて

  • 購読する このブログを購読
Powered by
Movable Type 4.25
  and
This site is powered by CMS Designer.
Creative Commons 2.1 by-nc copyright(c) 2002-2009 tawawa-s.com. some rights reserved.