# おおたfab
## 3/1
バランスカーをより安定させる
35行~38行の
OFFSET
P
I
D
の値を変えてより安定させる
モータがばらつくので
数値は各自違う。
41~44行のスピード調整は
最終調整時
その前にPIDの値を調整
中心点に来た時
回転が緩くなれば制御がきいている
モータの取付が各自違う
ギヤの位置を比較のこと
大内さんのバランスカーが一番安定している。




EVOLTA 飯島さん
7 巻島さん
黒 前田
次回モータの取付位置(極性)を統一する。
ハンダ付けやり直し
## 2/9
PID制御とは
https://ja.wikipedia.org/wiki/PID%E5%88%B6%E5%BE%A1
ESP32に以下を焼く
BalanceCar_kit
https://drive.google.com/drive/folders/1tY5Htj5CRfg5joHDwQ3-sKbWJOc7JBWw?fbclid=IwAR0QYh1WPuO8H6lROJTsD6voFPg6xUvkdQQs3t4Q19EzMfqbZE2n0VdyWcA
説明書の読む
モータ極性を合わせる
269~272行 HIGH LOWの書き換え
LEDが付いたらキャリブレーションする
モータのバラつきを修正
float OFFSET = 89.0; 元89.3 // ボディの重心点、90より小さいほど前に進む
32行目近辺にPID制御のパラメタがあるので調整する。
最初はIの値とPの値は0にして、OFFSETとPでなるべく重心を合わせる。そのあとIとDを調整していく。
```
#else
float OFFSET = 90.5; //89.9; // 89.3; // ボディの重心点。90より小さい程前に進む。ここが水平点
float COEF_P = 25.0; //25.0; // 25.0; // 大まかに合わせるためのP制御。最終的に目標値には一致しない。その差をオフセットと呼ぶ。
float COEF_I = 1.5; //0.4; // 1.5; // オフセットをなるべく合わせるためのI制御。でもやはり片側によってしまう。
float COEF_D = 1.0; //0.1; // 3.5; // P制御の振れ幅を小さくするためのD制御を行う。
#endif
```
## 1/26
バランスーカ組立
新参加者 グーグルホーマーさん
佐藤さんが7組キットそろえてくれました。
部品集めるのに2カ月かかって大変でした。そうです。

1パタ-ンカット
説明書3ページ目
カット後テスターで抵抗値確認

2電池BOXのリード線を切って予備ハンダする。
予備ハンダ盛りすぎない。
ピンヘッダ割り方
ラジペンで両側を挟んで割る。

3 モータドライバにピン取り付ける。
長い方・短い方注意
4 ESP32用ピンコネクタ取り付ける。
> []
| Column 1 | Column 2 | Column 3 |
| -------- | -------- | -------- |
| Text | Text | Text |
---
5 モータ用ピンヘッダ取り付け
ブリッジ方向が違うので注意
## 11/23
バランスカー実験
MPU-6050 6DOF GY-521 MPU6050 3軸ジャイロスコープ + 加速度センサーモジュールArduino用の検証

ターミナルをハンダ付けする

ストレート端子台をつける

参考ページ
https://shizenkarasuzon.hatenablog.com/entry/2019/02/16/162647
ロボットカーからArduino UNOを外す。


MPU-6050 とUNO配線

Arduinoとの接続
| MPU-6050 | Arduino |
|:--------:|:-------:|
| VCC | 3V3 |
| GND | GND |
| SCL | A5 |
| SDA | A4 |
SCLとSDAのジャンパーは短い方がよい
参考ページのサンプルプログラムをUNOに書き込む。
ツールのシリアルモニターで動作確認をする。
※ ハンダのブリッジや配線の接続不良で動作しない事があるので注意
## サンプルプログラム
```
#include <Wire.h>
// MPU-6050のアドレス、レジスタ設定値
#define MPU6050_WHO_AM_I 0x75 // Read Only
#define MPU6050_PWR_MGMT_1 0x6B // Read and Write
#define MPU_ADDRESS 0x68
// デバイス初期化時に実行される
void setup() {
Wire.begin();
// PCとの通信を開始
Serial.begin(115200); //115200bps
// 初回の読み出し
Wire.beginTransmission(MPU_ADDRESS);
Wire.write(MPU6050_WHO_AM_I); //MPU6050_PWR_MGMT_1
Wire.write(0x00);
Wire.endTransmission();
// 動作モードの読み出し
Wire.beginTransmission(MPU_ADDRESS);
Wire.write(MPU6050_PWR_MGMT_1); //MPU6050_PWR_MGMT_1レジスタの設定
Wire.write(0x00);
Wire.endTransmission();
}
void loop() {
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(0x68, 14, true);
while (Wire.available() < 14);
int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, Temperature;
axRaw = Wire.read() << 8 | Wire.read();
ayRaw = Wire.read() << 8 | Wire.read();
azRaw = Wire.read() << 8 | Wire.read();
Temperature = Wire.read() << 8 | Wire.read();
gxRaw = Wire.read() << 8 | Wire.read();
gyRaw = Wire.read() << 8 | Wire.read();
gzRaw = Wire.read() << 8 | Wire.read();
// 加速度値を分解能で割って加速度(G)に変換する
float acc_x = axRaw / 16384.0; //FS_SEL_0 16,384 LSB / g
float acc_y = ayRaw / 16384.0;
float acc_z = azRaw / 16384.0;
// 角速度値を分解能で割って角速度(degrees per sec)に変換する
float gyro_x = gxRaw / 131.0;//FS_SEL_0 131 LSB / (°/s)
float gyro_y = gyRaw / 131.0;
float gyro_z = gzRaw / 131.0;
char str[300];
int acc_x_int = (int)(acc_x * 100);
int acc_y_int = (int)(acc_y * 100);
int acc_z_int = (int)(acc_z * 100);
int gyro_x_int = (int)(gyro_x);
int gyro_y_int = (int)(gyro_y);
int gyro_z_int = (int)(gyro_z);
sprintf(str, "acc_x, y, z: %5d / %5d / %5d - gyro_x, y, z: %5d / %5d / %5d \n", acc_x_int, acc_y_int, acc_z_int, gyro_x_int, gyro_y_int, gyro_z_int);
Serial.print(str);
}
```
ブレッドボードでは接続不良を起こしやすいので
実際に使うときは、同一基盤に乗せるか配線の工夫が必要
PID制御とは?
次回ノートPC ブレッドボード UNO MPU=6050必要
OSOYOOバランスカー
http://osoyoo.com/2018/07/18/osoyoo-balancing-car/
## 10/14
lesson-4ロボットカーをBluetoothで制御
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-wifi-control/
チャンネル数に制限があるので、同時にできない。
チュートリアルどうりにやって動く。
トラッキングはスピードが速く上手くいかない。
左右に動かない。
void do_Drive_Tick()
{
if(Drive_Status == MANUAL_DRIVE)
{
switch (Drive_Num)
{
case GO_ADVANCE:
set_motorspeed(255,255);
go_ahead(15);
JogFlag = true;
JogTimeCnt = 3;
JogTime=millis();
break;
case GO_LEFT:
set_motorspeed(100,100);
turn_left(2);
JogFlag = true;
JogTimeCnt = 1;
JogTime=millis();
break;
case GO_RIGHT:
set_motorspeed(100,100);
turn_right(2);
JogFlag = true;
JogTimeCnt = 1;
JogTime=millis();
break;
のmotorspeedが遅すぎ(100では動かない)
上げれば動く
9/28
ライントラッキングの続き
lesson-3
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-tracking/
最初 キット調整
1黒ビニールテープ 大丈夫
コピー黒には反応する。
2 持ち運びでセンサが曲がって反応が悪くなる。
3 反応を調整すると曲がりがよくなる。
4 センサのボリューム調整完了⇒正常動作
5 配線間違いが多い。
6 モータが早すぎて鋭角に曲がれない。
7 モータスピードは150 170 より下げたほうがよさげ⇒サンプルプログラムでは早すぎる。
マニュアルを読んでプログラムをいじってみる。
バッテリーは4本か5本 5本の方がよい
次回はlesson4 ブルートゥースの試験
モータがギヤでスピード調整ができる方が望ましい。
センサ配線状態



ライントラッキング動画
https://www.facebook.com/profile.php?id=100005156706745
9/15
日本語チュートリアル
http://osoyoo.com/ja/2017/10/18/osoyoo-2wd-robot-car-starter-kit-tutorial-introduction/
ライントラッキング走行のテスト
1 コントラストは大きくないとセンサーが反応しない。
2 ボリュームでセンサの感度調節するがレンジが狭い。
3 布テープではセンサが反応しなかった⇒反射があるから?
マジックでぬったラインには反応した。
4 スピードが速いので速度を150→2桁 170→2桁にしたところ動かない
トルク不足か?
5 メーカ指定のバッテリーより単三乾電池4本直列の方が入手が楽
6 マニュアルでは、センサの配線が分かりにくい。
7 距離は関係ないようだ
9/7 スマートカー各々組立
3780円のkitにはバッテリーがついていない。
各自購入のこと
単三4本直列で可
但し将来ラズパイを使用するときは交換する可能性あり
⇒ラズパイ3A必要 単三では電流不足
lesson-1.zip
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-installation/?fbclid=IwAR1GJi7zdbnrMi1SxN09nZ80gmqHDfpAytG1IYZN3LERRnF-Olu_l8n_mgM
lesson-2.zip
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-infrared-remote/
IRコントローラで動かす
受光する範囲が狭く馴れないと反応しない。
センサ位置を工夫する必要あり
センサ交換も考える。
反応が悪いのはarduinoの性能?
Raspberry Piなら大丈夫か?
##OSOYOO 2WDロボットカー組み立て
巻島さんのURLを見る
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-installation/?fbclid=IwAR1GJi7zdbnrMi1SxN09nZ80gmqHDfpAytG1IYZN3LERRnF-Olu_l8n_mgM
部品確認せず始めてしまった。
IRつけてサンプルプログラムを走らす。
https://www.arduino.cc/en/Main/Software?setlang=jaからArduino IDEをダウンロード
IRのサンプルを動かしました
http://osoyoo.com/ja/2017/09/21/2wd-robot-car-infrared-remote/
問題
バッテリーが特殊
前輪がコントロールができないので方向が思った方に行かない。
次回以降はこのキットが良さそう
https://www.amazon.co.jp/SODIAL-227357-%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%83%AD%E3%83%9C%E3%83%83%E3%83%88%E3%82%AB%E3%83%BC%E3%82%AD%E3%83%83%E3%83%88-R3%E3%80%81%E8%B6%85%E9%9F%B3%E6%B3%A2%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%80%81%E3%83%96%E3%83%AB%E3%83%BC%E3%83%88%E3%82%A5%E3%83%BC%E3%82%B9%EF%BC%9F%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%81%8C%E5%90%AB%E3%82%80-%E3%83%81%E3%83%A5%E3%83%BC%E3%83%88%E3%83%AA%E3%82%A2%E3%83%AB%E4%BB%98%E3%81%8D%E3%81%AEArduino%E7%94%A8/dp/B07R96GB1J/ref=sr_1_46?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%B9%E3%83%9E%E3%83%BC%E3%83%88%E3%82%AB%E3%83%BC&qid=1566018445&s=gateway&sr=8-46
[toc]
## おおたfab_コインbox
## samplecode_フォトリフレクターのみ
int analogPin = 25 ;
int val = 0;
void setup() {
Serial.begin(9600);
}
void loop(){
val = analogRead(analogPin);
Serial.println(val);
delay(50);
}
# US-015とPIR


[参考ページ]
## US-015
http://310web.ddo.jp/led_kairo/pic_kairo/e_50_US-015/index.html
## PIR
http://www.microbot-ed.com/j_motion_sensor.html
[ライブラリ]
ESP8266 and ESP32 Oled Driver for SSD1306 display
## sample code
```
#include <Wire.h>
#include "SSD1306Wire.h"
/// timerとそれで使うセマフォの宣言
hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
uint32_t TimerEcho1, TimerEcho2;
SSD1306Wire display(0x3c, 4, 5);
int pir = 35;
int led = 13;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 超音波センサーのエコー割り込み
void IRAM_ATTR OnEcho()
{
detachInterrupt(0);
TimerEcho1 = timerRead( timer ); // 古いデータを取ってくるようなので1個は読み捨てる
TimerEcho2 = timerRead( timer );
Serial.println("E!");
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
digitalWrite(12, LOW); // US-015 Tirg PinLow
pinMode(12, OUTPUT);
pinMode(pir, INPUT);
pinMode(led, OUTPUT);
Serial.begin(115200);
////////////////////// timer関連設定
// timer満了待ち合わせセマフォ作成
timerSemaphore = xSemaphoreCreateBinary();
timer = timerBegin(0, 80, true); // 1μS毎にカウントアップ
timerWrite(timer, 300000); // 300mS 34m x 3 ≒ 100m
///////////////////////// SSD1306関連
display.init();
display.flipScreenVertically();
delay(100); //
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 超音波計測部
void Measurement() {
digitalWrite(12, HIGH); // 超音波測距開始
delayMicroseconds(200);
// port0 LOWエッジで割り込み 超音波のecho入力を割り込みで受ける
attachInterrupt(2, OnEcho, FALLING );
TimerEcho1 = TimerEcho2 = 0; // 距離情報をクリアしておく
// タイムアウト監視用のタイマ開始 300mSでsetupで設定
timerWrite(timer, 0);
digitalWrite(12, LOW); //
timerStart(timer); // 距離計測用タイマスタート
delay(150); // 割り込みがない時のタイムアウト 150mS≒50M 待ち
timerStop(timer);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void drawDist() {
display.clear();
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.setFont(ArialMT_Plain_16);
uint16_t Dist = ((TimerEcho2 - 450) * 10 / 588); // 1cmあたり58.8μS -450は調整値
String Echo = String(Dist) + "cm";
display.drawString(0, 0, Echo);
display.setColor(WHITE);
display.fillRect(0, 32, Dist, 8);
if(digitalRead(pir)) {
Serial.println("on");
display.drawString(0, 48, "PIR : Found!");
} else {
Serial.println("off");
display.drawString(0, 48, "PIR : ------");
}
display.display();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
Measurement(); // 距離計測
drawDist(); // OLED表示を行う
delay(100); // 100mS周期で計測
}
```
# ステッピングモータ
2019/5/18
[ステッピングモータ](http://akizukidenshi.com/catalog/g/gP-13256/)
[制御参考ページ1](https://stupiddog.jp/note/archives/1235)
## sample1
```
/*
BYJ48 簡単なテストプログラム
*/
#define PIN1 12 //28BYJ48のIN1につないだArduinoのピン番号を定義する
#define PIN2 14 //28BYJ48のIN2につないだArduinoのピン番号を定義する
#define PIN3 0 //28BYJ48のIN3につないだArduinoのピン番号を定義する
#define PIN4 2 //28BYJ48のIN4につないだArduinoのピン番号を定義する
/*setupは起動後ときに最小に呼び出される関数で、ここでさまざまな初期化を処理を行う*/
void setup()
{
//シリアル通信の初期化しシリアルモニタへ文字列を出力できるようにする 9600はボーレート(通信速度)
Serial.begin(9600);
Serial.println("プログラムが開始しました\n");
//各ピンを出力モードにする
pinMode(PIN1, OUTPUT); //PIN1を出力モードにする
pinMode(PIN2, OUTPUT); //PIN2を出力モードにする
pinMode(PIN3, OUTPUT); //PIN3を出力モードにする
pinMode(PIN4, OUTPUT); //PIN4を出力モードにする
}
/*setupの後、終了するまで繰り返し呼び出される関数*/
void loop()
{
int sleep_time = 10;
int sleep_time2= 5;//角ステップでのスリープ時間 5[ms]
//PIN1と2をHigh, PIN2と3をLowにしてステッピングモーターを1ステップ進める
digitalWrite(PIN1, 1);
digitalWrite(PIN2, 1);
digitalWrite(PIN3, 0);
digitalWrite(PIN4, 0);
delay(sleep_time ); //スリープ
//PIN2と3をHigh, PIN4と1をLowにしてステッピングモーターを1ステップ進める
digitalWrite(PIN1, 0);
digitalWrite(PIN2, 1);
digitalWrite(PIN3, 1);
digitalWrite(PIN4, 0);
delay(sleep_time2 ); //スリープ
//PIN3と4をHigh, PIN1と2をLowにしてステッピングモーターを1ステップ進める
digitalWrite(PIN1, 0);
digitalWrite(PIN2, 0);
digitalWrite(PIN3, 1);
digitalWrite(PIN4, 1);
delay(sleep_time );
//PIN4と1をHigh, PIN2と3をLowにしてステッピングモーターを1ステップ進める
digitalWrite(PIN1, 1);
digitalWrite(PIN2, 0);
digitalWrite(PIN3, 0);
digitalWrite(PIN4, 1);
delay(sleep_time2 );
}
```
## sample2
```
/*
BYJ48 簡単なテストプログラム
*/
#define PIN1 12 //28BYJ48のIN1につないだArduinoのピン番号を定義する
#define PIN2 14 //28BYJ48のIN2につないだArduinoのピン番号を定義する
#define PIN3 0 //28BYJ48のIN3につないだArduinoのピン番号を定義する
#define PIN4 2 //28BYJ48のIN4につないだArduinoのピン番号を定義する
/*setupは起動後ときに最小に呼び出される関数で、ここでさまざまな初期化を処理を行う*/
void setup()
{
//シリアル通信の初期化しシリアルモニタへ文字列を出力できるようにする 9600はボーレート(通信速度)
Serial.begin(9600);
Serial.println("プログラムが開始しました\n");
//各ピンを出力モードにする
pinMode(PIN1, OUTPUT); //PIN1を出力モードにする
pinMode(PIN2, OUTPUT); //PIN2を出力モードにする
pinMode(PIN3, OUTPUT); //PIN3を出力モードにする
pinMode(PIN4, OUTPUT); //PIN4を出力モードにする
}
/*setupの後、終了するまで繰り返し呼び出される関数*/
void loop()
{
int sleep_time = 5; //角ステップでのスリープ時間 5[ms]
int steps = 100;
Stepup(sleep_time,steps,0);
delay(2000);
steps = 100;
Stepup(sleep_time,steps,1);
}
void Stepup(int sleep_time,int steps,int dir){
int Steps[4][4] = {
{ 1, 1, 0, 0 },
{ 0, 1, 1, 0 },
{ 0, 0, 1, 1 },
{ 1, 0, 0, 1 }
};
int i = 0;
int cnt = 0;
if(dir == 0){
while(cnt <= steps){
digitalWrite(PIN1, Steps[i][0]);
digitalWrite(PIN2, Steps[i][1]);
digitalWrite(PIN3, Steps[i][2]);
digitalWrite(PIN4, Steps[i][3]);
delay(sleep_time ); //スリープ
i++;
cnt++;
if(i == 4){
i = 0;
}
}
}else{
i = 3;
while(cnt <= steps){
digitalWrite(PIN1, Steps[i][0]);
digitalWrite(PIN2, Steps[i][1]);
digitalWrite(PIN3, Steps[i][2]);
digitalWrite(PIN4, Steps[i][3]);
delay(sleep_time ); //スリープ
i--;
cnt++;
if(i < 0){
i = 3;
}
}
}
}
```
# SSD1306
2019 4/7 SUN ロボット勉強会2回目
参考ページ
https://wak-tech.com/archives/825
I2Cについて
https://www.mgo-tec.com/blog-entry-32.html
https://monolizm.com/sab/pdf/第16回_プレゼン資料(IC2通信編).pdf
SSD1306
http://akizukidenshi.com/catalog/g/gP-12031/
arduino(プログラムリファレンス)
http://www.musashinodenpa.com/arduino/ref/
他の表示方法
https://qiita.com/jakalada/items/793a6cf5ff2796db4e86
線などの描画
https://qiita.com/jakalada/items/8f83d07291d984a31633
## sample
### 1.数字のカウントアップ
`Adafruit_SSD1306`と`Adafruit-GFX-Library`のライブラリのインストールが必要.詳しくは[こちら](https://qiita.com/jakalada/items/8f83d07291d984a31633)
```
#include <Wire.h>
#include "SSD1306.h"//ディスプレイ用ライブラリを読み込み
int T = 0;
int Tstring = 0;
SSD1306 display(0x3c, 21, 22); //SSD1306インスタンスの作成(I2Cアドレス,SDA,SCL)
void setup() {
display.init(); //ディスプレイを初期化
display.setFont(ArialMT_Plain_16); //フォントを設定
//display.drawString(20, 24, "Hello World"); //(0,0)の位置にHello Worldを表示
//display.display(); //指定された情報を描画
}
void loop() {
display.init();
String Tstring = String(T);
display.drawString( 10, 24, Tstring); //(0,0)の位置にHello Worldを表示
display.display(); //指定された情報を描画
delay(1000);
T = T + 1;
//if(T = 128){
// T = 0;
//}
}
```
### 2.画面をドットで埋め尽くしていく
```
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define NUMFLAKES 10 // Number of snowflakes in the animation example
#define LOGO_HEIGHT 16
#define LOGO_WIDTH 16
int X = 0; int Y =0;
void setup() {
Serial.begin(9600);
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
}
void loop() {
if(X==0 && Y ==0){
display.drawPixel(0,0, WHITE);
}
if(X<=128){
X = X + 5;
}
if(X>128){
Y = Y + 5;
X = 0;
}
if( Y >= 64){
X = 0;
Y = 0;
display.clearDisplay();
}
display.drawPixel(X,Y, WHITE);
display.display();
delay(1);
// if(X==128 && Y ==64){
// display.clearDisplay();
// X = Y = 0;
// }
}
```
# ESP32
- Adruino IDEのファイル→環境設定→設定タブ。追加のボードマネージャーのURLに以下を入れる。
https://dl.espressif.com/dl/package_esp32_index.json
- ツール→ボード→ボードマネージャーを選択。ESP32と検索窓に入力すればESP32のボードが表示されるのでインストールする。
- ボード:`ESP32 Dev Module` に設定できればOK。
- windows driverをインストールする。
https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers
- スケッチ例 `blink`を使用
## sample
### Lちか
```
int LED_pin = 4;
void setup() {
pinMode(LED_pin, OUTPUT);
}
void loop() {
digitalWrite(LED_pin, HIGH);
delay(1000);
digitalWrite(LED_pin, LOW);
delay(1000);
}
```
[mac用ESP32のUSBドライバ](https://jp.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers#mac)
[ESP32 and Max7219 8×8 LED matrix example](
http://www.esp32learning.com/code/esp32-and-max7219-8x8-led-matrix-example.php)