Blog

MacBook Pro Monterey,使用 Arduino IDE 燒錄 ESP8266 會出現燒錄錯誤 “pyserial or esptool directories not found next to this upload.py tool.”

資料來源:https://www.tweaking4all.com/forum/arduino/macos-aruino-ide-how-to-fix-pyserial-or-esptool-directories-not-found-next-to-this-upload-py-tool-error-esp8266/

錯誤訊息如下:

pyserial or esptool directories not found next to this upload.py tool.
An error occurred while uploading the sketch

macOS版本:Monterey 12.3.1

ESP8266 Core version:2.6.3

aArduino IDE version:1.8.19

解決方法:

  1. 打開這個檔案
    file~/Library/Arduino15/packages/esp8266/hardware/esp8266/2.6.3/tools/pyserial/serial/tools/list_ports_osx.py
  2. 註釋掉這兩行
iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')    
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

加入這兩行:

iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

修改完成後,程式碼應該像下面這樣子才對:

from serial.tools import list_ports_common

#iokit = ctypes.cdll.LoadLibrary(ctypes.util.find_library('IOKit'))
#cf = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation'))
iokit = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/IOKit.framework/IOKit')
cf = ctypes.cdll.LoadLibrary('/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation')

kIOMasterPortDefault = ctypes.c_void_p.in_dll(iokit, "kIOMasterPortDefault")
kCFAllocatorDefault = ctypes.c_void_p.in_dll(cf, "kCFAllocatorDefault")
這樣就可以正常燒錄了!
Done!

Apple 的 iCloud 實在太棒了!

原先想說會搬移舊資料會很傷腦筋,結果一點都不費力,只要登入iClloud就可以了,完全都不需要額外做什麼。

就是要花時間而已!

Macbook Pro星期六晚上帶回家,到今天晚上,過了2天,我的新Macbook Pro經由iColud就已經同步完成了。

但是,不是所有資料都下載到新Macbook Pro,只是有用到的會自動下載下來,其他就等你什麼時候會用到,需要用到時,再下載下來就可以了,不用擔心空間不夠用。

整理舊資料,只要刪除,就會同步刪除iCloud的檔案。

但是,如果要保存資料,要另外儲存在其他外接硬碟或隨身碟,再刪除喔!

真的太好用了!

有使用Apple的產品建議一定要購買iCloud,真的超級方便。


tags: Macbook pro 2021 macOS 12.3.1 Monterey

2021 Macbook Pro 14吋 安裝 Arduino IDE 1.18.9 在 ESP32 發生 「exec: “python" : executable file not found in $PATH」錯誤

資料來源:
1. https://forum.arduino.cc/t/esp32-problem-with-compilation-on-macos-12-3-monterey/969771
2. https://forum.arduino.cc/t/mac-os-update-killed-esp32-sketch/969580/8

作者:順哥
email:palmbear@gmail.com

Table of Contents

[TOC]

前言

最近新購買2021 Macbook Pro 14吋 使用 Arduino IDE 1.18.9 在ESP32開發板上傳程式碼時,發生 「exec: “python": executable file not found in $PATH’」錯誤。上網查了發現解決方法,留下紀錄,以免後續再碰到時,不知如何解決。

問題

ESP32: problem with compilation on MacOS 12.3 Monterey

問題頁面

網頁畫面:

解決方法
網頁畫面:


我的解決方法

我按照網頁上的解決方法,更改
/Users/palmbearhung/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/platform.txt 文件內容:

# From
tools.gen_esp32part.cmd=python "{runtime.platform.path}/tools/gen_esp32part.py"

# To
tools.gen_esp32part.cmd=/usr/local/bin/python "{runtime.platform.path}/tools/gen_esp32part.py"

但是還時不能上傳!!!

Arduino IDE跟我說「no such file or directory」

將 python 更改為 python3 也不行!!!

這倒底是怎麼一回事呢?

後來把整個文章看完,才知道也有人跟我一樣。

但是有解決方法,就是:

找出 python3放在電腦的哪個位置?

使用 which python3 指令,找出 python3 的所在位置。

原來我的 python3 位置跟他們的不一樣!

更改完成後,儲存檔案。

再次上傳檔案,成功!!!


tags: Arduino ESP32 Macbook pro 2021 macOS 12.3.1 Monterey

在Arduino 使用ESP32與網路同步時間,獲取日期及時間

作者:順哥
email:palmbear@gmail.com

資料來源:
https://randomnerdtutorials.com/esp32-date-time-ntp-client-server-arduino/

Table of Contents

[TOC]

前言

如何使用 ESP32 和 Arduino IDE 從 NTP Server 同步日期和時間?

獲取日期和時間在Aiot應用中很有用。要從 NTP Server獲取時間,ESP32需要連接 Internet,而且不需要額外的硬體(如 RTC 時鐘)。


NTP(Network Time Protocol, 網路時間協議)

NTP想要將所有參與電腦的協調世界時(UTC)時間同步到ms的誤差內。NTP通常可以在internet保持幾十毫秒的誤差,並且在理想的區域網路環境中可以實現超過1毫秒的精度。

MCU與NTP Server同步示意圖:
資料來源:randomnerdtutorials.com


硬體

  1. AI Thinker ESP32-S(NODMCU-32 V1.2)
  2. ESP32擴展板
  3. USB充電傳輸線

軟體

  1. Arduino IDE 2.0.0 RC5 for MacOS:
  2. 需要的Library:

<WiFi.h>
<time.h>


程式碼

  1. 使用 ESP32 加上 ESP32擴展板,程式碼如下:
/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-date-time-ntp-client-server-arduino/

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <WiFi.h>
#include <time.h>

const char* ssid     = "Your wifi ssid";
const char* password = "your password";

const char* ntpServer = "time.google.com";
const long  gmtOffset_sec = 28800; //台灣時區+8hr,28800=8*60*60
const int   daylightOffset_sec = 0;  //台灣無日光節約時間

void setup(){
  Serial.begin(115200);

  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected.");

  // Init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
}

void loop(){
  delay(5000);
  printLocalTime();
}

void printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %Y %m %d %H:%M:%S"); //%A-Sunday,%Y-2022,%m-3,%d-27,%H:%M:%S-21:10:02
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S"); //%A-Sunday,%B-March,%d-27,%Y-2022,%H:%M:%S-21:10:02
  Serial.print("Day of week: "); //顯示英文 星期
  Serial.println(&timeinfo, "%A"); //Day of week: Sunday
  Serial.print("Month: "); //顯示英文 月份
  Serial.println(&timeinfo, "%B"); //Month: March
  Serial.print("Day of Month: "); //顯示英文 日
  Serial.println(&timeinfo, "%d"); //Day of Month: 27
  Serial.print("Year: "); //顯示英文 西元年
  Serial.println(&timeinfo, "%Y"); //Year: 2022
  Serial.print("Hour: "); //顯示英文 時 24小時制
  Serial.println(&timeinfo, "%H"); //Hour: 21
  Serial.print("Hour (12 hour format): "); //顯示英文 時 12小時制
  Serial.println(&timeinfo, "%I"); //Hour (12 hour format): 9
  Serial.print("Minute: "); //顯示英文 分
  Serial.println(&timeinfo, "%M"); //Minute: 01
  Serial.print("Second: "); //顯示英文 秒
  Serial.println(&timeinfo, "%S"); //Second: 24

  Serial.println("Time variables"); //時間變數Time variables
  char timeHour[3]; //宣告時間小時變數:timeHour
  strftime(timeHour,3, "%H", &timeinfo);
  Serial.println(timeHour); //顯示時數:22
  char timeWeekDay[10]; //宣告時間星期變數:timeWeekDay
  strftime(timeWeekDay,10, "%A", &timeinfo);
  Serial.println(timeWeekDay); //顯示星期:Sunday
  Serial.println("*****************************************************");

}

tags: NTP Arduino ESP32 ESP8266 Wio terminal

Arduino IDE 2.0 RC3 安裝紀實


title: ‘Arduino IDE 2.0 RC3 安裝紀實’

作者:順哥
email:palmbear@gmail.com

前言

Arduino IDE 已經發展很久了,但是編譯的速度一直很慢,因應這個問題以及 Tiny ML 的應用,終於開發出新版本,目前還在 RC3版本,提供大家試用,這邊可以下載嘗鮮Arduino IDE 2.0 RC3

下載網頁畫面:


安裝

可以按照自己的系統下載對應的檔案來安裝,我下載 Windows 版本來安裝。

下載後執行檔案就會看到:

安裝畫面-1:

安裝畫面-2:

依照指示完成安裝即可,Arduino IDE 2.0 RC3 安裝完成後,開啟它。


環境設定

  1. 第一次開啟Arduino IDE 2.0 RC3會出現這個新畫面,原先是淺色系,我把它改成暗色系:
  2. 新的使用者介面長這樣,工具列的左側最靠中間有一個 搜尋及選擇開發板 的小視窗,而左側的5個圖示分別是:
    (1)Sketchbook 草稿碼資料夾
    (2)Boards Manager 開發版管理員
    (3)Library Manager 函式庫管理員
    (4)Dubug 偵錯
    (5)Search 搜尋
  3. 點選 File > Preferences :
  4. 接下來就會看到Preferences的相關設定,把常用的都打勾,並點選右下角的符號以增加其他開發板如下圖:
  5. 點選右下角符號後,請copy下面網址貼在框框內,一個網址一行,以增加ESP8266、ESP32 以及 Wio terminal這三塊開發板:
    http://arduino.esp8266.com/stable/package_esp8266com_index.json
    https://dl.espressif.com/dl/package_esp32_index.json
    https://files.seeedstudio.com/arduino/package_seeeduino_boards_index.json
  6. 接下來點選左邊上面算下來第2個圖示-Boards Manager,並搜尋 ESP8266 ,安裝2.6.3版比較沒有問題。如下圖:
  7. 隨後搜尋 ESP32 ,安裝1.0.4版比較沒有問題。如下圖:
  8. 最後搜尋 Seeed wio terminal ,安裝1.8.2版
  9. 關閉 Arduino IDE 2.0 RC3 ,重新開啟,這樣就完成環境設定了。

測試

  1. 使用 ESP32 加上 ESP32 擴展版 來寫一個閃爍內建 LED 的程式來測試一下,程式碼如下:
//閃爍內建LED
void setup() {
  pinMode(2, OUTPUT);  //宣告pin2(內建LED)作為輸出用途
}
void loop() {
  digitalWrite(2, HIGH);  //宣告pin2(內建LED)輸出高電位(3.3V)
  delay(1000);            //延遲1秒
  digitalWrite(2, LOW);   //宣告pin2(內建LED)輸出低電位(0V)
  delay(1000);            //延遲1秒
}
  1. Arduino 2.0 在編輯時,再輸入程式碼時會出現輸入指令格式提示,這應該是Arduino 2.0 除了速度變快之外,最大的改變了!
  2. 程式碼編輯完成,並上傳到ESP32上的完成畫面:
  3. ESP32 + 擴展板相片
  4. ESP32閃爍LED影片

待續!!!

tags: Arduino ESP32 ESP8266 Wio terminal

OAK-D-Lite 開箱文

作者:順哥
email:palmbear@gmail.com

Table of Contents

[TOC]

緣起

不小心在 kickstarter網站 OpenCV AI Kit – Lite專案 看到 OpenCV AI Kit – Lite 這個可愛的東西,可以做很多AI的影像專案,經不起誘惑,就敗了一個,搶到早鳥優惠一個79美金。

到了要交貨時刻,因為使用禮物卡結帳,而且可以購買配件,測試了一下,發現可以增加數量,於是邀請台灣人工智慧學校經理人班眾學長們是否對這個OpenCV AI Kit – Lite 有興趣?一起購買,分攤運費。

2022/01/06 下訂單,因春節假期將至,原先預計到貨時間應該會在過年後,沒想到2022/01/17就寄到了,速度蠻快的,可能是沒有被海關抽到吧!。

現在 OpenCV AI Kit – Lit 已經更名為 OAK-D-Lite 了。

目前的購買網頁:
https://shop.luxonis.com/collections/

外觀

  1. 我們的戰利品
    我們的戰利品
  2. 盒子正面link text
  3. 盒子側面link text
  4. 將盒子上的雷射貼紙撕開,盒子打開後就看到 OAK-D-Lite 了。link text
  5. 拉近link text
  6. OAK-D-Lite 本體link text
  7. OAK-D-Lite 本體背後,有2個腳架固定孔,左右各1。link text
  8. OAK-D-Lite 本體底部有1個腳架固定孔及 USB-C 的插孔link text
  9. OAK-D-Lite 本體正面-1link text
  10. OAK-D-Lite 本體正面-2link text
  11. 撕開膠布,OAK-D-Lite 本體正面有殘膠痕跡,用酒精擦乾淨即可。link text
  12. 盒子背後,掃描QR-Code 就可以進入網站,說明如何設置 OAK-D-Lite。

主要特點

  • Neural Inference (object detection, image classification, semantic segmentation, pose estimation)
  • Object tracking
  • 3D Object Tracking (up to 20 objects with unique ID)
  • 3D Object Localization
  • H.264 & H.265 Encoding (HEVC, 1080P, and 4K Video) – A Pi Zero can record 4K/30 FPS video with this
  • Motion Estimation (allows real-time background subtraction)
  • Feature Tracking (optical, and visual inertial navigation)
  • Corner Detection
  • Stereo Depth (including median filtering, extended disparity and subpixel possible for wider dynamic range)
  • Warp/Dewarp – support for additional lenses for fish-eye applications
  • JPEG Encoding
  • MJPEG Encoding for easy web streaming
  • Compatible with most of OAK-D features
  • Enclosure compatible with standard tripod mount (1/4”-20)
  • Support for on-board stereo and RGB camera modules
  • USB 3.1 Gen1 Type-C

OAK-D-Lite 硬體規格

OAK-D-Lite 是他們產品裡面屬於 USB line,他們的產品統稱為 DepthAI device,DepthAI device 產品比較圖如下:
資料來源:https://docs.luxonis.com/projects/hardware/en/latest/
link text

OAK-D-Lite 硬體規格如下:

  1. 4K Camera – 4208×3120 – RGB Auto-Focus:
  • Aspect Ratio: 1.348:1
  • Focus Range: 8cm – Infinity
  • Lens Size: 1/3.1 inch
  • Effective Focal Length: 3.37mm
  • Diagonal Field of View: 81.3 degrees
  • F-Number: 2.2 +-5%
  • Distortion: < 1%
  • Image Sensor: Sony IMX214
  1. Stereo Pair – 300,000 depth points up to 10 meters:
  • Aspect Ratio: 1.333:1
  • Focus Range: 6.5cm – Infinity
  • Lens Size: 1/7.5 inch
  • Effective Focal Length: 1.3mm
  • Diagonal Field of View: 85.6 degrees
  • HFOV: 72.9 degrees
  • VFOV: 57.7 degrees
  • F-Number: 2.2
  • Distortion: < 1.5%
  • Image Sensor: OmniVision OV7251
  1. Vision Processor – 20 Computer Vision Processors:
  • 16 “Mini-GPU” Vector Processors
  • 2 Dedicated AI Processors
  • 1 Dedicated 200FPS Disparity Depth Processor
  • 4 Trillion Operations Per Second

Fixed-focus vs Auto-focus

  1. Fixed-focus:
  • Pros:
    較適合振動的狀況使用。如果相機受到劇烈振動,鏡頭不會振動,這會導致圖像模糊(無人機、機器人、機器上等)
  • Cons:
    更適合 RGB 深度對齊(因為鏡頭不會移動)
  1. Auto-focus:
  • Pros:
    可以動態對焦物體,主要適用 30cm 以內的物體。
  • Cons:
    在振動的中況下,無法正常使用(例如無人機、沒有懸架的自行車等)

使用 DepthAI 的第一步

掃描盒子背後的 QR-Code 就可以進入網站,會看到下面這個畫面:link text

點選 New to DepthAI? Start here進入TUTORIALS 的 First steps with DepthAI 的畫面:link text

如果你是使用 Windows 系統,看這頁就可以了。

如果你使用其他系統,請到這裡來……
link text

其他資料

DepthAI’s documentation:
https://docs.luxonis.com/en/latest/

DepthAI SDK documentation:
https://docs.luxonis.com/projects/sdk/en/latest/

DepthAI API Documentation:
https://docs.luxonis.com/projects/api/en/latest/

DepthAI Hardware Documentation:
https://docs.luxonis.com/projects/hardware/en/latest/

待續!!!

tags: DepthAI OAK-D-Lite

ESP32輔助板背面I2C使用方法

資料來源:

1.https://youyouyou.pixnet.net/blog/post/121069748-esp32-x-nbiot-%e8%bc%94%e5%8a%a9%e7%89%88-%e8%83%8c%e9%9d%a2i2c-lcd?pixfrom=related
2.IoT物聯網應用:使用 ESP32 開發版與 Arduino C 程式語言,尤濬哲老師著

本文實作尤老師製作的「ESP32輔助板」背面 I2C 使用方法,背面的I2C為附加的PCF85741 I2C晶片,因此使用的腳位是 26 ,27 而非 21 , 22。

要使用ESP32輔助板背面的 I2C 介面,必須將 SDA 設為 GPIO 26,SCL 設為 GPIO 27。每個 I2C 裝置都會有一個位址,宣告錯誤的位址是不會有任何反應的,所以必須先做一次 I2C 掃描,取得正確位置。

我們可以使用下面程式碼掃描 I2C 的位址:

#include <Wire.h>

void setup()
{
  Serial.begin (115200);  
  Wire.begin (26, 27);   // sda=GPIO_26, scl=GPIO_27
}

void Scanner ()
{
  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;

  Wire.begin();
  for (byte i = 8; i < 120; i++)
  {
    Wire.beginTransmission (i); // Begin I2C transmission Address (i)
    if (Wire.endTransmission () == 0) //0=success(ACK response) 
    {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);     // PCF8574 7 bit address
      Serial.println (")");
      count++;
    }
  }
  Serial.print ("Found ");      
  Serial.print (count, DEC);        // numbers of devices
  Serial.println (" device(s).");
}

void loop()
{
  Scanner ();
  delay (5000);
}

我接上一個 0.96吋的 OLED 螢幕,掃描到的 I2C 的位置有3個,分別是

I2C scanner. Scanning …
Found address: 32 (0x20)
Found address: 60 (0x3C)
Found address: 80 (0x50)
Found 3 device(s).

I2C 位址掃描結果

用 Arduino 打開 AdafruitSSD1306 範例檔,我參考網路上資源加上了一些文字顯示,程式碼如下:

/**************************************************************************
 This is an example for our Monochrome OLEDs based on SSD1306 drivers

 Pick one up today in the adafruit shop!
 ------> http://www.adafruit.com/category/63_98

 This example is for a 128x64 pixel display using I2C to communicate
 3 pins are required to interface (two I2C and one reset).

 Adafruit invests time and resources providing this open
 source code, please support Adafruit and open-source
 hardware by purchasing products from Adafruit!

 Written by Limor Fried/Ladyada for Adafruit Industries,
 with contributions from the open source community.
 BSD license, check license.txt for more information
 All text above, and the splash screen below must be
 included in any redistribution.
 **************************************************************************/

#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)
// The pins for I2C are defined by the Wire-library. 
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///這裡要設定Address為 0x3C
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
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000 };

void setup() {
  Serial.begin (115200);  
  Wire.begin (26, 27);   // sda=GPIO_26, scl=GPIO_27,設I2C腳位為26,27
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds

  // Clear the buffer
  display.clearDisplay();

  // Draw a single pixel in white
  display.drawPixel(10, 10, SSD1306_WHITE);

  // Show the display buffer on the screen. You MUST call display() after
  // drawing commands to make them visible on screen!
  display.display();
  delay(2000);
  // display.display() is NOT necessary after every single drawing command,
  // unless that's what you want...rather, you can batch up a bunch of
  // drawing operations and then update the screen all at once by calling
  // display.display(). These examples demonstrate both approaches...

  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // Invert and restore display, pausing in-between
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // Animate bitmaps
}

void loop() {
  display.setTextColor(WHITE);                           //設定顯示文字的顏色
  display.setTextSize(1);                                        //設定第1行文字的大小為1
  display.setCursor(0,0);                                        //設定第1行文字在oled上顯示的座標
  display.println("Hello, world!");                         //設定第1行顯示的文字

  display.setTextSize(2);                                        //設定第2行文字的大小為2
  display.setCursor(0,15);                                      //設定第2行文字在oled上顯示的座標
  display.println("First");                                       //設定第2行顯示的文字

  display.setTextSize(3);                                        //設定第3行文字的大小為3
  display.setCursor(0,40);                                      //設定第3行文字在oled上顯示的座標
  display.println("Second");                                  //設定第3行顯示的文字

  display.display();                                                 //顯示資料緩衝區內的資料
  delay(2000);
  display.clearDisplay();                                        //清除資料緩衝區內的資料
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // Clear display buffer

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, 0, i, display.height()-1, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn line
    delay(1);
  }
  for(i=0; i<display.height(); i+=4) {
    display.drawLine(0, 0, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.width(); i+=4) {
    display.drawLine(0, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(0, display.height()-1, display.width()-1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=display.width()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=display.height()-1; i>=0; i-=4) {
    display.drawLine(display.width()-1, display.height()-1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for(i=0; i<display.height(); i+=4) {
    display.drawLine(display.width()-1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for(i=0; i<display.width(); i+=4) {
    display.drawLine(display.width()-1, 0, i, display.height()-1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000); // Pause for 2 seconds
}

void testdrawrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=2) {
    display.drawRect(i, i, display.width()-2*i, display.height()-2*i, SSD1306_WHITE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testfillrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2; i+=3) {
    // The INVERSE color is used so rectangles alternate white/black
    display.fillRect(i, i, display.width()-i*2, display.height()-i*2, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn rectangle
    delay(1);
  }

  delay(2000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // Update screen with each newly-drawn circle
    delay(1);
  }

  delay(2000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    display.drawRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for(int16_t i=0; i<display.height()/2-2; i+=2) {
    // The INVERSE color is used so round-rects alternate white/black
    display.fillRoundRect(i, i, display.width()-2*i, display.height()-2*i,
      display.height()/4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for(int16_t i=0; i<max(display.width(),display.height())/2; i+=5) {
    display.drawTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for(int16_t i=max(display.width(),display.height())/2; i>0; i-=5) {
    // The INVERSE color is used so triangles alternate white/black
    display.fillTriangle(
      display.width()/2  , display.height()/2-i,
      display.width()/2-i, display.height()/2+i,
      display.width()/2+i, display.height()/2+i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(2000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // Not all the characters will fit on the display. This is normal.
  // Library will draw what it can and the rest will be clipped.
  for(int16_t i=0; i<256; i++) {
    if(i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(2000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(2000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // Scroll in various directions, pausing in-between:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(2000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(2000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 // Indexes into the 'icons' array in function below
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // Initialize 'snowflake' positions
  for(f=0; f< NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for(;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for(f=0; f< NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // Then update coordinates of each flake...
    for(f=0; f< NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

OLED顯示影片如下:https://www.youtube.com/watch?v=9GmNvnwMRaI

如果使用的OLED是 128×64,無法正常顯示的話,需要修改 Arduino下 Libraries 資料夾中Adafruit_SSD1306的 Adafruit_SSD1306.h,修改為 #define SSD1306_128_64。如下圖:

How to remove and reinstall Node-Red in macOS Big Sur 11.4

資料來源:
1. https://www.hackster.io/daquilnp/3-steps-to-installing-node-red-and-bean-nodes-on-mac-os-ebaee2
2.https://stackoverflow.com/questions/11177954/how-do-i-completely-uninstall-node-js-and-reinstall-from-beginning-mac-os-x?newreg=c6cfabe02a584b76a1812859f2575651
3.https://stackabuse.com/how-to-uninstall-node-js-from-mac-osx/
4.https://diyprojects.io/installing-using-node-red-macos-windows/

Uninstall Node-red

原本已經參考這位大神(資料來源1)他的安裝步驟,安裝完成Node-Red,因 使用過程中,Tensorfolw coco ssd 節點啟動不起來,移除也無法移除,只要重新安裝。

第一次刪除重新安裝步驟(失敗):(參考益師傅Node-red Windows版災難復原)

1.將隱藏檔案顯示出來

Shift + Command + .
這樣就可以顯示出隱藏的檔案囉,只要再按一次就可以重新隱藏。(參考MacUknow

Mac 隱藏檔案

2.備份.Node-Red 檔案夾的這三個檔案

(1)flows.json:這是原本流程頁簽內所有的流程的檔案,重安裝完成後匯入 Node-Red。
(2)package.json:這是原本已安裝節點的檔案,重安裝完成後匯入 Node-Red
(3)settings.js:這是Node_Red 的設定檔,存放著使用者帳號、密碼,重安裝完成後,將帳號、密碼相關資料複製到新的 settings.js 檔案中。

3.刪除.Node-Red 相關檔案夾
(1)刪除.node-Red 檔案夾
(2)刪除.node-gyd 檔案夾
(3)刪除.nmp 檔案夾

4.重新開機。

5.重新安裝Node-Red

使用大神安裝檔安裝,會把 Node-Red 與 Light Blue Bean節點一起安裝,但是我主要是安裝 Node-Red ,Light Blue Bean節點一起安裝,只要不用其實沒有什麼關係,或者安裝完成 Node-Red 後,再把它移除,以免與想要使用的節點衝到。

打開 安裝檔的目錄按滑鼠右鍵 > 服務 > 終端機視窗打開 ,

安裝完成後,Tensorfolw coco ssd 節點仍然啟動不起來,只好再次刪除重裝!!!

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

第二次刪除重新安裝步驟:(參考資料來源2資料來源3

1.將隱藏檔案顯示出來

Shift + Command + .
這樣就可以顯示出隱藏的檔案囉,只要再按一次就可以重新隱藏。(參考MacUknow

2.備份.Node-Red 檔案夾的這三個檔案(先前已完成)

3.刪除 Node-Red 所有相關檔案夾
(1)刪除.node-Red 檔案夾
(2)刪除.node-gyd 檔案夾
(3)刪除.nmp 檔案夾
(4)再參考資料來源2資料來源3 手動刪除資料夾或檔案。
下面這些可能就是所有的檔案,但是作者不確定,但我刪除這些就沒問題了。

Uninstall Node-red 手動刪除檔案清單

這樣刪除後就算是手動乾淨移除 Node-red了!

Install Node-red

參考 資料來源4 進行安裝:

1.先安裝 Node.js :前往官方網站下載 安裝檔,請下載14.17.5 LTS 版本,或者是參考 這裡 使用 Command Line 手動安裝。

Node.js官方下載點
Node-red Command Line 安裝

2.安裝 Node-red

(1)打開終端機輸入下面程式碼

sudo npm install -g --unsafe-perm node-red

您必須在 sudo 的 npm 命令之前執行。 -g 表示將上傳到 npm 目錄,並且可用於所有 node.js。 –unsafe-perm 允許在出現錯誤時繼續安裝。

(2)安裝完成後,打開終端機輸入下面程式碼:

killall Finder

重新啟動 Finder

(3)啟動 Node-red:再次打開終端機輸入下面程式碼:

node-red
啟動 Node-red

(4)最後打開瀏覽器,輸入:http://127.0.0.1:1880

Done !

ESP32學習筆記-01:ESP32輔助板-01

資料來源:
1.IoT 物聯網應用:使用ESP32開發版與 Arduino C 程式語言
2.ESP32 x NBIoT 模組 i2c燈號測試程式

這是正式學習ESP32及Arduino C 語言的第一步,買了尤濬哲老師的書「IoT 物聯網應用:使用ESP32開發版與 Arduino C 程式語言」,以及ESP32、ESP32Cam、ESP32輔助板,入門IOT領域。

以下是尤老師的程式說明:
本範例說明如何使用本教學輔助板(ESP32 Matrix)的LED
教學板使用GPIO 26,27連接附加的I2C晶片
一、依照LED編號開啟或關閉:
MatrixInt(LED編號,開關),燈號(0~7),開關(1/0)

燈編號列表:
1.訊號指示燈:0~4
2.紅色LED:5
3.綠色LED:6
4.藍色LED:7

Example:
MatrixInt(1,1);//開1號燈
MatrixInt(5,0);//關5號燈


二、按信號強度開啟訊號指示燈:
MatrixLEDrssi(rssi);
MatrixLEDrssi(-60);//大於-65:5 顆Leds
MatrixLEDrssi(-70);//大於-75:4 顆Leds
MatrixLEDrssi(-80);//大於-85:3 顆Leds
MatrixLEDrssi(-90);//大於-95:2 顆Leds
MatrixLEDrssi(-100);//大於-105:1 顆Leds
//其餘均為0 Led

三、程式碼:(小弟有做一些小修改)

#include <Wire.h>
#include "MatrixInt.h"

void setup() {
  Serial.begin(115200);
  Wire.begin(26, 27);
}

void loop() {
  Serial.println("Turn on ALL LEDs by ID");
  for (int i = 0; i < 8; ++i)
  {
    MatrixInt(i, 1);//亮燈
    Serial.println("LED " +  String(i) + " 亮燈");//在序列監視埠輸出顯示「LED 號碼 亮燈」
    delay(1000);
    MatrixInt(i, 0);//關燈    
  }
  Serial.println("Turn on RSSI LED by RSSI value");

  for (int i = -50; i > -120; i=i-1)
  {
    Serial.println("RSSI = " +  String(i));
    MatrixLEDrssi(i);
    delay(300);
  }
  delay(1000);
}

加快 Mac 桌面 Dock 工具列的顯示速度

資料來源:https://briian.com/39552/

設定方法:開啟「終端機」視窗,貼上以下指令….

加快隱藏/顯示速度:

defaults write com.apple.dock autohide-time-modifier -int 0;killall Dock

或是

defaults write com.apple.dock autohide-time-modifier -int 0.8;killall Dock

恢復原本的設定:

defaults delete com.apple.dock autohide-time-modifier;killall Dock