Raspberry Pi Zero (W, WH, 2 W)でサイクルコンピューターを作ってみよう

github repository is here
https://github.com/hishizuka/pizero_bikecomputer

(2020/10/4) [Maker Faire Tokyo2020](https://makezine.jp/event/makers-mft2020/m0016/)で非常に多くの方に興味を持っていただき、ありがとうございます。本記事の内容は、構成の解説や使い方で若干更新が間に合っておらず、上記Githubの英語版が最新となっております。

[ロードバイクアドベントカレンダー2019](https://adventar.org/calendars/4172)の22日目になります。大分異色な技術寄りの投稿になりますが、よろしくお願いします。

筆者はサイクルコンピューターを1から自作するという取り組みを数年前からしています。2019年春に一定の形までたどり着いたので「[サイクルコンピューターをガチで作ってみたら、割とできてしまったという話](https://qiita.com/hishi/items/8f77fd4655027fac7c7d)」を公開しました。~~実際はMaker Faire Tokyo 2019の応募文章だったので、ポエム成分多めで書いたのですが、見事に落選しました(笑)~~

この投稿自体はありがたいことに大きな反響を頂きましたので、今回、せっかくの機会なので続編を書き起こしてみました。

今回はレシピ（[プログラム](https://github.com/hishizuka/pizero_bikecomputer)+組み立て方）を公開しますので、ぜひ実際に手を動かして試して下さい！　小さなシングルコンピューターから自分でデバイスが作れる、という新たな愉しみを感じ取っていただければ幸いです。

日々の細かいアップデートは[Twitter](https://twitter.com/pi0bikecomputer)で発信しています。こちらもよろしくお願いします。

# はじめに
Raspberry Pi Zero Wで、スポーツ自転車向けにサイクルコンピューターを作っています。実装中の機能やハードウェア構成は、「[サイクルコンピューターをガチで作ってみたら、割とできてしまったという話](https://qiita.com/hishi/items/8f77fd4655027fac7c7d)」をご一読ください。

今の見た目はこんな感じです。Topeakのスマートフォンケースを代用し、ある程度の防水ができています。
![title-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/a6746d2f-bae0-a511-f6e7-972d4c6bc592.png)
![top_screen-04](https://user-images.githubusercontent.com/12926652/206645388-7440cea8-a796-47fe-b470-7285a64e64fb.jpeg)

外装ケースがないのでボタンは少々押しづらいですが、普通に使えています。
2022年は5,000km弱(＝ざっくり土日どこかの半日100km×4週×12ヶ月)のデータが取れました。
(何のしがらみもなく土日合計200km以上を走れていた頃が懐かしい…)

それではお待ちかね、レシピのお披露目になります。
相当長いので、お時間に余裕のある時にどうぞ。

# PCで起動確認

まずはお手持ちのPCで、ソフトウェアの起動を試してみましょう。

このプログラムの一つの大きな特徴は、実機で直接画面を描画するプログラムをゴリゴリ書かず、PCで開発できると言う点です。気圧センサーやGPSの値は流石に実機でないと確認できませんが、画面やメインロジックはPCで書いて確認した方がはるかに効率がいいです。

## 必要なもの

- python(version3系)実行環境
- pipコマンド
- pythonのプログラミングスキル、必要なパッケージをインストールできるスキル
- gitコマンド

## 起動まで

レポジトリからgitコマンドで持っていきます。

```console
$ git clone https://github.com/hishizuka/pizero_bikecomputer.git
$ cd pizero_bikecomputer
```

必要なパッケージをインストールします。

```console
$ pip install PyQt6 numpy cython setuptools pillow pyqtgraph oyaml polyline aiohttp aiofiles qasync

$ pip install git+https://github.com/hishizuka/crdp.git
```

起動できるか、確認します。

```console
$ python3 pizero_bikecomputer.py
```
<img width="400" alt="screen01" src="https://user-images.githubusercontent.com/12926652/206077256-f8bda5e5-e4a3-4c39-a7ff-ea343067756c.png">

--demoオプションをつけると、適当に数字が出たり出なかったりします。

初回起動時に必要なディレクトリや設定ファイル(setting.conf)等が作られるので、一度閉じてください。

## 使い方

画面下部にあるボタンは割と見ての通りですが、左から順に以下の機能を割り当てています。
(実は短押し/長押し共に変更可)

- 左ボタン(<)：画面間の移動
  - 地図画面やコースプロファイル画面に遷移します。
- ラップボタン：ラップ。ストップ時に長押しでリセットし、logフォルダ以下にfitファイルを出力。
- メニューボタン：メニュー画面に移動
- スタート/ストップボタン：スタートとストップの状態を遷移。長押しでプログラム終了。
- 右ボタン(>)：画面間の移動

数値を表示する画面は、上記のボタンのみですが、一部の画面で追加のボタンや操作があるので解説していきます。

### 地図

<img width="400" alt="map-01" src="https://user-images.githubusercontent.com/12926652/206341071-5f9bee00-d959-489b-832a-9b4bf7fe2279.png">

#### 左サイド

- "-": ズームアウト
- "L": 移動ボタン(右サイド)のロック/アンロック
- "+": ズームイン
- "G": Google Directions APIによる経路検索ボタン
  - setting.conf内の GOOGLE_DIRECTION_API セクションでトークンを設定したら表示されます

#### 右サイド

左サイドの上から2番目のアンロックボタンを押した状態で、上下左右の移動ができるようになります。

### コースプロファイル
<img width="400" alt="map-02" src="https://user-images.githubusercontent.com/12926652/206341086-7935cfbd-8ed3-4068-9f2b-93f676a8932a.png">

左サイド

- "-": ズームアウト
- "L": 移動ボタン(右サイド)のロック/アンロック
- "+": ズームイン

#### 右サイド

左サイドの上から2番目のアンロックボタンを押した状態で、左右の移動ができるようになります。

### メニュー画面
<img width="400" alt="menu-01" src="https://github.com/hishizuka/pizero_bikecomputer/assets/12926652/46291e12-9104-4486-a896-aaf7010d7cd2">

各項目ごとに解説しますが、自明な項目の説明は省きます。

#### Sensors

<img width="400" alt="menu-02-sensors" src="https://user-images.githubusercontent.com/12926652/206076191-4b8a4084-64a0-443b-a434-f6c6b4d51e2a.png">

- ANT+ Sensors
  - ANT+のライブラリを入れた状態、かつ、setting.confの[ANT]ブロックの冒頭```status = True```とすると、各種センサーとのペアリングが可能になります。
  - センサー接続時にペアリングに必要な情報をsetting.confへ出力するので、次回起動時は自動で接続しにいきます
- ANT+ MultiScan
  - 周囲に存在する複数のANT+心拍計とANT+パワーメーターの値を見にいきます。
- Wheel Size
  - ANT+スピードセンサーが使えるときは、ホイール周長をmm単位で入力してください。距離の計算に使います。デフォルトは700x25cのタイヤ周長である2,105mmにしています。入力された値はsetting.confに記録します。
- Adjust Altitude
  - Raspberry Pi(以下実機と記載)で気圧センサーを接続している場合、現在地の高度を入力することで海面更正を行い、精度を上げられます。
  - コースファイルに高度が含まれている場合、1回だけ自動的に行われます。

#### Courses

<img width="400" alt="menu-03-courses" src="https://user-images.githubusercontent.com/12926652/206076194-a0b3b356-fbda-4591-ba27-02701e461aaa.png">

- Local Strage
  - courseフォルダに配置された .tcx ファイルをリスト表示します。
- Ride with GPS
  - setting.conf でトークンが設定されていると、コースを最新順に表示します。コースを選択すると詳細画面に入り、右上の白い">"ボタンでコースを読み込みます。(下図参照)
- Google Direction API mode
  - setting.conf でトークンが設定されていると、地図画面で本APIによる経路探索が可能になります。
  - この項目は、経路探索時に自動車(Car)か自転車(Bycicle)を選択できます。
  - 地域によっては、自転車の検索に対応していないことがあるので、その時は自動車にしてください。自動車の検索時は、有料道路と高速道路は除外する設定をしています。

<img width="400" alt="RidewithGPS-01" src="https://user-images.githubusercontent.com/12926652/206076210-9c50f789-bac3-4bd0-8209-9dea3a61a132.png"> <img width="400" alt="RidewithGPS-02" src="https://user-images.githubusercontent.com/12926652/206076212-8696ac34-c9e6-485f-b1ba-687c0d2a0061.png">

#### Upload Acticity

<img width="400" alt="menu-04-upload_activity" src="https://user-images.githubusercontent.com/12926652/206076198-55803175-ef4c-4f9b-9408-b44dbe98b1b3.png">

リセット操作で書き出した直近の記録ファイルを、各クラウドサービスにアップロードします。いずれも setting.conf にトークン、またはメールアドレスとパスワードの設定が必要です。

#### Live Track

<img width="400" alt="livetrack-01" src="https://github.com/hishizuka/pizero_bikecomputer/assets/12926652/9f9660fd-eca4-4b97-a60a-d2ff890bf3f0">

- Live Track
  - [ThingsBoard](https://thingsboard.io)によるリアルタイムアップロード機能を有効にします。
  - `tb-mqtt-client`パッケージが必要なので、`pip`コマンドでインストールしてください。
  - データのアップロードには、Thingsboardデバイスアクセストークンが必要となるので、アカウントを作成し、デバイスを作成したら、setting.confのTHINGSBOARD_APIセクションに記載ください。
  - ダッシュボードのアップロードや設定も別途必要になるので、詳細は[レポジトリの解説ページ](https://github.com/hishizuka/pizero_bikecomputer/blob/master/doc/thingsboard_setup.md)を参照ください。
- Auto upload via BT
  - ThingsBoardへのアップロードをBTテザリング経由で行います。`bluetoothctl`コマンドで事前にペアリング下さい。詳細は[こちら](https://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573#オプションbluetoothテザリングによるネットワーク設定)を参照ください。
  - データのアップロードは2分間隔で実行され、Wifiのテザリングを行うより、Raspberry Pi本体、スマートフォン両方で消費電力を大幅に削減できます。
- Select BT device
  - Bluetoothテザリングに使う端末を指定できます。

#### Map

<img width="400" alt="menu-05-map" src="https://user-images.githubusercontent.com/12926652/206076200-383c1d24-ec26-4b79-95e9-a6fd88e161dd.png"> <img width="400" alt="menu-06-map_overlay" src="https://user-images.githubusercontent.com/12926652/206076202-29989a71-34c0-4892-8433-48305868326d.png">

Select Mapはconfig.pyにビルトインされている地図、およびmap.yamlに記載された地図をリスト表示します。

Map Overlayはよく走られている道路を示すHeatmap、雨雲マップ、風速マップを重ねて表示するための設定画面です。

##### Heatmap

使用するためには、setting.confに追加の設定が必要です。
Stravaはemailとパスワード、Ride with GPSはアクセストークンを設定してください。

以下はStrava heatmap (bluered)の例です。荒川の朝霞水門あたりですが、荒川サイクリングロードがはっきりと高頻度の赤色となっています。

![map_overlay-strava](https://user-images.githubusercontent.com/12926652/205793586-0b754cde-d1e7-4e57-81d2-2bbd60fc8b11.png)

##### Rain map

特に設定なく、世界向けの[RainViewer](https://www.rainviewer.com/weather-radar-map-live.html)と[気象庁降水ナウキャスト](https://www.jma.go.jp/bosai/nowc/)が選択できます。

RainViewer
![map_overlay_rainviewer](https://user-images.githubusercontent.com/12926652/205876664-ae1b629c-5b3f-4d8a-b789-d3ac24753d7f.png)

気象庁降水ナウキャスト
<img src ="https://user-images.githubusercontent.com/12926652/205563333-549cf4dc-abbd-4392-9233-b8391687e0bc.png" width=400/> 

##### Wind map

こちらも特に設定なく、世界向けの[openportguide](http://weather.openportguide.de/map.html)と[SCW](https://supercweather.com)が選択できます。

openportguide

![map_overlay_weather openportguide de](https://user-images.githubusercontent.com/12926652/205876684-253b672f-615d-410c-8496-5eb9a13b2558.png)

#### Profile

<img width="400" alt="menu-07-profile" src="https://user-images.githubusercontent.com/12926652/206076204-197f2454-940b-4267-a626-52740391ddac.png">

ANT+パワーメーターを使用しているときに計算される、W'balance(%)を計算するためのパラメーターであるCPとW'balanceを入力します。データが蓄積されていれば、[GoldenCheetah](http://www.goldencheetah.org)や[intervals.icu](https://intervals.icu)で求めることができます。


#### System

<img width="400" alt="menu-08-system" src="https://github.com/hishizuka/pizero_bikecomputer/assets/12926652/402692a5-1612-4bf3-a645-a84ba91b766b">

- Network
  - WifiやBTのオンオフを行います
  - BT Tetheringは、Bluetoothのテザリングを行い、インターネット接続をします
    - あらかじめ、`bluetoothctl`コマンドで対象のデバイスとペアリング済であることが必要です。詳細は[こちら](https://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573#オプションbluetoothテザリングによるネットワーク設定)を参照ください。
  - GadgetBridgeは、Androidの[GadgetBridge](https://gadgetbridge.org)アプリを介して、通知の転送を行ったり、GPSモジュールの代わりにスマートフォン経由で位置情報を取得する開発/検証中の機能です。
    - <img width="400" alt="message" src="https://user-images.githubusercontent.com/12926652/206078983-fcf6b101-21c5-4c12-a118-d25a1e133d6a.png">
    - Raspberry Pi Zeroでは安定しないようです。Zero2なら安定します。
    - 詳細は[レポジトリの説明ページ](https://github.com/hishizuka/pizero_bikecomputer/blob/master/doc/software_installation.md#network)を参照ください。
- Update
  - プログラムを更新しにいきます。実際はupdate.sh内で`git pull origin master`を しているだけです。
- Debug log
  - デバッグログを参照できます。
- Power Off
  - 実機でサービス起動をしている時に電源を落とすのに使います。

# Raspberry Pi Zero で起動

ここまで辿り着けたら、次は実機で表示させます！

PiTFTを当初用いていましたが、プロジェクトとしてはディスコン扱いにしましたので、[記事の末尾](#raspberry-pi-zero--pitft版-アーカイブ)に移動しました。手のかかる配線は不要で、Raspberry Pi Zero WHと、PiTFTを接続すればとりあえず動くので、とにかく手軽に試したいという場合は、こちらを参照して下さい。

以下は、反射型液晶(モノクロ)または、MIPカラー反射型液晶を用いる場合の説明を行います。

「[サイクルコンピューターをガチで作ってみたら、割とできてしまったという話](https://qiita.com/hishi/items/8f77fd4655027fac7c7d)」で紹介した、トータル1万円前後になる構成で実際にサイクルコンピューターを作ってみましょう。説明を読むとわかりますが、手のかかる配線をしているので、ハンダ付けはある程度慣れた人を想定しています。

本稿ではコストを抑えるために、反射型液晶(モノクロ)版の解説をしますが、入手できるのであればMIPカラー反射型液晶でも作れるように説明を所々加えています。

## 必要なもの

### ハードウェア

結構多いので、頑張って海外からIYHするか、秋葉原で買い揃えて下さい！

- Raspberry Pi Zero (W, WH) (3,000円前後), Raspberry Pi Zero 2 W (3,000円程度)
  - セットアップは筆者の記事「[Raspberry Pi Zero(W, WH, 2 W)のセットアップ](https://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573)」等でどうぞ
- 反射型液晶(モノクロ)版
  - [Adafruit SHARP Memory Display Breakout](https://www.adafruit.com/product/4694)
  - 海外から部品を購入する際は、digi-keyやmouserなどでまとめて買うのも手です。
  - カラー液晶を買う場合、[WAHOOのパネル付き](https://www.aliexpress.com/item/1005002276498187.html?spm=a2g0o.productlist.0.0.75631bcfeHZvG1&algo_pvid=15c33af1-273e-4fac-a224-6dff903b6f43&algo_expid=15c33af1-273e-4fac-a224-6dff903b6f43-0&btsid=0b0a555416212467903751350ef791&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_)か、[オリジナル](https://www.aliexpress.com/item/1005002351792191.html?spm=a2g0o.productlist.0.0.52452576NqqM6z&algo_pvid=ba698ed0-3580-48fa-8fdc-b7774c4c9cf0&algo_expid=ba698ed0-3580-48fa-8fdc-b7774c4c9cf0-0&btsid=0bb0623116212468747683928ed47e&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_)を買うと良いです。変換ボードは上記のAdafruit SHARP Memory Display Breakoutを流用するか、バックライトが欲しいなら、[MIPカラー反射型液晶中継ボード](https://www.switch-science.com/catalog/5393/)が必要。オートバックライト動作のために、後述の照度センサーも購入必要。
- GPSモジュール (2,000円〜、オプション)
  - 位置情報を記録したい場合や地図を使いたい場合に必要。
  - [秋月電子のモジュール](http://akizukidenshi.com/catalog/g/gK-09991/)が入門として最適
  - [SparkFun GPS Breakout - ZOE-M8Q (Qwiic)](https://www.sparkfun.com/products/15193)や、[BerryGPS IMU v4](https://ozzmaker.com/product/berrygps-imu/)もおすすめ。運用には[外部アンテナ](https://www.sparkfun.com/products/15246)が別途必要。後者はI2C接続のセンサー付き(気圧/9軸IMU)で、後述のEnviro pHATの代替としても最適。pHAT接続なのでハンダ付けの作業も省略可。ただし、なぜか手元にある品は地磁気センサーが壊れている(二台中二台)。
- ANT+ USBドングル (1,000円前後、オプション)
  - ANT+センサーを使用したい場合に必要。ない場合、速度だけはGPSで代用。
  - micro USB変換コネクタとセットで調達ください
- I2Cセンサー (オプション)
  - 気圧センサーは、高度を算出するために使用。
    BMP280/BMP388/BMP390/LPS33HW/LPS35HWに対応。BMPシリーズがおすすめで、最新版になるほど低ノイズで信頼性が増す印象。センサー単独で購入するなら[Adafruit BMP390L - Precision Barometric Pressure and Altimeter - STEMMA QT / Qwiic](https://www.adafruit.com/product/4816)
  - 加速度と地磁気センサーは、取り付け角度の検出や振動検知に使用。
    LSM303/LSM6DS/LSM9DS1/LIS3MDL/BMX160/BNO055/ISM330DHCX/MMC5983MAに対応。BNO055が機能面でずば抜けているが、消費電力大なのでこの用途には向いていない。他は似たり寄ったりな印象。単独で購入するなら[Adafruit LSM6DS33 + LIS3MDL - 9 DoF IMU with Accel / Gyro / Mag - STEMMA QT Qwiic](https://www.adafruit.com/product/4485)等、9DOFのものが良い。
  - BMP388＋LSM6DSL＋LIS3MDLがまとまった[BerryIMU v3](https://ozzmaker.com/product/berryimu-accelerometer-gyroscope-magnetometer-barometricaltitude-sensor/)という商品もある
  - 照度センサーは液晶のオートバックライトで使用。TCS3472(Enviro pHAT付属)/VCNL4040に対応。Enviro pHATを使わないのであれば、[Adafruit VCNL4040 Proximity and Lux Sensor - STEMMA QT / Qwiic](https://www.adafruit.com/product/4161)。
  - センサーの接続には、[SparkFun Qwiic SHIM for Raspberry Pi](https://www.sparkfun.com/products/15794)と、[Qwiic Cable](https://www.sparkfun.com/products/14426)が何本か必要。
  - ボタンは[Button SHIM](https://shop.pimoroni.com/products/button-shim)が必要。
  - オプションとして、電源は[PiJuice](https://uk.pi-supply.com/products/pijuice-standard)、[PiJuice Zero](https://uk.pi-supply.com/products/pijuice-zero?lang=ja)にも対応。
  - セットアップは後述。
- ケース
  - 手持ちで使えるものがなければ、Topeakの[SmartPhone DryBag](http://www.topeak.jp/bag/acz23200.html)がお勧め
  - いくつかサイズ展開がありますが、5インチを推奨。
- ネジ・ナット
  - 基板間の固定に使いますが、運用時は固定することが非常に重要。
  - キット等で余ったものを使い回すか、M2.5かM2.6のネジとナットを購入する。
  - 長さも6mm程度のものと、15~20mm程度のものがあれば盤石。
  - バラ売りしていないので、揃え出すと意外と高く。
- SDカード
  - とりあえずは手持ちのもので(8GB以上のもの)。
  - 毎週使っていると1年程度で壊れてしまう。今は[サンディスクの高耐久版32GB](https://shop.westerndigital.com/ja-jp/products/memory-cards/sandisk-max-endurance-uhs-i-microsd#SDSQQVR-032G-JN3ID)を使用中で、2年経過しても順調。
    - 1世代前のHIGH ENDURANCEカードではBullseyeでは起動せず、最新のMAX ENDURANCEカードを使用すること。
- その他
  - スリムかつL字のUSB microケーブル。上記のSmartPhone DryBagを使う場合、左向きのL字ケーブルか、micro USBリバーシブルのL字ケーブルを調達しないと、ケースにスッキリ入らない。
  - モバイルバッテリー。3000mAhあれば15時間近くは使用可能。筆者は5000mAhある[Olight RN 1500](https://www.olightstore.jp/olight-rn-led.html)をバッテリー兼ライトで使用。雨天対策はなし。

作業に必要な工具は以下になります。

- はんだごて、はんだ
- ジャンパワイヤやリード線の類
- 絶縁用のテープ(セロテープ等)
- ニッパー等 (自転車のメンテナンスができるならあるかと)
- はんだで臭くなっても怒られないスペース (同上)

### スキル

- はんだごてを扱えるスキル
  - 自転車で言うと、ワイヤ交換ができる程度の器用さがあれば多分大丈夫です
- 販売元のHPを参照するなりして、個々の部品の稼働確認を行えるスキル（本文章では適宜スキップ）

### その他

- 折れない心
- パーツ破損した時のために備え、数セット買える財力
  - 上記一式がみんな大好きGP5000(ロードバイクの高級タイヤです)の2~4本分程度ですので…

## 組み立て

主な材料はこんな感じです。
![assembly-01](https://user-images.githubusercontent.com/12926652/91796767-f6803d80-ec5b-11ea-9bde-19940a951588.png)

- 上段左：Raspberry Pi Zero WH
- 上段右：PiJuice Zero (なくてもよい)
- 中段左：Adafruit SHARP Memory Display Breakout
- 中段真ん中：GPSモジュール (違うものを使っていますが、UART接続は同じです)
- 中段右：気圧センサ＋加速度・ジャイロ・地磁気センサー (違うものを使っていますが、Qwiic接続は同じです)
- 下段左：Button SHIM
- 下段真ん中：SparkFun Qwiic SHIM for Raspberry Pi

これらを組み立てていきます。

難しいなと思ったら、一つずつ確認と、順を追って動作確認をすることをお勧めします。まずディスプレイが動くことを確認し、GPSモジュールやI2Cセンサー、ANT+ USBドングルといった順です。

まずは、一番大掛かりな作業ですが、ディスプレイとRaspberry Pi Zeroを接続します。
SHARP Memory Display Breakoutに関しては、本家のチュートリアルと接続するピンを一部変えているのでご注意ください。

<img src="https://user-images.githubusercontent.com/12926652/91796771-f7b16a80-ec5b-11ea-9b24-113049fd5998.png" width=360 />

| 名称 | Raspberry Pi | SHARP Memory Display Breakout | MIPカラー反射型液晶中継ボード |
|:-|:-:|:-:|:-:|
| GND      | IO25 | GND   | CN1-4 |
| VCOMSEL  | IO11 | EXTIN | CN2-3 |
| DISP     | IO13 | DISP  | CN1-9 |
| CS       | IO15 | CS    | CN1-8 |
| 3.3V     | IO17 | VIN   | CN1-6 |
| SPI MOSI | IO19 | MOSI  | CN1-7 |
| SPI SCLK | IO23 | SCLK  | CN1-5 |

SPI SCLKは今まではIO22でしたが、今後、他機種展開を考え、IO23に移しました。


参考:
- https://pinout.xyz/pinout/io_pi_zero

MIPカラー反射型液晶中継ボードでバックライトを使う場合

| 名称 | Raspberry Pi | MIPカラー反射型液晶中継ボード |
|:-|:-:|:-:|
| LEDPWM   | IO12 | CN2-1 |
| VBUS-5V  | IO02/04 | CN3-5 |
| BL2-CTRL | IO06/09/14/20/25/34/39 | CN4-3 |

参考:
- https://docid81hrs3j1.cloudfront.net/medialibrary/2019/03/JDI_MIP_LCD.pdf
- https://qiita.com/hishi/items/669ce474fcd76bdce1f1

接続したら、画面表示ができるか確認を行った方がよいです。(動作確認の方法は後述の[初回起動まで](#初回起動まで)にて述べます)
<img src="https://user-images.githubusercontent.com/12926652/91796772-f84a0100-ec5b-11ea-8610-508f64692c9e.png" width=360 />

次に、GPSモジュールをUARTを介して、SparkFun Qwiic SHIM for Raspberry PiとButton SHIMをI2Cを介して接続します。GPSの接続は各種購入元サイトに説明があると思います。電源電圧と、RX/TXを間違えないように接続してください。

<img src="https://user-images.githubusercontent.com/12926652/91796775-f97b2e00-ec5b-11ea-8fea-52658208261f.png" width=360 />

ネジを用いて各部品を固定します。

<img src="https://user-images.githubusercontent.com/12926652/91796778-fb44f180-ec5b-11ea-91a3-2d929107cfc2.png" width=360 />

(オプション)PiJuice Zeroも接続します。

<img src="https://user-images.githubusercontent.com/12926652/91796781-fd0eb500-ec5b-11ea-8451-593858d32b17.png" width=360 />

ANT+ USBドングルがある場合、Raspberry Pi Zeroの内側にあるmicro USB端子に挿して下さい。(写真は別の組み立て例)
![assembly-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/f632a516-466c-3ee7-c217-aed050ece23f.png)

最後に、電源供給用のUSBケーブルをRaspberry Pi Zeroの外側にあるmicro USB端子に挿してください。(オプションのPiJuiceがある場合は、PiJuice側のmicro USB端子に接続ください)

ANT+ USBドングルと電源ケーブルは振動対策のため、Raspberry Pi Zeroとテープで固定します。コネクタとボードの間に隙間ができる場合は、適当な緩衝材を挟んだ上で、テープ固定して下さい。また、モバイルバッテリーのUSBコネクタも振動で瞬断しうるので、対策した方が良いでしょう。この方法で、オンロードの峠の下りでも瞬断はほとんど起きないことを確認しています。


## 初回起動までの準備

以下ができている前提とします。

- Raspbian BullseyeまたはBusterがインストールされていること (Liteでも可能だが、インストールするパッケージは増える。本稿では未解説)
- ユーザーはpi
- 何らかの形でPCからアクセスできること(USB経由またはWifi)
  - Wifiは作業場とスマートフォンのテザリングが接続できるとなお良い。後者は出先で確認したい場合の保険。

ここまで出来ていたらゴールは近いです。

まず、SSHでログインし、raspi-configでいくつか設定を変更します。

```console
$ sudo raspi-config
```

- 「1 System Options」
  - 「S1 Wireless LAN」：Wifiを使う場合は、設定します。
  - 「S3 Change User Password」：パスワードを変更します。
  - 「S4 Hostname」で必要に応じてホスト名を変更します。複数台運用する場合は変えた方がよいでしょう。ただし、ログインのホスト名も変わるので注意
  - 「S5 Boot / Auto Login」：「B1 Console」に変更します。
- 「3 Interfacing Options」
  - 「P4 SPI」「P5 I2C」をONにします。
  - 「P6 Serial　Port」はGPSモジュールを使う場合に必要で、「Would you like a login shell to be accessible over serial?」はNo、「Would you like the serial port hardware to be enabled」はYesにします。
- 「5 Localisation Options」
  - 「L2 Change Timezone」でお住まいの国のタイムゾーン(日本ならAsia->Tokyo)を選択し、時刻にタイムゾーン が反映されるようにします。```date```コマンドで確認して下さい。

ここまできたら、いったん再起動(```sudo reboot```)します。

次にアップデート祭りです。

```console
$ sudo apt update
$ sudo apt upgrade
$ sudo reboot
```

ここからインストール祭りです。

レポジトリからgitコマンドで持っていきます。

```console
$ cd
$ git clone https://github.com/hishizuka/pizero_bikecomputer.git
$ cd pizero_bikecomputer
```

必要なパッケージをインストールします。Raspbian Busterだとcython以外は最初から入っている模様です。

```console
$ sudo apt install -y git python3-venv python3-yaml cython3 cmake python3-numpy sqlite3 libsqlite3-dev python3-pil python3-aiohttp python3-aiofiles python3-psutil python3-pyqt6 python3-pyqt6.qtsvg pyqt6-dev-tools

# Pythonの仮想環境がない場合
$ python -m venv --system-site-packages ~/.env
$ source ~/.env/bin/activate
$ echo "source ~/.env/bin/activate" >> ~/.bashrc

$ pip install oyaml polyline qasync pyqtgraph git+https://github.com/hishizuka/crdp.git
$ cd pizero_bikecomputer
```

Bluetoothを使いAndroidスマホと通信したい場合や、クラウドサービスへアクティビティをアップロードをしたい場合、以下をインストールします。

```
$ sudo apt install -y bluez-obexd
$ pip install garminconnect stravacookies dbus-next bluez-peripheral tb-mqtt-client mmh3 timezonefinder
```

ディスプレイ用に以下のパッケージをインストールします。

```
$ sudo apt-get install python3-pigpio
$ sudo systemctl enable pigpiod
$ sudo systemctl start pigpiod
```

pigpiodはデフォルトの設定だとCPU使用率を10%程度使うので、気に入らない場合は/lib/systemd/system/pigpiod.serviceを編集します

```
#ExecStart=/usr/bin/pigpiod -l -m #Disable alerts
```

## 初回起動

画面が接続できているか、まずは一回起動してみます。
Cythonが使える場合は、コンパイルが走りますので、初回のみ数分かかります。

```
$ QT_QPA_PLATFORM=offscreen python3 pizero_bikecomputer.py
```

画面には何も表示されないので、一旦ctrl+cで終了し、プログラムの設定ファイルを変更します。
詳細は[設定ファイル](#設定ファイル)の項にありますが、setting.confの`display`の設定値を初期値の`PiTFT`から、ディスプレイに応じて、以下に変更します。

- `MIP_Sharp`: SHARP Memory Display Breakout
- `MIP`: MIPカラー反射型液晶モジュール 2.7型

エラーなく起動できることを確認してください。

## 追加の設定

ここまで来たら、もう一息です！

### GPS module

raspi-configによる設定ができているとして、GPSdのサービス及び、pythonで使うパッケージをインストールします。

GPSモジュールによる出力は/dev/ttyS0にあるとします。```$ cat /dev/ttyS0```で文字化けしていない文字列が出力しているか、確認してください。/dev/ttyAMA0を使っている場合は、GPSdの設定ファイル(/etc/default/gpsd)を修正してください。

```
$ sudo apt-get install gpsd gpsd-clients python3-dateutil
$ pip install gps3 timezonefinder 
$ sudo cp install/etc/default/gpsd /etc/default/gpsd
$ sudo systemctl enable gpsd
$ sudo systemctl start gpsd
```

GPSdが正しく実行されているかの確認は、```cgps```または```gpsmon```コマンドで値が取れているか確認して下さい。屋外に数分間放置したらGPSの補足ができ、緯度経度等の情報が流れてくるようになります。

### I2C sensors

raspi-configによる設定ができているとします。

#### 各種センサー

使用するセンサーに応じて、pipコマンドでライブラリをインストールします。（下記は例)

```
$ pip install adafruit-circuitpython-bmp280
```

| 製造元 | センサー | インストールするpip package |
|:-|:-|:-|
| [Pimoroni](https://shop.pimoroni.com) | [Enviro pHAT](https://shop.pimoroni.com/products/enviro-phat) | None |
| [Adafruit](https://www.adafruit.com) | [BMP280](https://www.adafruit.com/product/2651) | None |
| [Adafruit](https://www.adafruit.com) | [BMP390](https://www.adafruit.com/product/4816) | None |
| [Sparkfun](https://www.sparkfun.com/) | [BMP581](https://www.sparkfun.com/products/20170) | None |
| [Adafruit](https://www.adafruit.com) | [LPS33HW](https://www.adafruit.com/product/4414) | adafruit-circuitpython-lps35hw |
| [Strawberry Linux](https://strawberry-linux.com) | [LPS33HW](https://strawberry-linux.com/catalog/items?code=12133) | None |
| [Adafruit](https://www.adafruit.com) | [LSM6DS33 + LIS3MDL](https://www.adafruit.com/product/4485) | adafruit-circuitpython-lsm6ds adafruit-circuitpython-lis3mdl |
| [Sparkfun](https://www.sparkfun.com/) | [ISM330DHCX + MMC5983MA ](https://www.sparkfun.com/products/19895) | adafruit-circuitpython-lsm6ds |
| [Adafruit](https://www.adafruit.com) | [LSM9DS1](https://www.adafruit.com/product/4634) | adafruit-circuitpython-lsm9ds1 | 
| [Adafruit](https://www.adafruit.com) | [VCNL4040](https://www.adafruit.com/product/4161) | adafruit-circuitpython-vcnl4040 |
| [ozzmaker](https://ozzmaker.com) | [Berry GPS IMU v4](https://ozzmaker.com/product/berrygps-imu/) | adafruit-circuitpython-lsm6ds adafruit-circuitpython-lis3mdl |
| [GPS PIE](https://gps-pie.com/) | [GPS PIE](https://gps-pie.com/) | adafruit-circuitpython-bno055 |
| [waveshare](https://www.waveshare.com/) | [Environment Sensor HAT](https://www.waveshare.com/environment-sensor-hat.htm) | adafruit-circuitpython-bme280 adafruit-circuitpython-icm20x adafruit-circuitpython-tsl2591 adafruit-circuitpython-ltr390 adafruit-circuitpython-sgp40 |

- Adafruitのセンサーは緑のLEDがあり、複数繋げるとチリツモで消費電力がちょっと上乗せされる。電源を切った際、待機電力で確認可。除去した方が良さげ。

#### Button SHIM

```
$ sudo apt-get install python3-buttonshim
```

#### PiJuice HAT

[オフィシャルのセットアップガイド](https://github.com/PiSupply/PiJuice/tree/master/Software)をご参照ください。本稿では割愛します。

### ANT+ USBドングル

openantは一部修正していますので、筆者のレポジトリのものをインストールして下さい。

```
$ sudo apt-get install libusb-1.0-0 python3-usb
$ pip install git+https://github.com/hishizuka/openant.git
```

setting.confの[ANT]ブロックの冒頭を編集し、有効にします。

```console
[ANT]
status = True
```

## 追加インストールの確認

もう1回手動で起動して確認します。

```
$ QT_QPA_PLATFORM=offscreen python3 pizero_bikecomputer.py
```

GPSもANT+も、必要なものをインストールできた場合、実行ログの出力が変わります。

## サービス化

最後に、電源を入れたら自動で起動するようにサービス化します。

### スクリプトのインストール

まず、install/etc/systemd/system/pizero_bikecomputer.serviceを修正します。

```
ExecStart=/home/pi/pizero_bikecomputer/exec-mip.sh
```

次に、自動起動用、シャットダウン用のプログラムをインストールします。

```
$ sudo cp install/etc/systemd/system/pizero_bikecomputer.service /etc/systemd/system/
$ sudo cp install/usr/local/bin/pizero_bikecomputer_shutdown /usr/local/bin/
$ sudo cp install/etc/systemd/system/pizero_bikecomputer_shutdown.service /etc/systemd/system/
$ sudo systemctl daemon-reload
$ sudo systemctl enable pizero_bikecomputer.service
$ sudo systemctl enable pizero_bikecomputer_shutdown.service
```

### サービス起動

```
$ sudo systemctl start pizero_bikecomputer.service
```

ログは、"/home/pi/pizero_bikecomputer/log/debug.txt"に出力されます。
さらに、systemd経由で起動する際に、ファイル名の末尾に日付が追加してファイルを退避し、ログが蓄積されていきます。

## ボタン操作

実機では、ハードウェアボタンを用いて操作することになるので、ボタンのアサインメントをある程度理解することが必要です。

### Button SHIMによる物理ボタン

ソフトウェアのボタンに類似させています。

<img src="https://user-images.githubusercontent.com/12926652/91799330-cfc50580-ec61-11ea-9045-e1991aed205c.png" width=240 />

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 画面間の移動(逆方向) | なし |
| B | ラップ | リセット |
| C | スクリーンショット | なし |
| D | スタート/ストップ | なし |
| E | 画面間の移動(順方向) | メニュー画面へ |

#### 地図（初期画面）

地図画面では、B,C,Dボタンの割り当てが変わります。Cボタンはボタンのアサインを変更して、地図の移動を行います。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 画面間の移動(逆方向) | なし |
| B | ズームアウト | リセット |
| C | ボタンのアサイン変更 | なし |
| D | ズームイン | なし |
| E | 画面間の移動(順方向) | メニュー画面へ |

ボタンのアサイン変更中

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 左に移動 | なし |
| B | 下に移動 | ズームアウト |
| C | ボタンのアサインを戻す | 地図移動量の切り替え(大/小) |
| D | 上に移動 | ズームイン |
| E | 右に移動 | 経路探索(*) |


(※)現在地から画面中央までの経路探索を実行します。setting.confでGoogle Directions API Keyの設定が別途必要。

#### コースプロファイル画面

B,C,Dボタンの割り当てが変わります。Cボタンはボタンのアサインを変更して、コースプロファイルの前後移動を行います。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 画面間の移動(逆方向) | なし |
| B | ズームアウト | リセット |
| C | ボタンのアサイン変更 | なし |
| D | ズームイン | なし |
| E | 画面間の移動(順方向) | メニュー画面へ |

ボタンのアサイン変更中

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 左に移動 | なし |
| B | ズームアウト | なし |
| C | ボタンのアサインを戻す | なし |
| D | ズームイン | なし |
| E | 右に移動 | なし |

#### メニュー画面

メニュー画面では、ボタンのアサインは以下のようになります。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| A | 戻る | なし |
| B | バックライトON/OFF(※) | なし |
| C | 決定 | なし |
| D | 項目間の移動(逆方向) | なし |
| E | 項目間の移動(順方向) | なし |

(※) MIPカラー反射型液晶のバックライトの接続をしているときに使用可能。

### Edge Remote(ANT+接続)

必要最低限の操作ができるようにアサインしています。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| PAGE | 画面間の移動(逆方向) | 画面間の移動(順方向) |
| CUSTOM | ボタンのアサイン変更 | メニュー画面へ |
| LAP | ラップ | なし |

ボタンのアサイン変更時は以下になります。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| PAGE | ANT+ライトON/OFF | バックライトON/OFF |
| CUSTOM | ボタンのアサインを戻す | なし |
| LAP | スタート/ストップ | なし |

さらに、地図の画面では以下に変わります。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| PAGE | 画面間の移動(逆方向) | 画面間の移動(順方向) |
| CUSTOM | ボタンのアサイン変更 | ズームアウト |
| LAP | ズームイン | なし |

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| PAGE | なし（実装中） | なし（実装中） |
| CUSTOM | ボタンのアサインを戻す | ズームアウト |
| LAP | ズームイン | なし |

メニュー画面では、ボタンのアサインは以下のようになります。

| ボタン | 短押し | 長押し |
|:-|:-|:-|
| PAGE | 項目間の移動(順方向) | なし |
| CUSTOM | 項目間の移動(逆方向) | 戻る |
| LAP | 決定 | なし |

## 設定ファイル

対象ファイルは5つあります。1つ目のsetting.confのみ設定必須で、残りは修正しなくても動作します。

### setting.conf

ユーザー環境に依存した設定を行います。
冒頭のGENERALセクションのdisplayを正しく設定する必要があります。

#### GENERALセクション
- `display`
  - ディスプレイの種類を設定します。
  - modules/config.py に定義があり、解像度、タッチスクリーンの有無(画面にボタンを出すかの判定)を定義しています。
  - `NONE`: デフォルト
  - `PiTFT`: PiTFT2.4 (同解像度のPiTFT2.8でもよい)
  - `MIP`: MIPカラー反射型液晶モジュール 2.7型
  - `MIP_Sharp`: SHARP Memory Display Breakout
  - `Papirus`: PaPiRus ePaper / eInk Screen HAT
  - `DFRobot_RPi_Display`: e-ink Display Module
- `autostop_cutoff`
  - ストップウォッチ機能のスタート後、自動でストップ/スタートさせる速度の閾値を設定します。
  - デフォルト値は `4` (単位はkm/h)です。
- `wheel_circumference`
  - ANT+スピードセンサー使用時に必要なホイール周長を設定します。
  - 画面からも設定可能です。
  - デフォルト値は `2105` (単位はmm)です。700x25cの値です。
- `gross_ave_speed`
  - グロスの平均速度を設定します。
  - ブルベ等、長い距離を決められた制限時間で走る際に使います。定義は走行距離÷総称時間(休憩込み)
  - 画面では、実績のグロス平均と、本項目で設定したグロス平均からの貯金or借金の時間を表示します。
  - デフォルト値は `15` (単位はkm/h)です。
- `lang`
  - 表示項目のラベルの言語設定です。
  - デフォルトは`EN`。
  - modules/gui_config.py の `G_LANG` で他言語を設定可。`JA`のサンプルあり。
- `font_file`
  - 使用したいフォントをフルパスで記載すると、フォントを変更可能。
  - fonts フォルダ以下に配置を想定。
  - 太字のフォントが使いやすいです。[源ノ角ゴシック（Source Han Sans）のSourceHanSansJP-Bold.otf](https://github.com/adobe-fonts/source-han-sans/blob/release/SubsetOTF/JP/SourceHanSansJP-Bold.otf)とか。
- `map`
  - 地図の指定を行います。
  - modules/config.py の `G_MAP_CONFIG` にいくつかプリセットの定義があります。
  - `toner`: モノクロ表示に優れた地図です。[http://maps.stamen.com/toner/](http://maps.stamen.com/toner/)
  - `wikimedia`: フルカラー地図の例として登録した地図です。[https://maps.wikimedia.org/](https://maps.wikimedia.org/)
  - `jpn_kokudo_chiri_in`: 国土地理院の地図です。[https://cyberjapandata.gsi.go.jp](https://cyberjapandata.gsi.go.jp)
  - 後述の map.yaml に、地図URLの追加が可能です。[OSMのページ](https://wiki.openstreetmap.org/wiki/JA:タイル)等でお気に入りの地図を探してください。タイル形式のURL(x, yによってタイル座標を指定、zでズームレベルを指定)を記載し、地図名を本変数で指定します。

#### ANTセクション
- `status = True` でANT+をONにします。
- その後の設定は、画面でペアリングした結果が書き込まれるので編集は不要です。
- センサーの設定が予め存在すると、起動時に各センサーと接続します。
- 異なるセンサーが装着されている複数の車体で運用する時、稼働した設定ファイルを車体ごとにバックアップを取り、起動直前に切り替えるとよいです。

#### SENSOR_IMUセクション
modules/sensor_i2c.py のchange_axisメソッドで、IMU(加速度/地磁気/ジャイロセンサー)の取り付け向きに応じて軸方向の変換を行うための設定です。
設定は共通なので、複数のセンサーに分かれる場合は、向きを全部揃えてください。

基盤にプリントされているX, Y, Zをそれぞれ以下の向きがデフォルトです。

- X: 進行方向、加速度センサーで上向きの回転をしたときが正の値。
- Y: 左方向、加速度センサーで上向きの回転をしたときが正の値。
- Z: 加速度センサーで静止状態が正の値。

軸変換は以下の変数で行います。

- `axis_swap_xy_status`: 軸変換を行う
  - デフォルトは `False` 、適用したい場合は `True` に変更。
- `axis_conversion_status`: 符号反転を行う。
  - デフォルトは `False` 、適用したい場合は `True` に変更。
  - `axis_conversion_coef`: X, Y, Zの順に±1を記入。

[SparkFun 9DoF IMU Breakout - ISM330DHCX, MMC5983MA (Qwiic)](https://www.sparkfun.com/products/19895)のように、同一ボードに加速度・ジャイロセンサーと、地磁気センサーが実装されていながら、地磁気センサーだけZ軸が逆を向くケースに対応するために、以下項目で個別に設定できるようにしています。

- `mag_axis_swap_xy_status`
- `mag_axis_conversion_status`
- `mag_axis_conversion_coef`

`mag_declination`は magnetic-field-calculator パッケージがインストールされ、GPSが有効であれば、ネットワーク接続時に偏角を取得してこの項目に代入し、地磁気センサーによる方角を補正するようにしています。

#### STRAVA_APIセクション
メニュー画面にある "Strava Upload" で、Stravaに.fitファイルをアップロードするために設定を行います。アップロード対象は、直近でリセットして書き出された.fitファイルに限られます。

トークンの取得は「Strava V3 APIの認可方式(OAuth2)を試す」(https://hhhhhskw.hatenablog.com/entry/2018/11/06/014206)を参照してください。
手順の過程で取得する`client_id`, `client_secret`, `code`, `access_token`, `refresh_token`をそれぞれ設定します。一度設定したら、その後は自動で更新され続けます。

#### STRAVA_COOKIEセクション

地図にStrava HeatMapを使いたい場合、`email`と`password`を設定してください。stravacookiesパッケージで必要なクッキーを取得、保持します。

#### RIDEWITHGPS_APIセクション

Ride with GPSによるHeatmapと、アクティビティのアップロードを行いたい場合は、Ride with GPS APIの`token`を設定します。ただし、Apikeyの初期値は`pizero_bikecomputer`です。（変更可)

#### GARMINCONNECT_APIセクション

Garmin Connectにアクティビティをアップロードしたい場合、`email`と`password`を設定してください。

#### GOOGLE_DIRECTION_APIセクション

Google Directions APIで経路検索をしたい場合、API Keyを取得して、こちらに登録してください。(ただし、登録にはクレジットカードが必要です)

2020/11より一部の都道府県で自転車ルートが検索できるようになり、例えば葛西臨海公園から戸田公園のルートを検索した時、国道17号ルートではなく荒川サイクリングロードによるルートを提示することを確認しています。

#### OPENWEATHERMAP_APIセクション

気圧センサーで求める高度の補正を行いたい場合、OpenWeatherMap APIの`token`を設定してください。

#### THINGSBOARD_APIセクション

LiveTrack機能によりデータをリアルタイムでアップロードしたい場合、ThingsBoardデバイスアクセストークンを`token`を設定してください。
取得方法は[レポジトリのドキュメント](https://github.com/hishizuka/pizero_bikecomputer/blob/master/doc/thingsboard_setup.md)を参照ください。

### setting.pickle

ユーザーが意識しなくて良い一時変数を記録します。リセット時にほとんどが消去されます。電源瞬断時に速やかに復旧するための値や、センサーのキャリブレーション結果を記録しています。

### layout.yaml

数値の表示のみで構成される画面の表示、及び各項目の配置に用いる座標を設定します。

- 左上が[0,0]で、下方向のY軸が最初、右方向のX軸を後に記載します。
- セル結合をしたい時は[y, x, y+m, x+n]とし、nとmは何マス埋めるかを記載します。
  - [0, 0, 1, 2]の場合は、左上の[0, 0]に対し、縦1マス、横2マスを結合。y = 0の行は[0, 2]から有効、y = 1の行は普通に[1, 0]から有効。
- 地図やグラフの画面はこの設定の対象ではないです

下記にトップ画面の例を示します。

```
MAIN:
  STATUS: true
  LAYOUT:
    Power: [0, 0, 1, 2]
    HR: [0, 2]
    Speed: [1, 0]
    Cad.: [1, 1]
    Timer: [1, 2]
    Dist.: [2, 0]
    Work: [2, 1]
    Ascent: [2, 2]
```

- `MAIN`: 名称は自由です。プログラムでは使っていませんが、以下に続く `STATUS`, `LAYOUT` を1画面として表示を行います。画面の数は増やすことも減らすこともできます。
- `STATUS`: この画面を表示するか否かを決めます。
  - yamlフォーマットの真偽値である `true` または `false` を設定します。
- `LAYOUT`: 各要素の配置位置を記載します。
  - 各要素は modules/gui_congig.py の `G_ITEM_DEF` に定義されています。自分で変数を作って追加することも可能です。
  - 配置位置は、左上を原点[0, 0]として、右がX軸の正方向、下がY軸の正方向として、[Y, X]の形で設定します。実装は、QGridLayoutの座標系になります。
  - 複数のマスを結合したい場合、第3引数に下端のY座標+1、第4引数に右端のX座標+1を記載します。`Power: [0, 0, 1, 2]`の例だと、0行目0番目のマスと、右隣の0行目1番目のマスを結合します。

### map.yaml

本ファイルに地図名、タイルURL、著作権表示を登録します。
以下にStrava HeatMapの一例を示します。

```
strava_heatmap_hot:
  url: https://heatmap-external-b.strava.com/tiles-auth/ride/hot/{z}/{x}/{y}.png?px=256
  attribution: strava
```

- 1行目：地図名
  - setting.conf のGENERAL -> mapに設定する文字列になります。
- 2行目：タイルURL
  - ご自身で調べたタイルURLを記載してください。タイル座標X、Y、ズームZは `{x}`, `{y}`, `{z}` で記載ください。
- 3行目：著作権表示
  - 地図の使用に必要な著作権表示を設定します。


### config.py

ユーザーがあまり意識する必要のない設定や、上記の設定ファイルの変数が定義をしています。


## 走り出すまで

大変お疲れ様でした。これで外で走れるようになります。

### コースファイルの配置と地図の事前ダウンロード

使用したい場合、TCX形式のcourse.tcxファイルをcourseフォルダ下に配置して下さい。今はファイル名を固定しています。起動時にファイルがあれば読み込みます。

地図の事前ダウンロードは、以下で実施します。(手抜きです)
サービス起動ではなく、手動で--demoオプションをつけて起動すると、デモモードで起動します。

```console
$ python3 pizero_bikecomputer.py --demo
```

この時、地図画面にするとコースに沿って現在位置が移動していき、必要な範囲の地図をダウンロードします。起動したらすかさず左ボタンを押して地図画面に移動し、しばらく放置してください。


### ロードバイクへの装着

ハンドルバーにケースを装着し、トップチューブバッグ等に入れたバッテリーと接続します。特にスイッチはないので、接続した瞬間に起動します。念のため。
![bike-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/5157c02c-0fe2-c6bb-ab7b-d1e1965f10c2.png)

### 起動後

GPS補足に数分かかるので、なるべく上空が開けている箇所で待機しましょう。
その間、必要に応じてANT+ペアリング、ホイール長設定、高度更正を行います。

スタートボタンを押したら記録開始、適宜ラップボタンを押して区間を計測、走り終えたらまたスタートボタンを押して記録終了、その後ラップボタン長押しでストップウォッチのリセットと記録ファイルの書き出しを行います。logフォルダにスタート時の日付で.fitファイル、.csvファイル、.dbファイルが出力されます。

記録したファイルはSFTP経由で取り出すか、必要な設定がされていればメニューからStrava Uploadでアップロードできます。


# おわりに

![E2s_dMaVkAEjX6p.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/b7ddfbb5-d63d-81d9-cfb9-1ea49ae7969f.jpeg)

いかがでしたでしょうか？　

感想をコメント欄や[Twitter](https://twitter.com/pi0bikecomputer)でお聞かせいただけると幸いです。特に挑戦してみた方、参考にさせていただきたいのでぜひお願いします。

市販品にないインパクトのある機能はあまり実装できていないゆえ、まだスタート地点に立てているか怪しいこの趣味プロジェクトですが、今後も日進月歩で取り組む予定ですので、興味のある方はぜひご参加ください。

以下は、今後アップデートしないPiTFT版の記載になりますので、本記事は以上となります。

***

# Raspberry Pi Zero + PiTFT版 (アーカイブ)

PiTFTの差分のみ抜粋します。
主な手順は上記の流れを参照してください。

## 必要なもの

### ハードウェア

- タッチスクリーン付きTFT液晶モジュール
  - PiTFT 2.4インチを推奨 (5,000円弱)
  - こちらも、セットアップは「[Raspberry Pi Zero(W, WH)でPiTFTを使う](https://qiita.com/hishi/items/bdd630666277e4f8162a)」等でどうぞ
  - X Windowが表示できるようになっていることを前提とします

## 組み立て

主な材料はこんな感じです。
![assembly-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/7d798ce9-8b76-18b1-09c7-85f068903f89.png)

- 左上段：PiTFT 2.4インチ
- 左中段：Raspberry Pi Zero WH
- 左下段：Enviro pHAT (適当なI2Cセンサで代用可)
- 右中段：GPSモジュール (上記で紹介したものではありません。念のため)
- 右下段：ANT+ USBドングルとmicro USB変換コネクタ

これらを組み立てていきます。

難しいなと思ったら、一つずつ確認と、順を追って動作確認をすることをお勧めします。まずPiTFTが動くことを確認し、GPSモジュール、Enviro pHAT、ANT+ USBドングルといった順です。

また、最初のうちは、PiTFT内にあるGPIOピンから取り外し容易なジャンジャンパワイヤを用いて、GPSモジュールとEnviro pHATを接続した方が良いです。
筆者のようにできるだけコンパクトにしたい場合は、余計なピンを可能な限り取り外して複雑怪奇な空中配線を行いますが、この手の魔改造は時間も労力もかかりますのでご注意を。

![assembly-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/f632a516-466c-3ee7-c217-aed050ece23f.png)
Enviro pHATとANT+ USBドングルを取り付けます。Enviro pHATはプリントされている面にセンサーがあるので、外側に向けた方がいいと思います。(内側だとCPUの熱をより拾います)　また、ANT+ USBドングルは内側のmicro USB端子に挿して下さい。

![assembly-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/427c55a8-9927-036f-5f4f-2ad5eb544720.png)
Enviro pHATは必要な箇所を直接配線しています。
世に出回っている有名なpHATは、[Raspberry Pi Pinout](https://pinout.xyz/pinout/enviro_phat)のサイトでどのピンを使用しているか分かります。

![assembly-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/82984a06-6b9d-8afb-3a58-4c5566dd8f3a.png)
PiTFT 2.4インチを接続します。

![assembly.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/d44e58a8-52af-7a7b-1ca5-3c4f5be92493.png)
PiTFT 2.4インチは横からGPIOピンが出ているので、ジャンパワイヤで接続できます。

作りきると下記のようになります。

![pitft-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/2f63cc6d-8e14-0320-3227-6e05fa8851cd.png)
各部品はネジで固定しています。PiTFTのボタンは上から押すタイプなので、固定していないとたまに押しすぎて本体との接続が切れてしまい、とても悲しい気持ちになります。
また、ANT+ USBドングルと電源ケーブルは振動対策のためテープで固定しています。この方法にたどり着いてから、今まで問題は出ていません。コネクタとボードの間に隙間ができる場合は、適当な緩衝材を挟んだ上で、テープ固定して下さい。また、モバイルバッテリーのUSBコネクタも振動で瞬断しうるので、対策した方が良いでしょう。

手持ちのプロトタイプは可能な限り薄くしたいので、PiTFT内で外向きに出ているGPIOピンは全て取り除いています。(上記の写真の中央右下、ANT+ドングルとGPSの間に縦2列の跡があります)

![pitft-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/5aa2428a-9252-4941-5599-a5a8038be925.png)
また、PiTFT側にピンソケットを使わず、Raspberry Pi Zero WHと直接はんだ付けしています。

## 初回起動まで

PiTFT 2.4用のバックライトの制御プログラム、シャットダウン用のプログラムをインストールします。

```console
(PiTFT 2.4用のバックライトの制御プログラム)
$ sudo cp install/usr/local/bin/disable-pitft /usr/local/bin/
$ sudo chmod 755 /usr/local/bin/disable-pitft
$ sudo cp install/usr/local/bin/enable-pitft /usr/local/bin/
$ sudo chmod 755 /usr/local/bin/enable-pitft
$ sudo cp install/etc/systemd/system/disable-pitft.service /etc/systemd/system/

(シャットダウン用のプログラム)
$ sudo cp install/usr/local/bin/pizero_bikecomputer_shutdown /usr/local/bin/
$ sudo chmod 755 /usr/local/bin/pizero_bikecomputer_shutdown
$ sudo cp install/etc/systemd/system/pizero_bikecomputer_shutdown.service /etc/systemd/system/

(サービスへの反映)
$ sudo systemctl daemon-reload
$ sudo systemctl enable disable-pitft.service
```

この時点で起動できるか、確認します。最初のコマンドはPiTFT上で起動するおまじないです。

```console
$ export DISPLAY=:0.0
$ python3 pizero_bikecomputer.py -f
```

![test-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/0304effb-6a05-4064-a29d-b9bb7cf8593a.png)

## 起動周りの設定

### 自動起動 (X Window)

以下の3行で終わります。2020/1現在のBusterが前提です。バージョン等が変わるとできなくなるかもしれません。

```console
$ mkdir -p ~/.config/lxsession/LXDE-pi
$ cp /etc/xdg/lxsession/LXDE-pi/autostart ~/.config/lxsession/LXDE-pi/
$ echo "@/home/pi/pizero_bikecomputer/exec.sh" >> ~/.config/lxsession/LXDE-pi/autostart
```

参考：Raspberry Pi公式フォーラム
https://www.raspberrypi.org/forums/viewtopic.php?t=249620

Xを介さず直接行った方がスマートなのですが、aptコマンドでインストールされるPyQt5でXを介さず直接起動する場合、どうもPiTFTのタッチパネルが効かないようなので、tslibを有効にしたQt5とPyQt5をビルドする必要があります。タッチスクリーンをどうしても使いたい場合は、コンパイル用にRasberry Pi4の4GB以上を調達しましょう。このあたりは続編で記載します。

### メニューにボタンを追加

(結構長いので不要なら読み飛ばして下さい)

PiTFTの小さなデスクトップ画面では到底設定変更の操作ができないので、VNC経由で画面の設定を変更します。

```console
$ sudo apt install tightvncserver
$ tightvncserver :1

(tightvncserverを終了する場合)
$ $ tightvncserver -kill :1
```

ログイン用のパスワードが設定できたら、VNCでログインします。
WindowsはVNCビューワー([RealVNC](https://www.realvnc.com/en/)等)をインストールして下さい。サーバー名はSSH等で接続するものと同じ、ポートは5901版です。

macOSはデフォルトで入っていますので、Finderの移動メニューの最下部にある「サーバへ接続」(command + k)を押し、vnc://raspberrypi.local:5901でログインして下さい。
![vnc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/9446e413-f294-6dec-5d3f-98257217eb84.png)

![vnc-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/5d259ac8-8448-273b-f3d6-3c7f2ba70624.png)
普通の解像度で使う分には害がないですが、320x240で使うとなると全て余計ですので、消していきます。

![vnc-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/1b4a1072-0e4f-08f3-a371-9b36f4992a65.png)
左から2〜4番目のアプリケーションランチャーは不要なので、右クリックでRemove(上から3段目)します。

![vnc-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/28a10531-9958-e6ee-945d-af1a8f7e0481.png)
最上部のバー上で右クリックし、Panel Settingsに入ります。

![vnc-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/d5a23eea-710e-66a3-5882-cd26ace00f9b.png)
Pannel Appletsで右端の不要なトレイアイコン的なものも不要なものは消してしまいます。

![menu-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/8edfb1d6-5b3d-a560-5d84-f815f425ce87.png)
次、メニューが多すぎるので、これも消します。PreferencesのMain Menu Editorを起動します。

![menu-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/808db736-8615-324f-2c25-27333a0d5cac.png)
左上のApplicationsが選択された状態で、中央の各メニューのチェックボックスを、Preferences以外外します。
次に、右端上から2番目のボタンNew Itemで項目を作ります。

![menu-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/025fcc7c-0718-3fbf-57ec-8a38509b4b73.png)
プログラムの名前を打ち込み、Command欄の横のBrowseボタンを押します。

![menu-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/07902a9e-b31b-e8be-e6b8-b034214ef96d.png)
プログラムを配置したフォルダ(/home/pi/pizero_bikecomputer/)にある、exec.shを選択します。

![menu-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/e318acf1-3c89-0537-956c-9e64738b8f81.png)
これで入力完成です。OKを押して戻ります。

![menu-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/743ea1f8-1c81-f801-0285-c27a4715c942.png)
新しい項目はPreferencesの下に配置されるので、追加した項目を選択した状態で、画面右端のMove Upボタンを押し、少なくともPreferencesより上に配置します。

![menu-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/8e461b03-0751-b4f0-d012-df071c3155cb.png)
これでめでたくメニュー数が減り、一番最初に本プログラムが出てくるようになりました。

![menu-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100741/c466c6f0-ede8-5de2-2061-fbbbcccb93fc.png)
再起動して、実機の画面から確認します。