目的
- RCヘリコプターのヘリポートを作成する
- 発着時にLEDをアニメーション点灯させる
- 距離に応じてLEDのアニメーションが変化する、自分でパターン編集出来るようにする
出来上がった部分
残作業は距離測定センサのケース埋め込み、USB端子のケース埋め込みです。
3Dモデル
AutoDesk 123D Designを利用して下記を作成しました。
印刷イメージ
ダヴィンチ Jr. 1.0 にて印刷しました。
完成物
印刷可能サイズ、ぎりぎりの大きさで印刷したので迫力があります、大体 140mm * 140mm * 50mm です
印刷に掛かった時間、フィラメント
購入時付属のフィラメントが底をついたので、2本目をセットしてから真新しい状態で印刷しました
印刷時間が 20h 程、利用したフィラメントが 54m でした。
s
失敗談
WS2822Sの大きさピッタリに合わせて 3Dモデルも作成してハンダ付けする前はちょうど良いサイズだったのですが
ハンダ付け後は2,3mm 削る必要が出てきたため、リュータでガリガリと穴を広げ余裕を持たせた上で
ホットボンドでくっつけております。。。悲しい
回路
下記記事のLED個数と点灯パターンを変更しました。
http://kouzu.info/distance-sensing-on-adafruit-trinket/
ソースコード
#include <Ws2822s.h>
#include <avr/interrupt.h>
// WS2822Sセットアップ
#define NUM_PIXELS 6 // 使用するWS2822Sの数
#define LED_PIN 1 // WS2822SのDAIピンにつなげるTrinketのピン番号 #1
#define ADR_PIN 0 // WS2822SのADRIピンにつなげるTrinketのピン番号 #0
// センサーセットアップ
#define DISTANCE_SENSOR 1 // 距離センサーのアナログ出力値を取得 Trinketのピン番号#2
// TrinketでanalogRead利用時は AnalogPinNumberで記載する A1 = #2 となる
#define MAX_VOLTAGE 3.0
Ws2822s LED(LED_PIN , NUM_PIXELS);
// アニメーションパターンの定義
#define RGB 3
#define FRAME_MAX 6
PROGMEM const uint8_t displayAnim[][RGB*NUM_PIXELS*FRAME_MAX] = {
// R G B
// LED1
// LED2
// 近い
{
0x66,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x66,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
0x00,0x00,0x00,
0x99,0x00,0x00,
},
// 中位
{
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x55,0x00,
0x00,0x55,0x00,
},
// 遠い
{
0x00,0x00,0x11,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x11,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x11,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x11,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x11,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x00,
0x00,0x00,0x11,
},
};
// interrupt関数で使いまわす変数
volatile uint8_t animPattern; // 実行するアニメーションのパターン
volatile uint8_t animFrameNum; // タイマー割り込みが toggleCount 回実行されたらアニメーションフレームが1進む
volatile uint16_t animWaitTime; // タイマー割り込みが toggleCount 回実行されたらアニメーションフレームが1進む
volatile uint16_t toggleCount; // タイマー割り込み時にカウントアップされるカウンタ
void setup()
{
// put your setup code here, to run once:
// tnx for information
// http://w8bh.net/avr/TrinketTimers.pdf
// http://tetunori.hatenablog.com
// http://www.geocities.jp/zattouka/GarageHouse/micon/Arduino/DMSU/DMSU2.htm
// Disable interrupts
cli();
// Clear Timer on Compare
TCCR1 = (1<<CTC1);
// all of the prescaler bits are set to 1. The prescaler divides the 8 MHz clock by 16384
// resulting in a counter frequency of 488 Hz
TCCR1 |= (1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10);
// The output frequency for CTC mode is: freq(Hz) = 8 MHz/2/prescaler/(OCR1C+1)
// resulting a calling TIM1_COMPA_vect frequency is 4.8 Hz
OCR1C = 50;
// Enable Timer1 interrupt (compare mode)
TIMSK = (1 << OCIE1A);
// init WS2822S Address
// EEPROMの寿命を考えて初回だけ実行済みのため毎回実施しない
// LED.setAddress(0, NUM_PIXELS-1);
//色配列の初期化
setAnimationPatternToBlank();
setAnimationPattern(2, 5);
// Enable interrupts
sei();
}
void loop()
{
// put your main code here, to run repeatedly:
// 着陸するヘリとの距離に応じてアニメーションを変化させる
int sensorValue = analogRead(DISTANCE_SENSOR);
float voltage = (float)sensorValue * (MAX_VOLTAGE / 1024.0);
if (voltage > 1.2) {
// 距離が10cm以内
setAnimationPattern(0, 1);
} else if (voltage > 0.6) {
// 距離が30cm以内
setAnimationPattern(1, 3);
} else if (voltage < 0.6) {
// 距離が30cm以上
setAnimationPattern(2, 5);
}
// 何もない場合は待ち状態アニメーション
// 距離が40cm-30cmの場合のアニメーション
// 距離が30cm-20cmの場合のアニメーション
// 距離が20cm-10cmの場合のアニメーション
// 距離が0cm-10cmの場合のアニメーション
// 着陸済み状態のアニメーション
}
void setAnimationPatternToBlank()
{
// 全てのWS2822Sピクセルの色情報をR,G,B=0,0,0とする
for (int ledAddr=0; ledAddr<NUM_PIXELS; ledAddr++) {
LED.setColor(ledAddr, 0, 0, 0);
}
LED.send();
}
void setAnimationPattern(uint8_t _animPattern, uint16_t _animWaitTime)
{
// アニメーションのパターンが現在の物と異なったら初期化
if (animPattern != _animPattern) {
animWaitTime = _animWaitTime;
animPattern = _animPattern;
animFrameNum = 0;
}
}
// LEDの色情報を1秒以内に再送信
ISR(TIM1_COMPA_vect)
{
// 設定されたアニメーションのパターンとフレームをLEDに設定 & 送信
for (int ledAddr=0; ledAddr<NUM_PIXELS; ledAddr++) {
LED.setColor(ledAddr, pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)]),
pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)+1]),
pgm_read_byte_near(&displayAnim[animPattern][(animFrameNum*NUM_PIXELS*RGB)+(ledAddr*RGB)+2]));
}
LED.send();
// タイマー割り込みのタイミング * animWaitTimeの値で アニメーションのフレームを進める
if (toggleCount < animWaitTime) {
toggleCount++;
} else {
if (animFrameNum < (FRAME_MAX-1)) {
animFrameNum++;
} else {
animFrameNum = 0;
}
toggleCount = 0;
}
}