LoginSignup
0
0

More than 3 years have passed since last update.

【EV3 x C#】lejos-server/clientを使ってC#でEV3を制御する(Android編)

Last updated at Posted at 2020-12-31

はじめに

Visual Studio/C#でWindows、Macとくれば「次はAndroidからEV3を制御してみよう!」ということでやってみました。
【関連記事】
【EV3 x C#】lejos-server/clientを使ってC#でEV3を制御する(Windows編)
【EV3 x C#】lejos-server/clientを使ってC#でEV3を制御する(Mac編)
本記事は、上記Windows編での準備およびlejos-serverの転送・実行ができている状態を前提とします。

スマホアプリは今回が初めてという私ですら、Xamarin.Formsを使用して簡単にAndroidからEV3の制御ができましたのでご紹介します。

環境

開発PC

  • Windows 10 64bit
  • Visual Studio 2019

EV3

  • leJOS
  • 車の基本モデル形
  • WiFiドングル付 (ELECOM WDC-150SU2MBK)

Android

  • OPPO Reno A (Android 9)

WiFi

  • スマホ、EV3を同一APに接続

準備

Visual Studioでモバイル開発を有効にする

Visual Studioインストーラーを実行し、[.NETによるモバイル開発]にチェックしてインストールしておきます。
android00.png

Androidアプリの作成

Xamarin を使用して Android 向けの開発を始める」を参考にしながら以下の手順を実施します。

Xamarin.Formsプロジェクトの新規作成

Visual Studioを起動し、新規プロジェクトの作成から[モバイルアプリ(Xamarin.Forms)]を選択して[次へ]
android01.png
次の画面で任意のプロジェクト名を入力して[作成]をクリック。

[新しいモバイルアプリ]画面が表示されるので、

  • [空白]を選択
  • 予定している開発対象で[Android]のみにチェック

し、[作成]をクリック
android03.png

実機と接続して実行

Android デバイスまたはエミュレーターでテストする」を参考にしながら、以下の手順を実施します。
(一部文言はOPPOの場合)

  • スマホと開発PCをUSB接続し、設定を開く
  • [端末情報]を表示する
  • [ビルド番号]を7回タップ =>開発者モードになる
  • 前の画面に戻り、[その他の設定] -> [開発者オプション] -> [USBデバッグの許可]をセット

ここまでの手順を実施すると、接続した実機名で実行できそうな状態になります。
android04.png
プログラムは何も変更せずに、とりあえず実行してみます。
おぉ!実機上にこんな画面が表示された!!(もうこの時点で感動)
android05.png

画面の変更

Xamarin.Forms XAML ページのレイアウトをカスタマイズする」を参考に、MainPage.xamlファイルの内容を次のように書き換えます。
ラベル部分を「EV3 Controller」に書き換えたのと、3x3のグリッドにボタンを配置しました。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="lejosAndroid.MainPage">

    <StackLayout>
        <Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
            <Label Text="EV3 Controller" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
        </Frame>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button Grid.Row="0" Grid.Column="1" Text="Forward" Clicked="OnForwardButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="0" Text="Left" Clicked="OnLeftButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="1" Text="STOP" Clicked="OnStopButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="2" Text="Right" Clicked="OnRightButton_Clicked" />
            <Button Grid.Row="2" Grid.Column="1" Text="Back" Clicked="OnBackButton_Clicked" />
        </Grid>
    </StackLayout>
</ContentPage>

NuGetからlejos-clientを追加

  • Visual Studioのメインメニューから[ツール] -> [NuGetパッケージマネージャー] -> [パッケージマネージャーコンソール]を選択
  • パッケージ マネージャー コンソールで次のように入力し、Enter
PM> Install-Package lejos-client

【補足】
Android開発に合わせて、lejos-clientは.NET Standard2.0にも対応しました。

ロジックの記述

MainPage.xamlを右クリックし、[コードの表示]を選択します。

MainPage.xaml.csに次のように記述します。
ボタンのイベント処理で各EV3のコマンドを実行(パラメータは適当)するシンプルなものです。

using System;
using System.Collections.Generic;
using Xamarin.Forms;
using lejos_client;

namespace lejosAndroid
{
    public partial class MainPage : ContentPage
    {
        //EV3オブジェクト
        EV3 _ev3;

        public MainPage()
        {
            InitializeComponent();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            // アプリ開始時にEV3がWiFiで取得したアドレスに接続
            _ev3 = new EV3("192.168.1.107", 6789);
        }

        private void OnForwardButton_Clicked(object sender, EventArgs e)
        {
            //前進
            _ev3.Wheels.GoForward(150, 720);
        }

        private void OnLeftButton_Clicked(object sender, EventArgs e)
        {
            //左に回転
            _ev3.Wheels.TurnLeft(100, 100);
        }

        private void OnRightButton_Clicked(object sender, EventArgs e)
        {
            //右に回転
            _ev3.Wheels.TurnRight(100, 100);
        }

        private void OnBackButton_Clicked(object sender, EventArgs e)
        {
            //後進
            _ev3.Wheels.GoBackward(150, 720);
        }

        private void OnStopButton_Clicked(object sender, EventArgs e)
        {
            //停止
            _ev3.Wheels.Stop();
        }
    }
}

再度デバッグ実行

デバッグ実行の前に、EV3が「READY」の状態になっていることを確認してください。
実行すると、簡易的にグリッドに配置したボタンがこのように表示されました。
android06.png
ボタンをタップして動きを確認します。

一度スマホでデバッグ実行すると、アプリがスマホ内に入るのでUSBケーブルを抜いても動作します。

追記:傾きでの制御

スマホの傾きで直感的に操作できるようにしてみました。
「Orientation Mode」を追加し、ONの場合はスマホの傾きがそのまま動きとなるようにします。
android6.png

MainPage.xamlを次のように変更します。グリッドに2行追加し、SwitchとOrientation表示用のLabelを追加しました。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="lejosAndroid.MainPage">

    <StackLayout>
        <Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
            <Label Text="EV3 Controller" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
        </Frame>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button Grid.Row="0" Grid.Column="1" Text="Forward" Clicked="OnForwardButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="0" Text="Left" Clicked="OnLeftButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="1" Text="STOP" Clicked="OnStopButton_Clicked" />
            <Button Grid.Row="1" Grid.Column="2" Text="Right" Clicked="OnRightButton_Clicked" />
            <Button Grid.Row="2" Grid.Column="1" Text="Back" Clicked="OnBackButton_Clicked" />
            <Label Grid.Row="3" Grid.Column="1" Text="Orientation Mode" HorizontalOptions="Center" />
            <Switch Grid.Row="3" Grid.Column="2" x:Name = "switch" HorizontalOptions="Start" Toggled = "OnToggled"/>
            <Label Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3" x:Name="LableOrientation" Text="Label Orientation" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
        </Grid>
    </StackLayout>
</ContentPage>

スマホの各種センサー値を取得するには@shuheyさんの記事から「Xamarin.Essentials」を使うと良いらしいことがわかったので、NuGetから「Xamarin.Esssentials」をインストールします。
上記各サイトを参考にしながらMainPage.xaml.csを以下のように修正します。

using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Essentials;
using lejos_client;

namespace lejosAndroid
{
    public partial class MainPage : ContentPage
    {
        //EV3オブジェクト
        EV3 _ev3;
        bool _OrientationMode = false;

        public MainPage()
        {
            InitializeComponent();
            // アプリ開始時にEV3がWiFiで取得したアドレスに接続
            _ev3 = new EV3("192.168.1.108", 6789);
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            OrientationSensor.ReadingChanged += OrientationSensor_ReadingChanged;
            OrientationSensor.Start(SensorSpeed.UI);
        }

        void OrientationSensor_ReadingChanged(object sender, OrientationSensorChangedEventArgs e)
        {
            var data = e.Reading;
            // 調整するパラメータ
            float paramX = 3;
            float paramY = 5.5F;
            int paramLR = 140; // 直角に傾けるくらいで左右モードにする

            // Xに係数をかけて左右のSpeedとする
            int ox = (int)(data.Orientation.X * 100 * paramX);
            // Yに係数をかけて前後のSpeedとする
            int oy = (int)(data.Orientation.Y * 100 * paramY);
            int ow = (int)(data.Orientation.W * 100);
            int oz = (int)(data.Orientation.Z * 100);
            Device.BeginInvokeOnMainThread(() =>
            {
                LableOrientation.Text = $"Orientation X={ox}, Y={oy}, Z={oz}, W={ow}";
            });
            if (_OrientationMode)
            {
                if (Math.Abs(ox) > paramLR)
                {
                    if (ox < 0)
                    {
                        _ev3.Wheels.TurnLeft(oy, 360);
                    }
                    else
                    {
                        _ev3.Wheels.TurnRight(oy, 360);
                    }
                }
                else
                {
                    if (oy >= 0)
                    {
                        _ev3.Wheels.GoForward(oy, 720);
                    }
                    else
                    {
                        _ev3.Wheels.GoBackward(oy, 720);
                    }
                }
            }
        }

        private void OnForwardButton_Clicked(object sender, EventArgs e)
        {
            _ev3.Wheels.GoForward(150, 720);
        }

        private void OnLeftButton_Clicked(object sender, EventArgs e)
        {
            _ev3.Wheels.TurnLeft(100, 100);
        }

        private void OnRightButton_Clicked(object sender, EventArgs e)
        {
            _ev3.Wheels.TurnRight(100, 100);
        }

        private void OnBackButton_Clicked(object sender, EventArgs e)
        {
            _ev3.Wheels.GoBackward(150, 720);
        }

        private void OnStopButton_Clicked(object sender, EventArgs e)
        {
            _ev3.Wheels.Stop();
        }

        private void OnToggled(object sender, ToggledEventArgs e)
        {
            _OrientationMode = this.@switch.IsToggled;
            if (!_OrientationMode)
            {
                _ev3.Wheels.Stop();
            }
        }
    }
}

こんな感じで動作します。

GitHubにアップしましたのでよろしければどうぞ。
https://github.com/teonsen/lejosAndroid

感想

  • ありがとう。Xamarin.Forms。
  • ドローンをスマホの傾きで制御したとき、どれだけうまくできるのかやってみたくなった。

参考サイト

Xamarin.Formsで各種センサーの値を取得するには
Xamarin.Essentials
Xamarin.Essentials:OrientationSensor

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0