LED通信事業プロジェクト エンジニアブログ

F#でラズパイを動かす(3)

F#で「Hello world!」

記事更新日 2022年4月19日


はじめに

前回は、F#でラズパイを動かす準備をしました。今回は、Visual Studio2022(VS)を使って、実際にプログラミングコードを書いていきたいと思います。最初は、プログラミング学習のお約束である「Hello world」です。

ソリューションとプロジェクトを作る

F#に限らずC#でもVB.NETでも、VSで作られるコードは、ソリューションとプロジェクトと二つの「入れ物」で構成されます。この関係を説明するのは少し難しいので、ソリューションとプロジェクトの関係を理解するのはもう少し後にして、先ずはプロジェクトの作成から行いましょう。

fig.1
図1: 最初のメニュー画面

VSを開くと、図1のようなメニュー画面が現れますので、一番下の新しいプロジェクトの作成(赤矢印)を選んでください。すると図2のような「新しいプロジェクトの作成」画面が開かれます。ここで「プロジェクトのテンプレート」を選ぶことで、目的に合ったプロジェクトが作成されます。

今回作りたいのは、F#のRaspberry Pi(ラズパイ)対応のコンソールアプリです。それには、Linux対応のF#コンソールアプリのテンプレートを使えばいいのですが、この画面にはC#などのテンプレートも含まれるので、テンプレートの数は相当数あります。このままでは目的のテンプレートを探すのが結構難しいですので、フィルターをかけて表示されるテンプレートを絞ります。①の言語選択コンボボックスにはF#を、②のプラットフォーム選択コンボボックスにはLinuxを選んでください。すると、いくつかのテンプレートだけが候補として残りますので、図2の通りF#のコンソールアプリを選んでください。

fig.2
図2: 新しいプロジェクトの作成画面

次は、プロジェクトやソリューションに名前を付ける画面です。プロジェクトの名前も、ソリューションの名前も何でもいいですが、今回はプロジェクト名をHelloworldとします。プロジェクト名を付けると、自動的に同じ名前がソリューション名欄に入力されます。プロジェクトとソリューションは同じ名前で構いませんが、ソリューション名を変更し別の名前にすることもできます。今回は後々区別しやすいようにソリューションに別の名前(FsharpFirstRasPi)を付けます。真ん中の場所の欄は、プロジェクト(ソリューション)の保存場所です。個人の開発レベルではドライブ速度はさほど重要ではないので、SSDでもHDDでも、好きな場所を指定して問題ありません。ただし、One DriveやGoogle Driveなどクラウドドライブとの自動同期を設定しているフォルダの指定は、できれば避けた方が良いと思います。VSがおかしな挙動(不要なメッセージを連発)をすることがあるからです。

fig.3
図3: 新しいプロジェクトの構成画面

最後の追加情報は対応する.NETのバージョンを決定するものです。ここでは.NET 6.0※1を選んでください。これでプロジェクトとソリューションの作成は完了。”次へ”を押せばいよいよVSの起動となります。

F#のコードを書く

fig.4
図4: Visual Studio(F#)の初期画面

画面の説明

VSが起動すると、図4の様な画面が表示されるはずです。真ん中に大きく表示されているのは、コードを書くウインドウ。最初はProgram.fsというファイルが開いています。右には、ソリューション エクスプローラーが開いています。今回使うのはこの2つのウインドウなので他色々あっても無視してください。

「ソリューションエクスプローラー」は、編集したいファイルを選択する、いわゆるファイルエクスプローラーです。ここからファイルを開くと、現在Program.fsが開かれているウインドウに、別のタブとして開かれます。ソリューションエクスプローラーの中身を見ると、ソリューションとプロジェクトの関係が分かります。ソリューションという中にグループの中に、プロジェクトというグループが含まれるという構成になります。テンプレートを開いただけの最初状況では、プロジェクトには、依存関係Program.fsの2つが含まれています。

依存関係には開発したアプリを動作させるのに必要なライブラリが入れられています。手動でライブラリを出し入れすることもできますが、通常はツールを使って管理します。今は触る必要はありませんが、次回"Lチカ(LEDの点滅)"をするときに出番となりますので、その時に改めて説明いたします。

Program.fsは、これから書くコードそのものです。このファイルは一般にソースファイルと呼呼ばれます。F#におけるプログラミングは、ソースファイルにコード(ソースコード)を記載していくことでアプリを作っていくことを言います。尚、".fs"という拡張子は、F#のコードを表すものです。

コードを書く

この連載は、ほんの少しでも「プログラミングというものをやったことがある」という人をターゲットにしています。(VBAやJavaScriptを少し書いたことがある、程度を想定)ですので、プログラミングの最低限のルール的なものは説明いたしませんので、あらかじめご了承ください。

まず、最初に書くべきコードはコマンドライン、つまり画面にHello world!という文字を表示させるものです。なんでHello world!なのか、詳しくはこちらをご覧頂ければと思いますが、これは一種のお約束で、どんな言語の学習もここからスタートします。

まずはProfram.fsを見ていきます。ここにコードを書いていくことによって、アプリを作ることができます。このファイルの中には、テンプレとして次のようなコードが最初から書かれているはずです。

// For more information see https://aka.ms/fsharp-console-apps printfn "Hello from F#"

1行目、//で始まる文は、緑で書かれていると思います。これはコメント文です。F#では、行の最初でも、途中でも//の後は行が終わるまですべてコメントと見なされます。

2行目のprintfnは、画面に文字を表示する関数です。F#では、”(ダブルクォーテーション)で囲むと「文字列」として認識します。つまり、この例だとHello from F#という文字列を画面に表示することになります。ちなみに、F#はコード中の大文字と小文字は区別します。例えば、printfnPrintfnは別のものと見なされます。

さて、それらを踏まえて、コードを編集しましょう。次のようにprintfnで出力する文字列を"Hello world!"に変更します。ついでに、コメントも変えておきましょう。

// Hello worldを出力します。 printfn "Hello world!"

記入している途中で、図4のようなprintfnの説明(ただし英語※2)が表示されたと思います。このリアルタイムの入力支援がVSの強みです。さらに、間違ってprintfnの代わりにprinthnと書いてしまったとしても、即座にVSよりエラーのメッセージが出で間違っていることに分かります。また、入力時に"pr"と入力しただけで、prが含まれる様々な関数や変数の候補が並べられます。この様な入力支援に関しては、今後改めて説明していきます。

fig.5
図5: 関数入力のサポート

Windows上で試行する

コードが書けたら実行です。このブログの目的はラズパイ上での動作ですが、まずは正しく動くかWindows上で試行して試してみることができます※3。この辺は、.NETがWindowsにもラズパイ(Linux)にも対応している強みです。

fig.5
図6: アプリの実行

画面上部メニューバーにある、実行ボタンを押してみて下さい。図6の赤い四角で囲ってある部分です。これを押すと、書いたコードがWindowsで実行されます。コードが正しく書けていれば、実行して暫く経った後、下の様なメッセージが表示されると思います。(下記の[ユーザーが指定した保存フォルダ]という部分は、皆様が指定したプロジェクト(ソリューション)の保存場所のフォルダが表示されます。)

Hello world! C:\[ユーザーが指定した保存フォルダ]\FsharpFirstRasPi\Helloworld\bin\Debug\net6.0\Helloworld.exe (プロセス 12412) は、コード 0 で終了しました。 デバッグが停止したときに自動的にコンソールを閉じるには、[ツール] -> [オプション] -> [デバッグ] -> [デバッグの停止時に自動的にコンソールを閉じる] を有効にします。 このウィンドウを閉じるには、任意のキーを押してください...

この表示が出れば成功です。コード、そしてVSの設定は正しいです。Windows上での実行に成功した、つまりバグがないことが確認できた(1行しかないので当たり前ですが・・・)ため、次は同じコードのラズパイでの実行に挑戦します。

ラズパイでの実行

さて、先ほどWindows上での試行の際、実行ボタンを押してから実行までの間に結構時間がかかったと思います。この間、VSはビルドといわれる動作をしていました。ビルドは、ソースコードから実行可能なファイルを作成することを言います。上の実行結果を改めて見て下さい。"Hello world!"の出力に続いて、C:\[ユーザーが指定した保存フォルダ]\FsharpFirstRasPi\Helloworld\bin\Debug\net6.0\Helloworld.exe (プロセス 12412) は、コード 0 で終了しました。というファイル名が付いたメッセージが出力されているはずです。これは「VSによって作成された"Helloworld.exe"というファイルを実行し、終了しました」ということを意味します。つまり、この実行ボタンを押した後、VSは"Helloworld.exe"というWindows用の実行ファイルを作成し、それを実行するという動作をしていたのです。そのことは"Helloworld.exe"のあるフォルダの中身を見ることで確認できます。フォルダの中を見ると実は"Helloworld.exe"以外にも沢山のファイルやフォルダを作成しているのが分かります(図7)。

fig.7
図7: 実行時に作成されたフォルダとファイル

一見同じようなファイルが沢山あるわけですが、これらには意味があります。実はVSはビルドの際、Windowsで動くようにするだけで無く、ラズパイでも動くようにファイルを作っています。VSは互換性実現のために、大きな"exe"ファイルを一つ作るのではなく、ファイルを小分けにしています。そのため、Windowsで動いていたこれらのファイル・フォルダをそのままラズパイにコピーするだけで、あら不思議、ラズパイでも動いてしまうのです。

ファイルのコピー

というわけで、作ったビルドファイルをラズパイで実行するためには、先ずはファイルのコピーをしなければ行けません。第一回で説明したとおり、ラズパイへのファイルコピーは"WinSCP"というアプリを使います。まず、WinSCPでラズパイにアクセスし、Helloworldのアプリを置くためのフォルダを作りましょう。今回は、pi/Documents/配下にsourceというフォルダを作り、その中にビルドファイルを置くためのHelloworldというフォルダを作成します。そこにビルドファイル、つまりWindows上のHelloworld.exeがあるフォルダの中身(図7)を全てコピーし、上記ラズパイのフォルダに貼り付けます。WinSCPへのドラッグ&ドロップでもできます。コピーできれば、図8の様になるはずです。

fig.8
図8: コピー後のWinSCP

ラズパイでの実行

ファイルのコピーができたら、次に実行です。最初に、コマンド入力画面(コマンドプロンプト、Windows PowerShell、Windowsターミナル等)を開いて、SSHを使ってラズパイにログインします(これも第一回で説明しています)。

ssh pi@[ラズパイのIPアドレス]

一度でもログインしたことがあれば、パスワード(piユーザーのパスワード)を聞いてくるだけです。 ログイン後は、cdコマンドを使ってカレントディレクトリーをHelloworldフォルダに移動させます。

cd /home/pi/Documents/source/Helloworld

そして、ここで実行です。Windowsの実行ファイルは"exe"ファイルでしたが、ラズパイの実行ファイルは"dll"ファイルです。dllファイルはいくつかありますが、通常実行ファイルは「プロジェクト名」がつけられますので、今回の場合はHelloworld.dllファイルが実行ファイルとなります。これを実行するために.NETと合わせて、コマンドを次のように打って下さい。

dotnet Helloworld.dll

.NETが正しくインストールされていれば、Hello world!のメッセージが表示されたはずです。(図9)

fig.9
図9: ラズパイでの実行結果

これでラズパイでのHello worldは成功です!!

とは言え、なんかWindowsしか操作していないのにラズパイで実行したと言っても実感が湧かないという方もいるかとおもいます。そういう方は是非ラズパイにキーボードマウスを繋ぎ、Helloworld.dllをラズパイのOS上で実行してみて下さい。当たり前ですが、全く同じ結果が返ってくるはずです。

従来、そうやって実機を操作して実行していたようなケースでも、WinSCPとSSHがあれば、ラズパイ本体は電源を入れるだけで全く触ることなくすべてWindows上だけで完結するというのが、この開発方法のメリットでしょう。

まとめ

次回以降、(恐らく二回に渡って)ラズパイの最大の特長である「GPIO」という物理ピンを使ってLEDを発行させる「Lチカ」と呼ばれるアプリをF#を使って作成します。「C#でLチカ」はWebでいくらでも見つかりますが、それをF#でやるとどうなるのか? 今回はあまりできなかったF#の文法を説明をやりつつ、ラズパイ操作の基本であるLチカを実現したいと思います。


※1; .NET 6.0には”長期的なサポート”(通称LTS)の表示がされています。.NETやOSなどバグフィックスやセキュリティ対策が重要なソフトウエアは、サポート期間が決められています。特にセキュリティのアップデートが打ち切られているバージョンは実質使用できなくなるため、長い期間使う予定のアプリケーションの開発では、対象.NETがLTSであることは重要です。.NET 6.0はMicrosoftが長期間サポートすると宣言しているバージョンです。尚、.NETの過去を見ると、サポートの短いバージョンは1~2年、LTSは3年程度でサポート終了となっています。

※2; C#やVB.NETだと日本語のサポート(説明)が入ります。ここが、マイナー言語の辛いところです。

※3; ただし、コードがラズパイにしか無い機能・ハードウエアを使っていない場合だけです。例えば、ラズパイのGPIOはWindowsにはありませんので、GPIOを利用したアプリケーションはWindowsで試行できません。