はじめに
RaspberryもGPIO(というかハードウェア全般)も初心者がDockerのコンテナでタクトスイッチのオンオフをConsoleに出力するだけのお話
環境
・Raspberry
・.NetCore 3.1(開発側)
・WiringPi
・実行はDocker(インストールしておいてください)
ソースはこちら
ハマりどころ
その1
現象
.NetCoreのruntimeコンテナでGPIOのアプリを起動したいので、マイクロソフトのイメージmcr.microsoft.com/dotnet/core/runtime:3.1-bionic-arm32v7を使ったところapt-getでWiringPiがインストールできませんでした(知っている方教えてください)
対処法
DockerfileにてラインタイムイメージにコンパイラをインストールしWiringPiをビルドすることで解決
その2
現象
RaspberryでGPIOを扱う場合に登場する/dev/gpioがコンテナ上ではアクセスができなくて困った。
対処法
Docerのコマンドに--deviceといパラメータがこれを使えばいいことが判明
だけど、今度はパーミッションエラーが発生
--privilegedコマンドを使えば回避できることが判明(特権モードで実行なので慎重に)
手順
開発側
- TackInvokerというフォルダを作成
- TackInvokerフォルダに移動
- dotnet new console
- Program.csを下記のファイルで置き換える
- TackInvokerフォルダの上に下記のDockerfileを配置
- docker build -t {自身のDockerHubID}/Tackinvoker:latest .
- docker push {自身のDockerHubID}/Tackinvoker:latest
Raspberry側
- docker run -it --rm --device /dev/gpiomem --privileged {自身のDockerHubID}/Tackinvoker:latest
素材達
Program.cs
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace TackInvoker
{
class Program
{
public const int INPUT = 0;
public const int OUTPUT = 1;
public const int INT_EDGE_FALLING = 1;
public const int INT_EDGE_RISING = 2;
public const int Tack_PIN = 17;
[DllImport("wiringPi")]
extern static int wiringPiSetupGpio();
[DllImport("wiringPi")]
extern static void pinMode(int pin, int mode);
[DllImport("wiringPi")]
extern static void digitalWrite(int pin, int mode);
[DllImport("wiringPi")]
extern static int wiringPiISR(int pin, int edgeType, CallbackFunc func);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackFunc();
static void Main(string[] args)
{
int ret = 0;
// wiringPiのセットアップ
wiringPiSetupGpio();
// GPIO をINPUTに設定する.
pinMode(Tack_PIN, INPUT);
CallbackFunc callBackFunc = delegate () {
Console.WriteLine("CallbackFunc is called !");
};
// GPIO がONになったらコールバック関数を呼ぶ.
ret = wiringPiISR(Tack_PIN, INT_EDGE_RISING, callBackFunc);
// 無限に待機する.
Thread.Sleep(Int32.MaxValue);
}
}
}
Dockerfile
# ビルドイメージ
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
# copy csproj and restore as distinct layers
COPY *.sln .
COPY TackInvoker/*.csproj ./ TackInvoker/
# copy everything else and build app
COPY TackInvoker ./TackInvoker/
RUN dotnet restore TackInvoker
WORKDIR /app/TackInvoker
RUN dotnet publish -c Release -o out
# ランタイムイメージ
FROM mcr.microsoft.com/dotnet/core/runtime:3.1-bionic-arm32v7
# WiringPiをインストールする
RUN apt-get update
RUN apt-get install -y libi2c-dev
RUN apt-get install -y git-core
RUN apt-get install -y sudo
RUN apt-get install -y make
RUN apt-get install -y gcc
RUN git clone https://github.com/WiringPi/WiringPi.git
WORKDIR /WiringPi
RUN ./build
WORKDIR /app
COPY --from=build /app/TackInvoker/out ./
ENTRYPOINT ["dotnet", "TackInvoker.dll"]