2026年3月27日金曜日

脳トレゲームボードを使った制御演習 資料配布

「 脳トレゲーム対応制御学習ボード演習」の資料配布ページです。

演習資料配布

これまで掲載してきた制御学習などをまとめて資料にしました。
 ・演習の解答例(ZIP)

学習ボードを「脳トレゲーム」にするためのソースコード
 こちらは、解凍後ArduinoIDEよりプログラムを書き込んでください。

訂正・アップデートなど

 こちらで訂正事項や、ソースのアップデート情報を提供いたします。


2026年3月16日月曜日

3D造形部品のジョイント(接続)の改良

 3D造形部品の接続の不具合

 ものづくりキットなどを手軽に接続する方法として、タッピングネジを利用してきました。これは、子供たち(小学生)が簡単に部品を組み立てるときに、ドライバのみで締め付けることで組み上がるためです。
 また、間違えた時にも、簡単にネジを外して、修正することができます。

 しかし、テオヤンセンロボットを製作しようと、「タッピングネジ」を使用して、組み立てました。スムーズに動作できるか調整をしていたところ、良い場合と、うまく動作しない場合があり、その問題を探りました。

 この結果、わかったことがタッピングネジを留めるときに、真っすぐに止めることが難しく、わずかに斜めに入ってしまうことがあります。特にタッピングネジは、ネジ山を作りながら留めるため、わずかなズレが生じます。
 テオヤンセンロボットのように、遊びが少なく、精度が求められる場合にタッピングネジを使うことが難しいということです。
 右の図はネジ止めしたものを裏側から見たものです。ネジの先端が穴の中心からずれています。

ジョイントの改良

 タッピングネジではずれてしまいます。ナットで締めると、ズレは無くなるのですが、厚みが大きくなります。
 

 そこで、思いついたのが、タミヤのギアボックスを組み立てるときに、シャフトにスプリングピン(右図)を差し込むことを思い出しました。
 穴の大きさを調整すれば、ピンを穴に沿って真っすぐに差し込むことができるはずです。

 ただ、スプリングピンは小さく、ハンマーなどで打ち込むのが難しく、何かと考え、「治具」を作成しました。

 片側から「スプリングピン」がはまります。反対側は、素材が金属に比べてPLAのため軟らかいため、保護するために、M3ネジを入れてあります。
 これで、治具を持ってハンマーで打ち込むことができます。

完成例(テオヤンセン機構)

 スプリングピンを使って、製作したテオヤンセン機構です。
 足部分をボディに止めるときには、ネジを使っていますが、黒い軸を留めるときにはスプリングピンを使っています。


 スプリングピンを使用したメリットは、回転軸の精度が高まるのが一つですが、それ以外に、ネジの頭部分が無く、薄くできることです。



 現在、テオヤンセン機構ロボットのマシン部分が出来上がっています。

2026年3月7日土曜日

脳トレゲーム対応制御学習ボード5 シリアル通信

  プログラミングのデバッグ(プログラム修正)する方法です。一般的にマイコンでは内部で使っている変数の状態を表示する方法はありません。

 Arduinoでは「シリアルモニタ」というシリアル通信機能があります。この機能を使うと、内部の変数状態を表示させることができます。


シリアル通信で接続する(準備)

 UIAPduinoのUSB端子はプログラムを書き込む機能はありますが、シリアル通信する機能はありません。このため、何かの方法で接続する必要があります。

 UIAPduinoボードでは、図の左上の送信「TX(15)」、受信「RX(16)」の2本がシリアル通信の機能を持つ端子です。

 脳トレゲーム対応制御学習ボードでは、送信「TX」の端子を外部に接続できるようにしています。(片方向 マイコン→PCのみです)


 脳トレゲーム対応制御学習ボードから、シリアル通信端子を接続したのが右図です。図の下側のボードから、赤(TX)、青(GND)の2本が出ており、これがシリアル通信変換機能を持つ基板を経由してパソコンと接続されています。(TX→RXに接続する)


 パソコン(Windows)のデバイスマネージャを見ると、「USB SERIAL(COM9)」として接続されていることが確認できます。(COM番号は接続の仕方で異なります)

 AdruinoIDEの「ツール」-「ポート」の設定を行います。(この場合はCOM9に設定)

 これで通信できる環境が整いました。

シリアル通信で接続する(プログラミング)

 Arduinoでは「Serial」というクラスが定義され、ここを使うとシリアル通信できます。プログラムを示します。
 「void loop()」の前に、1行使う変数cntの宣言があります。プログラムは、変数cntを「Serial.printf」関数で表示します。その後、変数cntを1増やし、時間待ちをするプログラムです。
int cnt=0;
void loop() {
  Serial.printf("cnt: %4d\n", cnt);
  cnt=cnt+1;
  delay(500);
}
 書き込み、シリアルモニタを表示させます。(「ツール」ー「シリアルモニタ」と選択)

 実行した状態は、右図のように0.5秒ごとに数字がカウントアップされ、表示されていきます。

 内部の変数cntがパソコンでモニタリングできていることになります。

脳トレゲーム対応制御学習ボード4 ブザー制御

 ブザーで音を出力するときには、右図のようなPWM(Pulse Wide Modulation)というONとOFFを繰り返して出力することで音が鳴ります。

 繰り返す時間(ONとOFF1つ分の時間)を周期T[s]といいます。音の高さは周波数[Hz]で表され、周期と逆数の関係になります。

 音楽の「ドレミファソラシド」は右のような関係で周波数が決まっています。
 例えば「ド」を鳴らすには、261.63Hz、523.25Hz、1046.5Hzの周波数です。(1オクターブ上の周波数は2倍となります)

音を鳴らす関数 tone関数

 音を鳴らす関数として「tone」関数が用意されています。

  tone(  出力ポート  ,  周波数  ,  時間[ms]  );

 設定値として、音を出力するポート番号、周波数、音を鳴らす時間[ms]を指定します。

 スイッチSW1を押したときに、ド(523Hz)の音を1秒間鳴らす例を示します。

void loop() {
  if(digitalRead(SW1)==0){
    // ドの音を1秒(1000ms)鳴らす
    tone( BUZZER, 523, 1000);
    delay(1000);
  }
}

 tone関数は、命令処理後に、すぐ次の命令を実行します。このため、時間待ちdelayを入れます。

 上の鍵盤の図では小数点以下の数字がありますが、tone関数の周波数は整数です(小数があっても無視されます)。


演習

(1)上の例題に追加して、スイッチSW2を押したときに「レ」の音を鳴らすように変更する。

void loop() {
  if(digitalRead(SW1)==0){
    // ドの音を1秒(1000ms)鳴らす
    tone( BUZZER, 523, 1000);
    delay(1000);
  }
  if(       ){  // SW2を押したとき
    // レの音(587Hz)を1秒(1000ms)鳴らす

  }
}

(2)(1)にさらに追加して、SW1~SW6を使い、「ド」~「ラ」まで鳴らす電子オルガンを作成する。


(3)前回の投稿の「スイッチ制御」にtone関数を追加して、SW1を押したら「ド」を鳴らし数字「1」を表示するプログラムを作成する。

void loop() {
  if(digitalRead(SW1)==0){
    // ドの音を1秒(1000ms)鳴らす
    tone( BUZZER, 523, 1000);
    // 数字「1」を表示
    
    delay(1000);
  }
  if(       ){  // SW2を押したとき
    // レの音(587Hz)を1秒(1000ms)鳴らす

  }
}


(4)(3)に追加して、SW1~SW6まで対応させましょう。


脳トレゲーム対応制御学習ボード3 スイッチ制御

  プログラム例では、「loop」関数部のみを示します。「loop」関数部以外は変更しないでください。

(1)if文

 プログラムの制御を行うときに使う命令の一つが「if」文です。

 if文の基本は「if文のみ」と「if-else文」です。

 「if文」の「条件1」が成り立つときに「処理1」を行う命令。

 「if-else文」の「条件1」が成り立つときに「処理1」を行う、成り立たないときに「処理2」を行う命令。

があります。


(2)スイッチSW1を押したら数字「1」を表示する。離しているときは数字「0」を表示する。

 スイッチを離しているときは「1(HIGH)」の状態で、スイッチを押すと「0(LOW)」になる回路になっています。このためプログラムでは「digitalRead(SW1)」の値がゼロ(押した)の時に数字「1」を表示し、それ以外は数字「0」を表示します。
 if-else文を使っています。
void loop() {
  if(digitalRead(SW1)==0){
    // 数字「1」を表示
    digitalWrite(SEG_A, 0);
    digitalWrite(SEG_B, 1);
    digitalWrite(SEG_C, 1);
    digitalWrite(SEG_D, 0);
    digitalWrite(SEG_E, 0);
    digitalWrite(SEG_F, 0);
    digitalWrite(SEG_G, 0);
  }else{
    // 数字「0」を表示
    digitalWrite(SEG_A, 1);
    digitalWrite(SEG_B, 1);
    digitalWrite(SEG_C, 1);
    digitalWrite(SEG_D, 1);
    digitalWrite(SEG_E, 1);
    digitalWrite(SEG_F, 1);
    digitalWrite(SEG_G, 0);
  }
}

(3)スイッチSW1を押したら数字「1」を表示、スイッチSW2を押したら数字「2」を表示する。離しているときは数字「0」を表示する。

 条件が2つ以上あるときには、「if-else if-else」文を使います。
 「else if」のelseとifの間にはスペースが必要です。

void loop() {
  if(digitalRead(SW1)==0){
    // 数字「1」を表示
    digitalWrite(SEG_A, 0);
    digitalWrite(SEG_B, 1);
    digitalWrite(SEG_C, 1);
    digitalWrite(SEG_D, 0);
    digitalWrite(SEG_E, 0);
    digitalWrite(SEG_F, 0);
    digitalWrite(SEG_G, 0);
  }else if(digitalRead(SW2)==0){
    // 数字「2」を表示
    digitalWrite(SEG_A, 1);
    digitalWrite(SEG_B, 1);
    digitalWrite(SEG_C, 0);
    digitalWrite(SEG_D, 1);
    digitalWrite(SEG_E, 1);
    digitalWrite(SEG_F, 0);
    digitalWrite(SEG_G, 1);
  }else{
    // 数字「0」を表示
    digitalWrite(SEG_A, 1);
    digitalWrite(SEG_B, 1);
    digitalWrite(SEG_C, 1);
    digitalWrite(SEG_D, 1);
    digitalWrite(SEG_E, 1);
    digitalWrite(SEG_F, 1);
    digitalWrite(SEG_G, 0);
  }
}

(4)演習

a)スイッチSW1を押したら数字「1」を表示、スイッチSW2を押したら数字「2」を表示、スイッチSW3を押したら数字「3」を表示する。離しているときは数字「0」を表示する。


 hint.  「else if」を増やしていくと条件を増やすことができます。
  if(      ){
    // 数字「1」を表示

  }else if(     ){
    // 数字「2」を表示    

  }else if(     ){
    // 数字「3」を表示  

  }else{
    // 数字「0」を表示

  }

b)同じようにスイッチSW6まで増やしましょう。

2026年3月6日金曜日

脳トレゲーム対応制御学習ボード2 LED制御

 ここからのプログラム例では、「loop」関数部のみを示します。「loop」関数部以外は変更しないでください。

(1)7セグメントLEDの「A」を点滅(Blink)する

 LEDの点灯・消灯・点滅は基本となります。

void loop() {
  digitalWrite(SEG_A, 1); delay(300);
  digitalWrite(SEG_A, 0); delay(300);
}

 「SEG_A」は前回のプログラムで、ポート「7」に定義されています。

 このため、

  digitalWrite(SEG_A, 1);   // LED on

は、

  digitalWrite( 7 ,  1); 

という命令となります。SEG_AのLEDをオンにします。

(2)7セグメントLEDに「3」という数字を表示する

 数字を表示するには、1つだけのLEDでなく、同時にすべてのLEDを点灯・消灯を出力します。

 数字「3」では、SEG A・B・C・D・Gを点灯、他を消灯します。

void loop() {
  // 数字3を表示
  digitalWrite(SEG_A, 1);
  digitalWrite(SEG_B, 1);
  digitalWrite(SEG_C, 1);
  digitalWrite(SEG_D, 1);
  digitalWrite(SEG_E, 0);
  digitalWrite(SEG_F, 0);
  digitalWrite(SEG_G, 1);
}

(3)7セグメントLEDに「3」と「7」の数字を交互に表示する

 数字「3」を表示した後に、(1)で行ったように「delay」で時間待ちをします。その後、数字「7」を表示した後に時間待ちをします。

void loop() {
  // 数字3を表示
  digitalWrite(SEG_A, 1);
  digitalWrite(SEG_B, 1);
  digitalWrite(SEG_C, 1);
  digitalWrite(SEG_D, 1);
  digitalWrite(SEG_E, 0);
  digitalWrite(SEG_F, 0);
  digitalWrite(SEG_G, 1);
  //数字7の表示
  digitalWrite(SEG_A, 1);
  digitalWrite(SEG_B, 1);
  digitalWrite(SEG_C, 1);
  digitalWrite(SEG_D, 0);
  digitalWrite(SEG_E, 0);
  digitalWrite(SEG_F, 0);
  digitalWrite(SEG_G, 0);
  delay(300);
}

(4)演習

 ・数字「0」~「9」までの数字を順番に表示させる。

2026年3月5日木曜日

脳トレゲーム対応制御学習ボード1 setup関数部分

 マイコン制御を行う上で、把握しておかないといけないことは、「マイコンのどの端子に何が接続されているか」ということです。

 何を見るとわかるかというと、回路図です。右図が今回設計した「脳トレゲーム対応制御学習ボード」の回路図です。


 UIAPudinoボードの端子がどこにつながっているかを把握します。表にすると、右のようになります。

 例えば、7セグメントLEDの「A」端子は、ポート7に接続され、出力として使われることを意味します。

 

 この表を基にして、初期設定のプログラミング(setup部分)ができます。

// ポート定義
#define SEG_A 7
#define SEG_B 9
#define SEG_C 10
#define SEG_D 8
#define SEG_E 2
#define SEG_F 11
#define SEG_G 5
#define SW1 12
#define SW2 6
#define SW3 0
#define SW4 1
#define SW5 3
#define SW6 4
#define BUZZER 16
#define SERIAL_RX 16

void setup() {
    // シームレスモード設定
  if (FLASH->STATR & (1 << 14)) NVIC_SystemReset();
  SystemReset_StartMode(Start_Mode_BOOT);
  pinMode(PD4, OUTPUT);

  // PD1をGPIOとして利用する設定
  pinV32_DisconnectDebug(PD_1);  // Disable SWIO (the argument is not "PD1")

  Serial.begin(9600);
  pinMode(SERIAL_RX, OUTPUT);  // シリアルRXをGPIOで使用

  //ポート初期化
  pinMode(SEG_A, OUTPUT);
  pinMode(SEG_B, OUTPUT);
  pinMode(SEG_C, OUTPUT);
  pinMode(SEG_D, OUTPUT);
  pinMode(SEG_E, OUTPUT);
  pinMode(SEG_F, OUTPUT);
  pinMode(SEG_G, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(SW1, INPUT_PULLUP);
  pinMode(SW2, INPUT_PULLUP);
  pinMode(SW3, INPUT_PULLUP);
  pinMode(SW4, INPUT_PULLUP);
  pinMode(SW5, INPUT_PULLUP);
  pinMode(SW6, INPUT_PULLUP);
}

void loop() {

}

 あとは、「loop」関数部分に、プログラミングすると、学習が始まります。



CH32V003マイコン7 脳トレゲーム製作

 

発注した基板が来たので、製作に取り掛かりました。



半田面の製作

 半田面を半田付けします。注意が必要なのは、UIAPudinoマイコンです。ずれないようにクリップで止めてから、位置調整をします。
 その後、対角の2カ所から半田付けします。
 ずれが無ければ、残りを付けます。
 次に抵抗を付けます。回路では1kΩですが、無かったため、1.2kΩになっています。

 これで半田面の製作が終わりです。


部品面の製作
 次に部品面を半田付けします。
 高さの低い部品から、付けるのが基本です。
 付ける順番は次の通りです。
 ・スイッチ
 ・ブザー
 ・7セグメントLED
 ・ピンヘッダ2P

UIAPudinoボードの改造

 これで、ほぼ完成です。しかし、このままであるとUSB接続では動作しますが、電池では動作しません。これは、UIAPudinoボードの回路が5V(USBより給電)を基本としているためです。改造することで、3.3V(バッテリ)でも駆動できるようになります。
 回路図を見ると、ジャンパJP1が、+5V側につながっています。これを+3.3V側にします。
 この時に、+5V側のパターンをカットして、+3.3V側を半田でブリッジします。
 右図が改造した様子です。(赤丸部分)

 この他、バッテリを長持ちさせるために、不要なLED表示をさせないようにします。
 これもパターンカットで対応できます。まず、電源表示LEDが「CUT1」、USB書き込み時の表示が「CUT2」です。この2カ所はカットします。(緑丸部分)
 パターン「CUT3」でもLEDの表示を制限できるのですが、ここはプログラムで対応できるので、カットしてもしなくても構いません。

電池ボックスの取り付け

 改造後に電池ボックスを取り付けます。
これで脳トレゲーム対応学習ボードが完成します。
 注意)電池ボックスを付けるとUIAPudinoボードの改造ができなくなります。

脳トレゲームを書き込み実行

 脳トレゲームを書き込んで実行します。
 USB接続することなく、バッテリ駆動でゲームができています。












LEDマトリックス表示装置の設計・製作 9(画像表示)

  LEDマトリックスに画像を表示させるには、いろいろな画像形式を知る必要があります。現在、よく使われるJPG形式やPNG形式は圧縮処理されて保存されています。これに対して、BMP形式やTIFF形式は非圧縮形式で、画像データがそのまま保存されています。このため、ファイルは大きくな...