x11VNCを用いた、JetsonNano(Ubuntu18.04)のリモートデスクトップ環境の構築

## はじめに
この記事ではJetsonNanoをリモートデスクトップ環境で使えるような手順を記録します。
JetsonNanoを移動ロボットに搭載したのですがいちいち起動するたびにモニター等を繋ぐのがめんどくさくなったのでリモートで操作できるようにしました。
環境構築に関しては、以下のサイトを参照させていただきました。
https://qiita.com/chyonevvi/items/3d907464d11b2f056ef6#x11vnc%E3%81%AB%E3%81%97%E3%81%9F
### 構成要素
操作される側（ホスト）：JetsonNano developer kit (Ubuntu18.04)
操作する側（クライアント）：ノートPC (Ubuntu20.04)
VNCクライアントソフト：RealVNC

## そもそもx11VNCとは何ぞ
x11vncとはモートデスクトップソフトウェアの一つで、具体的には、LinuxやUNIXベースのシステム上で動作する、VNC（Virtual Network Computing）サーバーです。
通常のVNCサーバーは仮想デスクトップを作成し、その仮想デスクトップをリモートで提供しますが、x11vncは物理的に接続されている実際のディスプレイの内容を共有します。つまり、現在使用している画面そのものを他のコンピュータから操作できるようにします。
他にもリモートデスクトップソフトはありますが、設定が比較的簡単な点とJetsonNanoの起動時からリモートデスクトップに接続できるという点から今回はx11vncを使用します。

### 注意点
x11vncはディスプレイマネージャーが「lightdm」でないと作動しません。デフォルトではおそらく「gdm3（GNOME）」というディスプレイマネージャーに設定されていると思いますので変更する必要があります。「lightdm」は軽量でカスタム性も高い優れたディスプレイマネージャーですが、こだわりがあって「gdm3じゃないと嫌だ！！」という方にはこの記事は役に立たないと思いますので、他のリモートデスクトップソフトを検討してください。
ディスプレイマネージャーを変えたからといってデータが吹っ飛ぶということはありませんし、裏側で動くマネージャーが変わるだけなので使う分には全く違いはありません。
## x11vncの設定
### ディスプレイマネージャーの設定
最初にディスプレイマネージャーを「lightdm」に変更します。
「lightdm」をインストールした後に、変更を反映させるために再起動します。
```
sudo apt-get install lightdm
sudo dpkg-reconfigure lightdm
sudo reboot
```
インストール中に朱色の画面が出てきて「gdm3」か「lightdm」のどちらを使うかという選択できます。この画面で「lightdm」を選択してください。
ディスプレイマネージャーが変更させるとJetsonNanoの画面が変わっていると思います。
ログイン画面でパスワードを打つことになるかと思いますが、その画面のユーザーネームの右側に白い歯車のようなアイコンがあります。（下図参照）
![タイトルなし.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3511665/2b2af306-07d0-c4c0-65db-f1b87bfcea71.png)
このアイコンをクリックするとデスクトップマネージャーを選択できます。「lightdm」を使う際には「Unity」が一番おすすめですが、好みで選択してください。
機種によってはログイン画面がこの画面じゃないことがあります。その時は右上のメニューバーにディスプレイマネージャーを選択できるタブがあるのでそれを使いましょう。
### リモート接続する設定
まずはx11vncをjetsonnanoにインストールします。
```
sudo apt install x11vnc
```
次に以下のコマンドを実行して、リモート接続する際のパスワードを設定します。
```
sudo x11vnc -storepasswd /etc/x11vnc.passwd
```
実行して以下の順に設定していきましょう。
```
Enter VNC password:  ← 設定したいパスワード
Verify password:     ← もう一度入力。パスワード確認用
Write password to /etc/x11vnc.passwd?  [y]/n   ← yを押してEnter
Password written to: /etc/x11vnc.passwd
```
最後に、ユーザの読み取り権限を与えます。
```
sudo chmod 644 /etc/x11vnc.passwd
```
これで、リモートデスクトップを使用する環境構築は終わりです。

### 実際につないでみよう
実際につないでみましょう。
```
sudo x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.passwd -rfbport 5900 -forever -loop -xkb -noxdamage -repeat -shared
```
このコマンドでVNCサーバーを起動します。
ここからクライアント側｛操作する側）のセットアップに移ります。
JetsonNanoと同じWi-Fi環境に接続した後に、クライアントソフトに**JetsonNanoのIPアドレス**と**先ほど設定したパスワード**を打ち込んで接続しましょう。
JetsonNanoの画面が表示されていれば成功です！

## 起動時に自動的にVNCサーバーが立ち上がるように設定する
ここまででリモートデスクトップ環境の初期設定は完了です。
ただ、実際に使うにあたってはJetsonNanoを起動したときに自動的にVNCサーバーが立ち上がるようにしないと、結局モニター等を接続して先程のコマンドを実行しなければならないため、本末転倒です。
ここから、さらに設定を加えていきましょう。
自動でサーバを起動させるためのファイル「x11vnc.service」を作成します。
```
sudo vi /etc/systemd/system/x11vnc.service
```
viの部分はnanoでも構いません。好きなテキストエディタを選択してください。
開いたエディタに以下のコードをそのままコピペしてください。
```
[Unit]
Description=x11vnc (Remote access)
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.passwd -rfbport 5900 -forever -loop -xkb -noxdamage -repeat -shared
ExecStop=/bin/kill -TERM $MAINPID
ExecReload=/bin/kill -HUP $MAINPID
KillMode=control-group
Restart=on-failure

[Install]
WantedBy=graphical.target
```
作成した.serviceファイルをsystemdに登録して起動させます。
systemdはLinuxを構成するソフトウェア群のことです。
```
sudo systemctl daemon-reload
sudo systemctl enable x11vnc
sudo systemctl start x11vnc
```
これで起動時にJetsonNanoを何もいじらなくてもリモート接続できるようになりました！

## HDMIを接続していない状態だとなぜか表示されない！？
x11vncは接続されている物理的ディスプレイの画面を表示しているので、JetsonNanoになにも画面が接続されていないときには接続しても何も画面が表示されません。
ディスプレイが何も接続されていない時用に仮想ディスプレイを構成する設定も加えます。
仮想ディスプレイを有効にするために、「dummy」ディスプレイドライバを使用します。
次にコマンドでXorg設定ファイルを作成します。
```
sudo nano /etc/X11/xorg.conf
```
作成したxorg.confファイルに以下のコードをコピーします。
```
Section "Device"
    Identifier "Configured Video Device"
    Driver "dummy"
EndSection

Section "Monitor"
    Identifier "Configured Monitor"
    HorizSync 31.5-48.5
    VertRefresh 50-70
    Modeline "1920x1080" 148.5 1920 2008 2052 2200 1080 1084 1089 1125 -hsync +vsync
EndSection

Section "Screen"
    Identifier "Default Screen"
    Monitor "Configured Monitor"
    Device "Configured Video Device"
    DefaultDepth 24
    SubSection "Display"
        Depth 24
        Modes "1920x1080"
    EndSubSection
EndSection
```
次のコマンドでこの設定を反映させます。
```
sudo systemctl restart lightdm
```
この設定で仮想ディスプレイを構成できました。
これでHDMIを接続していない状態でも画面を表示させることが出来るようになりました。
ただ、お金に余裕がある方は「ダミーHDMI」を購入してそれを使うのが良いかと思います。
上記のソフトウェアで解決する方法では原因不明のバグが起きることがありました。（軽微と言えば軽微だが）

## 終わりに
これでセットアップは終わりです。
素敵なUbuntuライフを！！！