ebisukeプログラミング初心者脱出黙示録

30歳を過ぎてから始めたプログラミングと競プロの記録。Pythonで取り組んでいます。Arduinoで電子工作も

初心者のArduinoプログラミング入門⑩【超音波センサ編】

今回もArduinoで遊んでみます!

この記事では、超音波センサを使って「対象物までの距離」を測る方法について記事にしていきます。

目標

超音波センサの基本的な使い方を学習して距離を測ってみます。

ライブラリを使用する方法と距離を計算する方法の2種類を試しました!

回路図

超音波センサ HC-SR04には4つのピンがあり、
今回は以下のように接続しました。

VCC -> 5V

Trig -> 11番ピン

Echo -> 12番ピン

GND -> GND

このような回路図になります。

専用ライブラリ(SR04.h)を使うスケッチ

#include "SR04.h"
const int TRIG_PIN = 11;
const int ECHO_PIN = 12;
SR04 sr04 = SR04(ECHO_PIN,TRIG_PIN);
long distance;

void setup() {
   Serial.begin(9600);
   delay(1000);
}

void loop() {
   distance=sr04.Distance();
   Serial.print(distance);
   Serial.println("cm");
   delay(1000);
}

ライブラリが計算をすべてやってくれるので、sr04.Distance() を呼び出すだけで距離が取得できます。

非常に楽ちんです!

動作確認



壁から約10cm離したときにシリアルモニタにはだいたい10cmが表示されました。




次に20cm離すと今度はシリアルモニタには20cmが表示されました。

なかなか値も安定しています。


ライブラリを使わずに計算するスケッチ

const int TRIG_PIN = 11;
const int ECHO_PIN = 12;

long sonic_speed;

void setup() {
   sonic_speed = 340; // 音速を340m/sと定義
   pinMode(TRIG_PIN, OUTPUT);
   pinMode(ECHO_PIN, INPUT);
   Serial.begin(9600);
}

void loop() {
   // トリガーピンを一度LOWにする
   digitalWrite(TRIG_PIN, LOW);
   delay(1000);

   // 10マイクロ秒間だけHIGHを出力して超音波を発射
   digitalWrite(TRIG_PIN, HIGH);
   delayMicroseconds(10);
   digitalWrite(TRIG_PIN, LOW);

   // 跳ね返ってくるまでの時間を計測(単位:マイクロ秒)
   unsigned int result = pulseIn(ECHO_PIN, HIGH, 200000);

   if (result > 0){
    // 距離(cm) = 音速(340m/s) * 時間(us) / 1000000(秒換算) * 100(cm換算) / 2(往復分)
    long distance = sonic_speed * result * 100 / 1000000 / 2;
    Serial.print(distance);
    Serial.println("cm");
   }
}

pulseIn 関数で超音波が跳ね返ってくるまでの時間を測り、計算式で距離を出しています。

仕組みを理解するには、こちらの書き方の方が勉強になりますね。

動作確認


こちらも壁から約10cm離すとおよそ10cmが表示されました。



20cm離したときは20cmが計測されました。

まとめ

今回は超音波センサを使って距離の計測に挑戦しました。

ライブラリで手軽に済ませたときも、計算式を書いたときもほぼ同じような測定結果になりました。

2つのプログラムの測定結果が同じになって実は少しだけ安心しました (笑)





この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門⑨【ボールスイッチ編】

今回は傾きでON/OFFするボールスイッチを使って、Arduinoの内蔵LEDを制御してみます!

目標

シンプルにボールスイッチの入力に応じて内蔵LEDを点灯させたり消灯させたりします。

今回は全然工夫してません!(笑)

回路図

ボールスイッチは2番ピンに接続します。

ボールスイッチに極性はなく、プラスとマイナスを気にせず接続しました。

オスメスのジャンプワイヤーが便利です。

このような回路図になります。

リズム変化のスケッチ

const int ledPin = 13;
const int tilt = 2;

void setup()
{ 
  pinMode(ledPin,OUTPUT);//内蔵LEDを出力に設定
  pinMode(tilt,INPUT);//ボールスイッチを入力に設定
  digitalWrite(tilt, HIGH);
} 

void loop() 
{  
  int digitalVal = digitalRead(tilt);
  if(HIGH == digitalVal)
  {
    digitalWrite(ledPin,LOW);//LED消灯
  }
  else
  {
    digitalWrite(ledPin,HIGH);//LED点灯 
  }
}

ボールスイッチは2番ピンで入力に設定し、
入力にあわせて内蔵LEDをON/OFFしています。

これでボールスイッチ傾けるとLEDが点灯/消灯するはず!です。

動作確認


www.youtube.com

ボールスイッチの傾きでLEDが変化しました!

シンプルなプログラムは安心します。

まとめ

今回はボールスイッチでLEDを制御してみました。

安全装置として使い道がありそうですね!




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門⑧【パッシブブザー編】

今回もArduinoで遊んでみます!

この記事ではArduinoで加える周波数に応じて音の高さが変わるパッシブブザーを使って音を出します。

せっかくなので がんばって聞き覚えのある曲を演奏してみます!

目標

アクティブブザー編と同じようにブレッドボード、パッシブブザーと押しボタンを使用して回路を作ります。

今回は押しボタンでリズムを変えることに挑戦しました。

まずは練習で聞き覚えのあるメロディーを流して、それが出来たら押しボタンでリズムを変化させます!

回路図

パッシブブザーはプラスとマイナスが決まっていますので間違えないように接続します。

よくみるとプラスマークがついていますので、ちゃんと確認して配置しました。

押しボタンでリズムを変えるときに割り込み処理を使うつもりなので、割り込み処理ができる2番ピンに押しボタンを接続しました。

このような回路図になります。

あのメロディーのスケッチ

#include "pitches.h"

// リズムを500msecに設定
int duration = 500;
 
void setup() {
 
}
 
void loop() {  
  // 以下、演奏
  tone(12, NOTE_AS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  tone(12, NOTE_DS5, duration);
  delay(duration);
  tone(12, NOTE_CS5, duration);
  delay(duration);
  tone(12, NOTE_DS5, duration);
  delay(duration);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration);
  tone(12, NOTE_AS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration*2);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  delay(2000);
}

pitches.hライブラリを使用します。

このライブラリには音階の周波数が定義されていますので
ド:C レ:D ミ:E ファ:F ソ:G ラ:A シ:BとしてNOTE_*1の*に出したい音のアルファベットを入れるとその周波数を出すことができます。

数字を大きくすると高い音になり、数字の前にSをつけるとシャープになります。
(pitches.hでググると詳しい情報が出てきますので、気になる方は調べてみてください。)

durationに基準となる音の長さを定義して、tone関数で音を出します。

tone関数はtone(pin,frequency,duration)のように使用して、
pinには出力するピン番号を、frequencyには出力周波数[Hz]を、durationに出力する時間[msec]を入力します。

tone関数のdurationと同じだけdelayすることで決められた時間だけ音を出すことができます。

そしてスケッチのように音を並べると…リ○スのいらないメリット♪が聞こえてくるはず!です。

あのメロディーの動作確認


www.youtube.com

これはまさしくリ○スのいらないメリット♪じゃないですか!

少し感動を覚えながら、次はボタンを押すことでリズムを変えてみたいと思います。

リズム変化のスケッチ

#include "pitches.h"

// 2番ピンをbuttonで表示
int button = 2;

// ボタンが押されたかのフラグ
volatile bool Flag=false;

// 基準のリズム
int duration = 500;
 
void setup() {
  //2番ピンをプルアップ付きの入力ピンとして設定する
  pinMode(button,INPUT_PULLUP);
  //2番ピンが押された瞬間に関数Pushed()が実行されるように設定する
  attachInterrupt(digitalPinToInterrupt(button),Pushed,FALLING);
 
}
 
void loop() {  
  // 演奏の前にボタンが押されたかフラグを確認しリズムを決定する
  if (Flag == true){
    duration = 200;  // 200 miliseconds
  } else{
    duration = 500;  // 500 miliseconds
  }
  // フラグのリセット
  Flag = false;

  // 以下、演奏
  tone(12, NOTE_AS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  tone(12, NOTE_DS5, duration);
  delay(duration);
  tone(12, NOTE_CS5, duration);
  delay(duration);
  tone(12, NOTE_DS5, duration);
  delay(duration);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration);
  tone(12, NOTE_AS5, duration);
  delay(duration);
  tone(12, NOTE_GS5, duration);
  delay(duration*2);
  tone(12, NOTE_FS5, duration);
  delay(duration);
  delay(2000);
}

//ボタンを押されたときの割り込み処理
void Pushed(){
  // ボタンが押されたらフラグを立てる
  Flag = true;
}

リズムを変化させる押しボタンは2番ピンに接続しました。

ボタンを押したら次の演奏のリズムが早くしたいと思って調べると、割り込み処理が適していたので使ってみました。

まず、volateileは割り込み処理の中と外で使う変数を宣言するときに使用し、
今回はボタンが押されたかのフラグに使いました。

attachInterrupt(digitalPinToInterrupt(button),Pushed,FALLING)のattachInterrupt関数は割り込み処理の関数です。

attachInterrupt(割り込み番号,実行する関数,割り込み発生条件)のような引数になっていて、
割り込み番号とピン番号は違っていますがdigitalPinToInterrupt(button)を使用するとピン番号を割り込み番号に変換してくれます。

ボタンを押すとPushed関数が実行され、
その発生条件はFALLING:ピンの電圧がHIGHからLOWに変化したときとなっています。
(こちらも割り込み処理で調べると詳しい情報が出てきます。)

ボタンを押すとPushed関数が実行され、
FlagがONされることで各演奏が始まる前にdurationが変更されてます。

これでボタンを押すとリズムが変化するはず!です。

動作確認


www.youtube.com

押しボタンで演奏が早くなりました!

スピートを変えると演奏の印象もけっこう変わりますね。

まとめ

今回はパッシブブザーで音を出し、割り込み処理を使ってリズム変化を楽しめました!

リ○スのいらないメリット♪って若い子もわかります…よね、とちょっとだけ不安になりました。




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門⑦【アクティブブザー編】

今回もArduinoで遊んでみます!

この記事ではArduinoを使ってアクティブブザーで音を鳴らします。

ブザーにもいろいろな種類がありますが、直流電流を加えるだけで音が出るアクティブブザーを使います!

目標

ブレッドボード、アクティブブザーと押しボタンを使用して回路を作ります。

音を出すだけなら押しボタンはいりませんが、ボタンを使って音を変えることにも挑戦しました。

まずは練習でブザーで音を出し、それが出来たら押しボタンで音を変化させてみます!

回路図

アクティブブザーはプラスとマイナスが決まっていますので間違えないように接続します。

押しボタンは制御するピンに接続しました。

このような回路図になります。

音を出す練習スケッチ

// 12番ピンにアクティブブザーを割り付け
int buzzer = 12;

void setup()
{
  // ブザーのピンを出力に設定
  pinMode(buzzer, OUTPUT);
}
void loop()
{
  digitalWrite(buzzer, HIGH);
  delay(1000);

  digitalWrite(buzzer, LOW);
  delay(1000);
}

12番ピンをブザーの出力に設定します。

そしてブザーをONして1秒(1000msec)待つ、ブザーをOFFして1秒待つを繰り返すプログラムです。

練習の動作確認


www.youtube.com

プログラムを書き込むと1秒ごとにオンオフを切り替えることができました!

次はボタンを押すことで音を変えてみましょう。

音を変化させるスケッチ

// 12番ピンにアクティブブザーを割り付け
int buzzer = 12;
// 2番ピンに押しボタンを割り付け
int button = 2;

void setup()
{
  // ブザーを出力に設定
  pinMode(buzzer, OUTPUT);
  // ボタンを入力に設定
  pinMode(button, INPUT_PULLUP);
}
void loop()
{
  //ボタンを押す押さないでブザー周期を変更
  if (digitalRead(button) == HIGH ){
    digitalWrite(buzzer, HIGH);
    delay(25);
    digitalWrite(buzzer, LOW);
    delay(25);
    } else {
    digitalWrite(buzzer, HIGH);
    delay(100);
    digitalWrite(buzzer, LOW);
    delay(100);
    }
}

音を変化させる押しボタンは2番ピンに接続しました。

if文でボタンを押したときは0.1秒ごとに、
そうでないとき(押されていないとき)は0.025秒ごとにブザーをオンオフします。

これでボタンで音が変化するはず!です。

動作確認


www.youtube.com

押しボタンで音が変わりました!

思った通りに動いてくれると気持ちいいですね。

まとめ

今回はアクティブブザーで音を出し、簡単な音の変化も楽しめました!

夜中にブザーを鳴らすと、思いのほか音が大きくてビクッとなったのは秘密です。




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

初心者のArduinoプログラミング入門⑥【RGB LED編】

私生活でいろいろあって放置していましたが、
めちゃくちゃ久しぶりに更新してみました。

この記事ではArduinoを使って赤緑青の三原色の光を
ひとつの素子で出すことができるRGB LEDの使い方を学習します。

周期的に色を変化させるプログラムを動かしてみたいと思います!

目標

ブレッドボード、抵抗とRGB LEDを使用して回路を作ります。

周期的にRGB LEDの色を変化させながら点灯させることを目標にします!

回路図

RGB ブレッドボード

RGB LEDの一番長い足をGNDに、RGBのそれぞれの足は抵抗につなげた後に制御するピンに接続しました。

RGB 回路図

上図のような回路図になります。

スケッチ

//ピン3,5,6を青、緑、赤LEDに割り付け
const int blueLed = 3;
const int greenLed = 5;
const int redLed = 6;

void setup()
{
//ピン3,5,6を出力に設定
pinMode(blueLed, OUTPUT);
pinMode(greenLed, OUTPUT);
pinMode(redLed, OUTPUT);
}

void loop()
{
int redValue; //赤色の強さの変数(最大255)
int greenValue; //緑色の強さ変数(最大255)
int blueValue; //青色の強さ変数(最大255)

//各色の初期値設定
redValue = 255;
greenValue = 0;
blueValue = 0;


//赤色を255→0、緑色を0→255に変化
for(int i = 0; i < 255; i++)
{
redValue = 255 - i; //赤色の強さを1ずつ弱くする
greenValue = i; //緑色の強さを1ずつ強くする
analogWrite(redLed, redValue); //赤色の強さを書き込み
analogWrite(greenLed, greenValue); //緑色の強さを書き込み
delay(10);
}

//緑色を255→0、青色を0→255に変化
for(int i = 0; i < 255; i++)
{
greenValue = 255 - i; //緑色の強さを1ずつ弱くする
blueValue = i; //青色の強さを1ずつ強くする
analogWrite(greenLed, greenValue); //緑色の強さを書き込み
analogWrite(blueLed, blueValue); //青色の強さを書き込み
delay(10);
}

//青色を255→0、赤色を0→255に変化
for(int i = 0; i < 255; i++)
{
blueValue = 255 - i; //青色の強さを1ずつ弱くする
redValue = i; //赤色の強さを1ずつ強くする
analogWrite(blueLed, blueValue); //青色の強さを書き込み
analogWrite(redLed, redValue); //赤色の強さを書き込み
delay(10);
}
}

まずアナログ出力できる3,5,6番ピンをそれぞれ青・緑・赤色LEDの出力に設定します。

各色の強さを変化させますので、色の強さを変数として宣言しておき、初期値を設定させます。

このあと、赤緑/緑青/青赤の2色ずつfor文内で強さを変化させていき、analogWrite関数でピンにかかる電圧を制御しました。
(i = 0のときは0Vで、i = 255のとき5V出力されます。)

これで赤→黄→緑→水色→青→紫→赤のようにLEDの色が変化するはず!です。

動作確認


www.youtube.com

プログラムを書き込むと時間とともにLEDの色が変化しました!

ちゃんと予想していた順番で色が変化しています。

まとめ

今回はRGB LEDで各素子の光る強さを変化させる方法を学び、様々な色を出すことができました。

光の3原色って本当だった、と実感できました!




この記事で使用しているArduinoは elegooというメーカの互換品です。

部品もついてきて安価なので学習用に購入しました。

AtCoder-ABC227 A - Last Card / B - KEYENCE building【Python解答例】

キーエンスプログラミングコンテスト2021-Nov. (AtCoder Beginner Contest 227)のA とB問題についてPythonの解答例を記事にしていきます。
KEYENCE Programming Contest 2021 (AtCoder Beginner Contest 227) - AtCoder



AtCoder Beginner Contest227 A - Last Card

A - Last Card

問題文

1,2,…,N の番号のついた N 人の人に合計 K 枚のカードを配ります。

人 A から始めて 人 A,A+1,A+2,…,N,1,2,… の順に 1 枚ずつカードを配るとき、最後のカードは誰に配られるでしょうか?

厳密には、人 x(1≤x

制約

・1≤N,K≤1000
・1≤A≤N
・入力は全て整数

解答例

n, k, a = map(int,input().split())

ans = (k+a-1) % n

if ans == 0:
    print(n)
else:
    print(ans)

解説

N人の人に対してK枚のカードをA番目の人から一枚ずつ配るときに、何番目の人に最後のカードが配られるか答える問題です。

K + A - 1をNで割った余りが答えansになりますが、番号が0番の人はいないのでansが0ときはN番目の人が答えとなります。

この結果を出力すればOKでした。



AtCoder Beginner Contest227 B - KEYENCE building

B - KEYENCE building

問題文

1 から N の番号がついた N 人の人がいます。

人 i はキーエンス本社ビルの建築面積を S i 平方メートルであると予想しました。

キーエンス本社ビルは下図のような形をしています。ただし、a,b はある 正の整数 です。
つまり、キーエンス本社ビルの建築面積は 4ab+3a+3b 平方メートルと表されます。

N 人のうち、この情報のみによって、予想した面積が確実に誤りであるとわかる人数を求めてください。

制約

・1≤N≤20
・1≤S i​ ≤1000
・入力に含まれる値は全て整数である

解答例

n = int(input())

S = list(map(int, input().split()))

ans = 0
for i in range(n):
    flag = False
    for a in range(1,S[i]):
        for b in range(1,S[i]):
            if 4*a*b + 3*a + 3*b == S[i]:
                flag = True
    if not flag:
        ans += 1

print(ans)

解説

Siを満たす正の整数a,bが存在するか全探索する問題です。

N人の予想をひとつずつ調べます。

aとbが存在する場合、その値はS[i]以下なので探索範囲はそこまでとします。

S[i]を満たす組み合わせがあればflagをTrueにして管理し、a,bの探索後もflagがFalseのままであればansに1を足しました。

ループを抜けたあとにansを出力すればACです。

AtCoder-ABC226 A - Round decimals / B - Counting Arrays【Python解答例】

AtCoder Beginner Contest226のA とB問題についてPythonの解答例を記事にしていきます。
AtCoder Beginner Contest 226 - AtCoder



AtCoder Beginner Contest226 A - Round decimals

A - Round decimals

問題文

小数第三位までで表すことのできる実数 X が、小数第三位まで入力されます。
X を小数第一位で四捨五入した結果として得られる整数を出力してください。

制約

・0≤X<100
・X は小数第三位までで表現可能である。
・X は小数第三位まで与えられる。

解答例

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

x = float(input())

ans = Decimal(str(x)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)

print(ans)

解説

小数第三位まで与えられたとき、小数第一位で四捨五入した結果を答える問題です。

Pythonで四捨五入をするためにdecimalモジュールをインポートします。

解答例のコードで小数第一位を四捨五入することができ、ansを出力してACでした。



AtCoder Beginner Contest226 B - Counting Arrays

B - Counting Arrays

問題文

1 から N までの番号がついた N 個の数列が与えられます。
数列 i は、長さが L i​ で j (1≤j≤L i​ ) 番目の要素が a i,j​ であるような数列です。

数列 i と 数列 j は、 L i​ =L j​ かつすべての k (1≤k≤L i​ ) に対して a i,k​ =a j,k​ が成り立つ時に同じであるとみなします。
同じ数列は 1 種類として数えるとき、数列 1 から 数列 N の中に全部で何種類の数列がありますか?

制約

・1≤N≤2×10 ^5
・1≤L i​ ≤2×10 ^5 (1≤i≤N)
・0≤a i,j​ ≤10 ^9 (1≤i≤N,1≤j≤L i​ )
・すべての数列の要素の個数の和、すなわち ∑ i=1N​ L i​ は 2×10 ^5 を超えない。
・入力はすべて整数である。

解答例

n = int(input())

A = set()
for i in range(n):
    array = input()
    A.add(array)

print(len(A))

解説

N個の数列が与えられたとき異なる数列が何個あるか答える問題です。

数列を文字列で受け取り、setを使うことで同じ数列を除去していきます。

すべての重複を確認したあとで、Aの長さ(個数)を出力すればOKでした。

AtCoder-ABC225 A - Distinct Strings / B - Star or Not【Python解答例】

AtCoder Beginner Contest225のA とB問題についてPythonの解答例を記事にしていきます。
UNICORN Programming Contest 2021(AtCoder Beginner Contest 225) - AtCoder



AtCoder Beginner Contest225 A - Distinct Strings

A - Distinct Strings

問題文

英小文字のみからなる長さ 3 の文字列 S が与えられます。

S の各文字を並び替えて得られる文字列は、何種類ありますか?

制約

・S は英小文字のみからなる長さ 3 の文字列

解答例

S = input()

if S[0] == S[1] and S[1] == S[2]:
    print(1)
elif S[0] != S[1] and S[1] != S[2] and S[2] != S[0]:
    print(6)
else:
    print(3)

解説

3文字の英子文字から何通りの文字列がつくれるか答える問題です。

3文字のなかに同じ文字があるかで場合分けを行いました。

3文字がすべて同じ文字の場合は、できる文字列は1通りだけです。

すべて文字が異なれば、文字列は6通りできます。

そうでなければ、おなじ文字が2つの場合になりますので、そのときは3通りです。

この場合分けで答えを出力すればOKでした。




AtCoder Beginner Contest225 B - Star or Not

B - Star or Not

問題文

N 頂点 N−1 辺の木が与えられます。

頂点には 1,2,…,N の番号がついており、i 本目の辺は頂点 a i​ と頂点 b i​ を結んでいます。

この木がスターであるか判定してください。

ただしスターとは、1 つの頂点から、他の全ての頂点に 1 本ずつ辺が出ている木のことです。

制約

・3≤N≤10 ^5
・1≤a i​

解答例

n = int(input())

graph = [[] for _ in range(n)]
for i in range(n-1):
    a, b = map(int,input().split())
    a -= 1
    b -= 1
    graph[a].append(b)
    graph[b].append(a)

res = 0
for i in range(n):
    res = max(res,len(graph[i]))

if res == n-1:
    print("Yes")
else:
    print("No")

解説

N頂点N-1辺の木が与えられ、その木がスターか判別する問題です。

スターとは問題文にあるように、1つの頂点からほかのすべての頂点に1本ずつ辺がでている木のことです。

配列graphを用意して、各頂点から出ている辺を格納していきます。
graph[i]には頂点iから辺でつながっているほかの頂点が保存されています。

したがって、変数resを用意し、ひとつの頂点から出ている辺の最大値を求めました。

このresがn-1ならばその木はスターで、そうでなければスターでないと判別できました。