質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.64%

Aduinoのプログラミングについて

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,049

shincra

score 13

以下のプログラミングをしたのですが(見づらくて申し訳ないです)、問題点がいくつかありました。

1、if文にボタンを押したら(status = HIGHの状態)割り込み?のようにすぐ飛んでほしい。
2、サーボモーターは止まっているはずが、常に微動している。
3、LEDテープの色が(255,255,255)で白になるはずが、オレンジになってしまう。

Arduino UNO R3 の互換品を使っています。
いい解決策があれば、できれば具体的に修正点を教えていただきたいです。

#include <Adafruit_NeoPixel.h>

//ライブラリインクルード
#include <Adafruit_NeoPixel.h>

#define LED_COUNT ( 40 )
#define DIGITAL_PIN ( 6 )


#define input_pin   2
#define input_pin2   3
#define input_pin3   10
#define input_pin4   11
#define input_pin5   12



//www.elegoo.com
//2016.12.08
#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position


Adafruit_NeoPixel led = Adafruit_NeoPixel( LED_COUNT,DIGITAL_PIN , NEO_GRB + NEO_KHZ800);
void setup() {
  //初期化処理
  led.begin();
  led.show();

     pinMode(input_pin,INPUT) ;
     pinMode(input_pin2,INPUT) ;
     pinMode(input_pin3,INPUT) ;
     pinMode(input_pin4,INPUT) ;
     pinMode(input_pin5,INPUT) ;

       pinMode(13, OUTPUT); 

         Serial.begin(9600);
  myservo.attach(7);  // attaches the servo on pin 9 to the servo object

}

void loop() {
    digitalWrite(13, HIGH);    // スイッチをOFFする



 for(int i = 0 ; i < LED_COUNT ; i++ )
{
led.setPixelColor(19+i,led.Color(255,255,255));
led.setPixelColor(20+i,led.Color(0,0,0));

led.setPixelColor(19-i,led.Color(255,255,255));
led.setPixelColor(18-i,led.Color(0,0,0));


led.show();
delay(20);
}

    int status ;
    int status2 ;


    status = digitalRead(input_pin) ; //スイッチの状態を読む
    status2 = digitalRead(input_pin2) ; //スイッチの状態を読む




    if(status == HIGH && status2 == LOW){
 for(int i = 0 ; i < LED_COUNT ; i++ )
{
led.setPixelColor(19+i,led.Color(0,255,0));
led.setPixelColor(20+i,led.Color(0,0,0));

led.setPixelColor(19-i,led.Color(0,255,0));
led.setPixelColor(18-i,led.Color(0,0,0));


led.show();
delay(20);
}
  digitalWrite(13, LOW);   // スイッチをONする
  delay(3000);                  //3秒待つ




   } else if(status == HIGH && status2 == HIGH){
 for(int i = 0 ; i < LED_COUNT ; i++ )
{
led.setPixelColor(19+i,led.Color(10,10,10));
led.setPixelColor(20+i,led.Color(0,0,0));

led.setPixelColor(19-i,led.Color(10,10,10));
led.setPixelColor(18-i,led.Color(0,0,0));


led.show();
delay(20);
}


        for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }



   while(1){
                          int status3 ;
                          int status4 ;
                          int status5 ;
        status3 = digitalRead(input_pin3) ; //スイッチの状態を読む
         status4 = digitalRead(input_pin4) ; //スイッチの状態を読む
          status5 = digitalRead(input_pin5) ; //スイッチの状態を読む

int t = 0;
int l = 0;
int m = 0;

                    if(status3 == HIGH){
                      digitalWrite(13, LOW);   // スイッチをONする

                      while(t<250){
 for(int i = 0 ; i < LED_COUNT ; i++ )
{
led.setPixelColor(19+i,led.Color(0,0,255));
led.setPixelColor(20+i,led.Color(0,0,0));

led.setPixelColor(19-i,led.Color(0,0,255));
led.setPixelColor(18-i,led.Color(0,0,0));


led.show();
delay(20);
t++;
}
                      }




  goto label;
   }else if(status4 == HIGH){

digitalWrite(13, LOW);   // スイッチをONする

                        while(l<500){

 for(int i = 0 ; i < LED_COUNT ; i++ )
{
led.setPixelColor(19+i,led.Color(255,0,0));
led.setPixelColor(20+i,led.Color(0,0,0));

led.setPixelColor(19-i,led.Color(255,0,0));
led.setPixelColor(18-i,led.Color(0,0,0));


led.show();
delay(20);
l++;
}
                        }



                         goto label;

                      }else if(status5 == HIGH){

digitalWrite(13, LOW);   // スイッチをONする

int m = 0;
while(m<1000){
 uint16_t i, j;

 for(j=0; j <256; j++) {
   for(i=0; i < led.numPixels(); i++) {
     led.setPixelColor(i, rotateColor((((i) * 256 / led.numPixels()) + j) & 255));
   }
   led.show();
   delay(10);
m++;
}
}



                         goto label;
                      }


                  }
      }
label:;
}

//RGBの色の移り変わり関数
uint32_t rotateColor(byte WheelPos) {
  if(WheelPos < 85) {
   return led.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if(WheelPos < 170) {
   WheelPos -= 85;
   return led.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
   WheelPos -= 170;
   return led.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • y_waiwai

    2019/03/21 18:09

    このままではコードが見づらいので、質門を編集し、<code>ボタンで、出てくる’’’の枠の中にコードを貼り付けてください

    キャンセル

  • y_waiwai

    2019/03/21 18:14

    そんで、Arduinoは何を使ってるんでしょう、回路構成はどういうものでしょうか。回路図を提示してください。

    キャンセル

  • thkana

    2019/03/21 22:06

    質問の内容にC#は全く関係ありません。C#タグは外しましょう。

    キャンセル

回答 3

checkベストアンサー

+1

先に2,3の方から。
全部組み上げて、動かなくて何が悪いかわからない...なら、ひとつずつ確実に動かしてみて下さい。
余計なパーツ、プログラムは無し。サーボを動かすだけ...出来た?
テープLEDを白く光らせるだけ...出来た?
(Arduino LEDテープについてで白を設定してみればいいですね。)
それが出来たら、組み合わせ...出来た?

LEDテープは持っていないので確認できませんけれど、少なくとも私の手元でサーボだけは動きましたが、質問のプログラムではサーボが異常動作しました。
前述のようにLEDテープを持っていないので確認できませんが、LEDライブラリの方もServoとの干渉で異常動作して白が出ていないんじゃないか、と想像します。
NeoPixel and Servo libraries won’t work together in the same Arduino sketch
だそうです。同ページで、別のServoライブラリの使用を提案して、そこからのリンク先で使い方を説明しています(Arduino m0はすでに製造中止になっちゃった)。手元でServoライブラリの差し替えでサーボモーターの動作は確認しました。

別件。
まさかと思いますが、スイッチを5Vと入力ピン間に繋いだだけで、オープンではLOW、なんて思い込んでいませんね?入力ピンを単純にオープンしたら「どうなるかわからない」ですから。スイッチを入力端子に付けるなら、プルアップまたはプルダウン抵抗と併用するなど適切な回路にして下さい。(プルアップ/プルダウンで検索すれば山程の例が見つかるはずですが、見つからない/理解できないということならまた聞いて下さい)

で、1.
割り込みを使わずにリアルタイム(一定時間内に刺激に反応することが保証されている、という意味)システムを組みたいのなら、直接的に長時間のdelayや、結果として長時間になるループ中でのdelayの使用は出来ません。(結局、ごく短い時間以外のdelayはダメだよ、ということ)
質問のプログラムを書き換える気力はとてもありませんから、考え方を単純なプログラムで説明しましょう。

例えば、3秒点灯1秒消灯の周期で点滅しているLEDがあって、スイッチを押すと押している間消灯する、というものを考えてみましょう。
まずダメダメな例。

const int SW = 4;
//スイッチは入力ピンとGNDの間につなぐ。
//入力端子は内部プルアップを使って定常HIGHレベルを確保する
//スイッチ押すとLOW, 離すとHIGH
const int LED = 13;

const int ON_PERIOD = 3000;
const int OFF_PERIOD = 1000;

void setup() {
  pinMode(SW, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

void loop() {
  digitalWrite(LED, HIGH);
  delay(ON_PERIOD);
  digitalWrite(LED, LOW);
  delay(OFF_PERIOD);
  bool swState;
  do {
    swState = digitalRead(SW) == LOW; //
    if (swState) {
      digitalWrite(LED, LOW);
    }
  } while (swState);
}


4秒周期のひと仕事が終わった瞬間しかスイッチを検査していません。それ以外は何が起ころうとプログラムは検知出来ず、当然反応も出来ません。長時間delayを使い割り込みを使わないなら、どうしようもない動作です。ではどうするか...長時間delayを短時間delayの積み重ねにします。まずはその方法で点滅だけやってみましょう。

const int LED = 13;

const int ON_PERIOD = 3000;//ON時間
const int OFF_PERIOD = 1000;//OFF時間
const int TICK=10; //単位時間
int count=0; //時間計測用変数

//状態変数設定
const int LED_ON = 0;//状態名1
const int LED_OFF= 1;//状態名2
int stat=LED_ON;//状態を保持する変数
/*
 * enum STAT{
 * LED_ON,
 * LED_OFF,
 * } stat;
 * としたほうが好ましいけど...
 */

void setup() {
  pinMode(SW, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

void loop() {
  int ledStat=LOW;
  if(stat==LED_ON){
    //LED_ON状態のときの動作を記述
    ledStat=HIGH;
    if(++count>ON_PERIOD/TICK){
      //ON_PERIOD時間が経過したら
      //LED_OFF状態に移行
      count=0;
      stat=LED_OFF;
    }
  } else if(stat==LED_OFF){
    //LED_OFF状態のときの動作を記述
    ledStat=LOW;
    if(++count>OFF_PERIOD/TICK){
      //OFF_PERIOD時間が経過したら
      //LED_OFF状態に移行
      count=0;
      stat=LED_ON;
    }
  }
  digitalWrite(LED,ledStat);
  delay(TICK);
}


loop()関数自体はTICKのdelayだけでさっさと抜けてしまいます。逆に言うと、TICK時間毎にloop()に仕込んだ仕事を一通りやってくれるということなので、スイッチの検査を仕込めばTICK時間毎にスイッチ動作を行うことが出来る、つまり「即反応する」ということになります。

const int SW = 4;
const int LED = 13;

const int ON_PERIOD = 3000;//ON時間
const int OFF_PERIOD = 1000;//OFF時間
const int TICK = 10; //単位時間
int count = 0; //時間計測用変数

//状態変数設定
const int LED_ON = 0;//状態名1
const int LED_OFF = 1; //状態名2
int stat = LED_ON; //状態を保持する変数

void setup() {
  pinMode(SW, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

void loop() {
  int ledStat = LOW;
  int swStat = digitalRead(SW);
  if (swStat != LOW) {//スイッチの検査
    //押されていなかったら点滅処理
    if (stat == LED_ON) {
      ledStat = HIGH;
      if (++count > ON_PERIOD / TICK) {
        count = 0;
        stat = LED_OFF;
      }
    } else if (stat == LED_OFF) {
      ledStat = LOW;
      if (++count > OFF_PERIOD / TICK) {
        count = 0;
        stat = LED_ON;
      }
    }
  }else{
    ledStat=LOW;
  }
  digitalWrite(LED, ledStat);
  delay(TICK);
}


あるいは、Arduinoには経過時間を知るmillis()という関数があるので、これを時間経過を知るのに使えばdelay()を完全に排することも出来て

const int SW = 4;
const int LED = 13;

const int ON_PERIOD = 3000;//ON時間
const int OFF_PERIOD = 1000;//OFF時間
long tRef = 0; //時間計測用変数

//状態変数設定
const int LED_ON = 0;//状態名1
const int LED_OFF = 1; //状態名2
int stat = LED_ON; //状態を保持する変数

void setup() {
  pinMode(SW, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
  tRef=millis();//状態に入る基準の「時刻」を記録
}

void loop() {
  int ledStat = LOW;
  int swStat = digitalRead(SW);
  long t=millis();//現在の「時刻」を取得
  if (swStat != LOW) {//スイッチの検査
    if (stat == LED_ON) {
      ledStat = HIGH;
      if (t-tRef > ON_PERIOD) {//現在時刻-基準時刻即ち経過時間
        tRef = t;
        stat = LED_OFF;
      }
    }else if (stat == LED_OFF) {
      ledStat = LOW;
      if (t-tRef > OFF_PERIOD) {
        tRef = t;
        stat = LED_ON;
      }
    }
  }else{
    ledStat=LOW;
  }
  digitalWrite(LED, ledStat);
}

ただし、これは「原理」に過ぎません。

あなたのプログラムにどんな「状態」があるのかを考えて、その状態間をどのようなトリガで移行するのか(スイッチであったり時間であったり)、というのを積み上げていけば、あなたのプログラムも応答性をよく出来る...はずです。ただ、漠然とdelayするプログラムと比べて「自分が何をやりたいのか」をきちんと把握しないとなかなか形に出来ないかも知れません。まぁ、頑張って下さい。

--追記--
BA選択後になりますが。

この機にAmazonでLEDテープをポチって遊んでみています。
で、

#include <Servo.h>
#include <Adafruit_NeoPixel.h>

const int LED_COUNT=60;
const int DIGITAL_PIN=6;

Adafruit_NeoPixel led = Adafruit_NeoPixel( LED_COUNT, DIGITAL_PIN , NEO_GRB + NEO_KHZ800);
Servo sv;

void setup() {
  led.begin();
  led.show();
  sv.attach(7);
}

int lvl;
void loop() {
  lvl=(lvl+1)%256;
  led.setPixelColor(0,led.Color(lvl,lvl,lvl));
  led.show();
  delay(10);
}


としてみました。サーボモーターはやはりひくひくしますが、LEDは白く光ります(セル内で各色がバラけて見えるのは仕方ないとして)。
このプログラムだとあなたの環境でも白になる、とかいうことはないでしょうか。電源が弱くて、LEDを1個だけ点灯しても大丈夫だけどたくさん点けると電圧降下を起こして、LEDのVfの大きい青とか緑のLEDの発光が弱くなる、とかいうことはあり得そうな気がします。試しに手元に転がっていた330Ωの抵抗をLEDテープの電源ラインにいれて上記プログラムを走らせてみたところ、赤LEDのみが点灯する(で明るさが変わる)状態になりました。そのモードであれば、LEDテープに供給する電源の強化が対策になりそうに思います。LEDテープの電源を3.3Vにしてみてもまだ白で光るので、それよりも下がっているとすると相当なものですけれど...

まぁ、いろいろやってみて下さい。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/25 20:20

    「電源が弱い」という表現がわかりにくかったですかね。おっしゃる通り、電流が少なければ正常に動作しても、電流をたくさん流そうとすると電圧が下がっちゃう、という疑念です。
    40個の3色LEDで各色各20mAずつ流せば2.4Aですから、それに耐える電源を選ばないと。PCのUSBコネクタからなんかじゃ全然足りません(USB2で500mA以下、USB3でも900mA以下です)。

    キャンセル

  • 2019/03/27 00:13

    原因はそこにあったのですね。早速、電圧の大きい電源を買ってみます!色々ありがとうございます。

    キャンセル

  • 2019/03/27 07:30

    電圧じゃなくて電流、ね。
    一般的に「電源」はある一定の電圧を出力する装置です。しかし、想定以上の電流を取り出そうとして、電圧を維持できなくなって下がってしまった、のが今回の事態。だから、より大きな電流を取り出しても電圧が維持できる電源を使いましょう、ということ。

    キャンセル

+1

コードを見てるとなかなかデタラメなので、これをこうしたら、というアドバイスはできかねます

まずは、配線をしっかりチェックして、あなたが想定する出力をしたら想定している結果が出るように、基本的な動作をチェックしましょう
・サーボモータは想定される出力で想定される動作をするかどうか
・LED出力も想定された出力で想定された色で光るのかどうか

いきなり動かすようなコードを書くのではなく、個別にこれらの動作をさせるコードを走らせ、どうなるか見てみることですね

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

直接的な回答ではないですが。

1について
attachInterruptを使うことで、IOに変化等があった場合、割り込み処理を行えます。
ただし、loop()内でdelayによる時間待ちが結構あるのでうまく実装できるかどうかは不明です。
まずdelayを呼ばないような実装にすれば、loop内の処理が速くなるのでは。

1、Interruptを使うとdelayが使えなくなってしますが、delayを使いたいです。

スイッチの検知のタイミングをもっと短くするには、loop内の処理時間をもっと短くする必要があります。
delayを使う理由を明確にし、それを実現しかつloop内の処理時間を短くするように設計をするしかないです。
例えば、スイッチを押した時間からの経過時間を利用して、LEDやサーボを回すような設計にするとか。

2について
コードを見る限り、input_pinとinput_pin2がHIGHの間5秒位サーボが0~180度の間を往復しているようなので、もしかしたらコード通りの動作をしているのでは。

2、何故かinput_pin1,2がLOWの時は微動します...試してみると、LEDテープを動かす間にサーボモーターが微動しました。

LEDの駆動でノイズとかが入っているのではないですか。
LED部分を外してみて想定した動作になるか確認し、想定通りであれば、LED部分が悪いということになります。まあそうであれば、これ以上は、ハードよりの話になるため、ちょっと回答は難しいかも。

3について
led周りの実装がちょっとおかしい感じがします。
showは全部のledの色の設定が終わったら1回だけやればいいはず(for分の外にshowがあるべき?)
それとも、40個のLEDを中心から流れるような感じに表示させたいのかな。

一応、オレンジというとr,g,bが(255,165,0)近辺ですが、もしあるとすると、rotateColorに渡すWheelPosが60近辺が比率的に近い値になるかも。

とりあえず、現在どこが動いているかをSerial.printなどで出力しながら動作確認をしたらどうですか。

3、その通りで、自分は真ん中から流れるものを作りたいのですが、白色だけがどうしても出ないんです。

自分もマイコン内蔵のフルカラーLED(PL9823)を動かしたときがあるのですが、結構タイミングがシビアで決まった色にならない場合がありました。
こっちもLED40個をドライブするのではなく、初めに5個とか10個とかから始めてみたらどうですか。
もし、それでうまくいけば、複数ピンで40個を制御すればいいのでは。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/22 07:45

    1、Interruptを使うとdelayが使えなくなってしますが、delayを使いたいです。

    2、何故かinput_pin1,2がLOWの時は微動します...試してみると、LEDテープを動かす間にサーボモーターが微動しました。

    3、その通りで、自分は真ん中から流れるものを作りたいのですが、白色だけがどうしても出ないんです。

    2、3に関しては回路がおかしいというのも十分有り得ますか?(結構ぐちゃぐちゃしてて自分はそんな気がします、、)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.64%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る