【ESP32入門】ESP8266との比較と追跡カメラを制御する♪ ～flash read error 1000の解決～

昨夜は、やっとesp32もうまくMicroPythonがインストールできたので、ここではesp8266との違いをまとめると共に、追跡カメラを動かしてみました。

###やったこと
・インストールの違い
・見かけの違いと利用できるPinについて
・追跡カメラのコード
###・インストールの違い
esp8266とesp32のイントールコマンドは参考から以下のとおりです。
まず、flashの消去は同一のコマンドで消せる。
【参考】
①[deploying-the-firmware@Getting started with MicroPython on the ESP8266](https://docs.micropython.org/en/latest/esp8266/tutorial/intro.html#deploying-the-firmware)
②[deploying-the-firmware@Getting started with MicroPython on the ESP32](https://docs.micropython.org/en/latest/esp32/tutorial/intro.html#deploying-the-firmware)

binのversionはともかく、それぞれ以下のコマンドです。

```
$ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20170108-v1.8.7.bin
または、 (e.g. some variants of a NodeMCU board) 以下を推奨しています
$ esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect -fm dio 0 esp8266-20170108-v1.8.7.bin
一方、esp32では、
$ esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash -z 0x1000 esp32-20180511-v1.9.4.bin
```
当初、esp32でインストールできなかったのは、このコマンドが異なっていたことが原因です。しかし、異なったコマンドでも、同じように書込みが正常に終了します。
ただし、Thonnyに接続したり、以下のコマンドでSerialを開くと、

```
$ sudo screen /dev/ttyUSB0 115200
```
error

```
flash read error 1000
```
が出て、このエラーはいろいろな理由で出ているようですが、エラーの意味は、

```
Then it basicly tells you, it cant read from addres 0x1000, 
```
ということのようです。
ということで、`write_flash -z 0x1000`が効果があったと言えると思います。
例えば、以下の例
③[flash read err, 1000 (IDFGH-807) #113](https://github.com/espressif/esp-idf/issues/113)
**つまり、今回はflashへの書き込みができていなかったためとかんがえられます。**
以下の参考にesptool.pyの解説がありますが、この解説からは何が原因で正常な書き込みが出来ないのかは明確にはなりません。
※上記と合わせると、--chipの指定と -z 0x1000の指定が必要だったのかなと思います
【参考】
④[ESP32でesptool.pyの使い方](https://lang-ship.com/blog/work/esp32-esptool-py/)
###・見かけの違いと利用できるPinについて
これは、アマゾンの販売サイトのesp8266の画像やesp32サイトからpin配置から両者の比較をしてみます。
まず、esp8266は、[DiyStudio ESP8266 NodeMCU ESP-12E；アマゾン](https://www.amazon.co.jp/gp/product/B07N4MP87M/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)を利用しています。
一般的なpin配置図は以下のとおり
[ESP8266 Pinout Reference: Which GPIO pins should you use?](https://randomnerdtutorials.com/esp8266-pinout-reference-gpios/)より

![esp8266pins_12ENodeMCUKit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/527376fe-abda-ae36-0596-c56e862cc5b3.png)
アマゾンより
![esp8266pins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/7555d630-a7a7-0b09-8bda-a047eb363dab.png)
そして、上記サイトより
![esp8266pins_explains.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/0de4450b-fdec-b612-1fa5-ec03ef6589c8.png)
これらの情報から、以下のように接続しています。

| esp8266 |mpu9250|servo|Led|
|:-:|:-:|:-:|:-:|
|GND|GND|GND|GND|
|Pin(3.3v)|3.3v|-|-|
|PILO(4.2v)|-|+|-|
|Pin(5)|SCL|-|-|
|Pin(4)|SDA|-|-|
|PWM(Pin(0))|-|Servo1(yellow)||
|PWM(Pin(12))|-|Servo2(yellow)||
|Pin(14, Pin.OUT)|-|-|led(+)|

[wayintopのesp32は以下のとおり；アマゾン](https://www.amazon.co.jp/gp/product/B086QKRY25/ref=ppx_yo_dt_b_asin_title_o03_s01?ie=UTF8&psc=1)です。
![Wayintop_esp32pins.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/b5800beb-f6b2-256d-9ccd-ef2e85c5ffc4.png)

| esp32 |mpu9250|servo|Led|
|:-:|:-:|:-:|:-:|
|GND|GND|GND|GND|
|Pin(3.3v)|3.3v|-|-|
|PILO(4.2v)|-|+|-|
|Pin(22)|SCL|-|-|
|Pin(21)|SDA|-|-|
|PWM(Pin(0))|-|Servo1(yellow)||
|PWM(Pin(2))|-|Servo2(yellow)||
|Pin(15, Pin.OUT)|-|-|led(+)|
###・追跡カメラのコード
ということで、追跡カメラのコードは以下の通りほぼ同じコードで動きました。

<details><summary>esp32の追跡カメラのコード</summary><div>

```py
from machine import Pin
from machine import I2C
from machine import PWM
import time
import math as mt

class mpu9250:
    def __init__(self, scl, sda):
        self.scl = scl
        self.sda = sda
        self.i2c = I2C(0,scl = self.scl, sda = self.sda, freq = 100000)
        slv = self.i2c.scan()
        #print(slv)

        self.slvAddr = 104
        # レジスタをリセットする
        self.writeByte(0x6B,0x80)   
        time.sleep(0.1)     

        # PWR_MGMT_1をクリア
        self.writeByte(0x6B,0x00) 
        time.sleep(0.1)

    def readXYZ(self):
        data    = self.readByte(0x3B ,6)
        x    = (2.0 / 0x8000) * u2s(data[0] << 8 | data[1])
        y    = (2.0 / 0x8000) * u2s(data[2] << 8 | data[3])
        z    = (2.0 / 0x8000) * u2s(data[4] << 8 | data[5])
        return (x,y,z)

    def readTemp(self):
        data    = self.readByte(0x41 ,2)
        raw    = data[0] << 8 | data[1]    # 上位ビットが先
        temp= u2s(raw)/340 + 36.53
        return temp

    def readGyro(self):
        data    = self.readByte(0x43 ,6)
        x    = (250 / 0x8000) * u2s(data[0] << 8 | data[1])
        y    = (250 / 0x8000) * u2s(data[2] << 8 | data[3])
        z    = (250 / 0x8000) * u2s(data[4] << 8 | data[5])
        return (x,y,z)

    def writeByte(self, addr, data):
        d = bytearray([data])
        self.i2c.writeto_mem(self.slvAddr, addr, d)

    def readByte(self, addr, num):
        s = self.i2c.readfrom_mem(self.slvAddr, addr, num)
        return s

#unsignedを、signedに変換(16ビット限定）
def u2s(unsigneddata):
    if unsigneddata & (0x01 << 15) : 
        return -1 * ((unsigneddata ^ 0xffff) + 1)
    return unsigneddata

def get_angle(rawX, rawY, rawZ):
    pitch = mt.degrees(mt.atan2(rawX, mt.sqrt(rawY*rawY+rawZ*rawZ)))
    roll = mt.degrees(mt.atan2(rawY, rawZ))
    return pitch, roll

if __name__ == "__main__":
    start = time.time()
    scl = Pin(22)
    sda = Pin(21)
    servo1 = PWM(Pin(0))
    servo2 = PWM(Pin(2))
    servo1.freq(100)
    servo2.freq(100)
    led_onboard = Pin(15, Pin.OUT)

    snsr = mpu9250(scl, sda)
    f = open('write1.txt', 'wb')
    f.write('t:  pitch:   zg_:  ' + ' \n')
    xg_,yg_,zg_ = 0,0,0
    x0,y0,z0 = snsr.readXYZ()
    z0 = z0 - 1
    try:
        while True:
            t = time.time()- start
            #print(t)
            x1,y1,z1 = snsr.readXYZ()
            x, y, z = x1-x0,y1-y0,z1-z0
            xg,yg,zg = snsr.readGyro()
            pitch, roll = get_angle(x,y,z)
            xg_ += xg
            yg_ += yg
            zg_ += zg
            #print('xg_,yg_,zg_=',xg_,yg_,zg_)
            print(zg,zg_,pitch)
            duty = int(150 - pitch)
            duty1 = int(150 - zg_) #int(roll)
            #print(duty, duty1)
            servo1.duty(duty1)
            servo2.duty(duty)
            led_onboard.on()
            f.write('{}'.format(t)+ ' ')
            f.write('{0:.2f} {1:.2f}'.format(pitch,zg_)+'\n')
            time.sleep(0.8)
            led_onboard.off()
            time.sleep(0.2)
    except KeyboardInterrupt:
        pass
    finally:
        f.close()
        pass
```
</div></details>

一方、ブレッドボードの様子は以下のとおり、ぎりぎりです。
GNDや電源供給は、外部電源のLIPOや外回りに逃がして確保しています。
![tuisekicamera.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233744/0c4241ed-3b7b-e82f-15a9-6e38f09974e9.jpeg)
###まとめ
・esp8266とesp32のインストールの違いを明らかにし、安定してインストールしてRaspi4及びwindows上のThonnyにてMicroPythonで開発が出来るようになった
・結線のpinについて明らかにし、追跡カメラのコードを移植できた

・picoに比較して優位な機能である通信機能を利用して外部から制御したいと思う
###おまけ
```
 $ esptool.py -h
usage: esptool [-h] [--chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}]
               [--port PORT] [--baud BAUD]
               [--before {default_reset,no_reset,no_reset_no_sync}]
               [--after {hard_reset,soft_reset,no_reset}] [--no-stub]
               [--trace] [--override-vddsdio [{1.8V,1.9V,OFF}]]
               [--connect-attempts CONNECT_ATTEMPTS]
               {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info}
               ...

esptool.py v3.0 - ESP8266 ROM Bootloader Utility

positional arguments:
  {load_ram,dump_mem,read_mem,write_mem,write_flash,run,image_info,make_image,elf2image,read_mac,chip_id,flash_id,read_flash_status,write_flash_status,read_flash,verify_flash,erase_flash,erase_region,version,get_security_info}
                        Run esptool {command} -h for additional help
    load_ram            Download an image to RAM and execute
    dump_mem            Dump arbitrary memory to disk
    read_mem            Read arbitrary memory location
    write_mem           Read-modify-write to arbitrary memory location
    write_flash         Write a binary blob to flash
    run                 Run application code in flash
    image_info          Dump headers from an application image
    make_image          Create an application image from binary files
    elf2image           Create an application image from ELF file
    read_mac            Read MAC address from OTP ROM
    chip_id             Read Chip ID from OTP ROM
    flash_id            Read SPI flash manufacturer and device ID
    read_flash_status   Read SPI flash status register
    write_flash_status  Write SPI flash status register
    read_flash          Read SPI flash content
    verify_flash        Verify a binary blob against flash
    erase_flash         Perform Chip Erase on SPI flash
    erase_region        Erase a region of the flash
    version             Print esptool version
    get_security_info   Get some security-related data

optional arguments:
  -h, --help            show this help message and exit
  --chip {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}, -c {auto,esp8266,esp32,esp32s2,esp32s3beta2,esp32c3}
                        Target chip type
  --port PORT, -p PORT  Serial port device
  --baud BAUD, -b BAUD  Serial port baud rate used when flashing/reading
  --before {default_reset,no_reset,no_reset_no_sync}
                        What to do before connecting to the chip
  --after {hard_reset,soft_reset,no_reset}, -a {hard_reset,soft_reset,no_reset}
                        What to do after esptool.py is finished
  --no-stub             Disable launching the flasher stub, only talk to ROM
                        bootloader. Some features will not be available.
  --trace, -t           Enable trace-level output of esptool.py interactions.
  --override-vddsdio [{1.8V,1.9V,OFF}]
                        Override ESP32 VDDSDIO internal voltage regulator (use
                        with care)
  --connect-attempts CONNECT_ATTEMPTS
                        Number of attempts to connect, negative or 0 for
                        infinite. Default: 7.

```