Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9743

C#とAndroidによるUDP通信で加速度センサの値を取得するアプリケーション

$
0
0

大まかな内容

ここでは、Androidの加速度センサの値をC#で取得し、その値によってAndroidの端末がどのように動いたかを感知するために作成している。

Androidのアプリケーション

このアプリケーションでは、三軸(X,Y,Z)の加速度センサの値をUDP通信で送る。端末が、どの軸方向に向いているかを分かりやすくるために、各軸が一定の値以上になった場合に音声が鳴るように作成した。

アプリケーションのGUI

ASUSTab K013の場合

ソースコード

ソケット通信を行うので、Androidmanifest.xmlに下記を追加する。

Androidmanifest.xml
<uses-permissionandroid:name="android.permission.INTERNET"></uses-permission>

次に、画像と音声ファイルを扱うため、app内のresのdrawableとrawを作成し、その中に画像データと音声データを入れる。

app
 └res
   ├drawable
   │├en.jpg
   │├en_gleen.jpg
   │└en_red.jpg
   └raw
     ├xjikum.mp3
     ├xjikup.mp3
     ├yjikum.mp3
     ├yjikup.mp3
     ├zjikum.mp3
     └zjikup.mp3
activity_main.xml
<EditTextandroid:id="@+id/IP_Address"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="52dp"android:layout_marginEnd="16dp"android:ems="10"android:inputType="textPersonName"android:text="0.0.0.0"android:textSize="24sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"/><EditTextandroid:id="@+id/Port"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="48dp"android:layout_marginEnd="16dp"android:ems="10"android:inputType="textPersonName"android:text="8080"android:textSize="24sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintHorizontal_bias="0.0"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/IP_Address"/><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="280dp"android:text="X:"android:textSize="32sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"/><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="24dp"android:text="Y:"android:textSize="32sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView"/><TextViewandroid:id="@+id/textView3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="24dp"android:text="Z:"android:textSize="32sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView2"/><TextViewandroid:id="@+id/X_Data"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="280dp"android:text="TextView"android:textSize="32sp"app:layout_constraintStart_toEndOf="@+id/textView"app:layout_constraintTop_toTopOf="parent"/><TextViewandroid:id="@+id/Y_Data"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="24dp"android:text="TextView"android:textSize="32sp"app:layout_constraintStart_toEndOf="@+id/textView2"app:layout_constraintTop_toBottomOf="@+id/X_Data"/><TextViewandroid:id="@+id/Z_Data"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="24dp"android:text="TextView"android:textSize="32sp"app:layout_constraintStart_toEndOf="@+id/textView3"app:layout_constraintTop_toBottomOf="@+id/Y_Data"/><TextViewandroid:id="@+id/textView7"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginTop="230dp"android:text="加速度センサの値"android:textSize="32sp"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"/><Buttonandroid:id="@+id/Ran"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="87dp"android:layout_marginLeft="87dp"android:layout_marginBottom="70dp"android:text="通信開始"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"/><TextViewandroid:id="@+id/textView4"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginLeft="16dp"android:layout_marginBottom="8dp"android:text="IPアドレス"android:textSize="24sp"app:layout_constraintBottom_toTopOf="@+id/IP_Address"app:layout_constraintStart_toStartOf="parent"/><TextViewandroid:id="@+id/textView5"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="16dp"android:layout_marginLeft="16dp"android:layout_marginBottom="8dp"android:text="ポート番号"android:textSize="24sp"app:layout_constraintBottom_toTopOf="@+id/Port"app:layout_constraintStart_toStartOf="parent"/><Buttonandroid:id="@+id/End"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginEnd="87dp"android:layout_marginRight="87dp"android:layout_marginBottom="70dp"android:text="通信解除"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"/><ImageViewandroid:id="@+id/LED1"android:layout_width="75dp"android:layout_height="75dp"android:layout_marginStart="100dp"android:layout_marginLeft="100dp"android:layout_marginBottom="150dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintStart_toStartOf="parent"app:srcCompat="@drawable/en"/><ImageViewandroid:id="@+id/LED2"android:layout_width="75dp"android:layout_height="75dp"android:layout_marginEnd="100dp"android:layout_marginRight="100dp"android:layout_marginBottom="150dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:srcCompat="@drawable/en"/><TextViewandroid:id="@+id/textView6"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="352dp"android:layout_marginEnd="124dp"android:layout_marginRight="124dp"android:text="Delay"android:textSize="32sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toTopOf="parent"/><EditTextandroid:id="@+id/Delay"android:layout_width="159dp"android:layout_height="49dp"android:layout_marginTop="16dp"android:layout_marginEnd="40dp"android:layout_marginRight="40dp"android:ems="10"android:inputType="textPersonName"android:text="100"android:textSize="24sp"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintTop_toBottomOf="@+id/textView6"/>
MainActivity.java
importandroid.hardware.Sensor;importandroid.hardware.SensorEvent;importandroid.hardware.SensorEventListener;importandroid.hardware.SensorManager;importandroid.media.AudioAttributes;importandroid.media.AudioManager;importandroid.media.SoundPool;importandroid.os.AsyncTask;importandroid.os.Build;importandroid.os.Bundle;importandroid.os.Handler;importandroid.view.View;importandroid.widget.Button;importandroid.widget.EditText;importandroid.widget.ImageView;importandroid.widget.TextView;importandroidx.appcompat.app.AppCompatActivity;importjava.io.IOException;importjava.io.UnsupportedEncodingException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetSocketAddress;importjava.net.SocketException;importjava.util.Timer;importjava.util.TimerTask;publicclassMainActivityextendsAppCompatActivityimplementsSensorEventListener{privateSensorManagersensorManager;privateTextViewX_Data_TextView;//加速度センサXの値privateTextViewY_Data_TextView;//加速度センサYの値privateTextViewZ_Data_TextView;//加速度センサZの値privatefloatdata_X,data_Y,data_Z;privateintxp,yp,zp,xm,ym,zm;privateintdata_x,data_y,data_z;privateStringData;privateTimertimer1,timer2;privatemTimerTask1timerTask1;privatemTimerTask2timerTask2;privateHandlerhandler=newHandler();privateHandlerhandler1=newHandler();privatelongDelay;ImageViewLED1,LED2;SoundPoolsoundPool;intmp3_xp,mp3_xm,mp3_yp,mp3_ym,mp3_zp,mp3_zm;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);sensorManager=(SensorManager)getSystemService(SENSOR_SERVICE);X_Data_TextView=findViewById(R.id.X_Data);Y_Data_TextView=findViewById(R.id.Y_Data);Z_Data_TextView=findViewById(R.id.Z_Data);LED1=findViewById(R.id.LED1);LED2=findViewById(R.id.LED2);LED1.setImageResource(R.drawable.en);LED2.setImageResource(R.drawable.en);//効果音付けるのに必要なやつif(Build.VERSION.SDK_INT<Build.VERSION_CODES.LOLLIPOP){soundPool=newSoundPool(5,AudioManager.STREAM_MUSIC,0);}else{AudioAttributesattr=newAudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();soundPool=newSoundPool.Builder().setAudioAttributes(attr).setMaxStreams(5).build();}mp3_xp=soundPool.load(this,R.raw.xjikup,1);mp3_xm=soundPool.load(this,R.raw.xjikum,1);mp3_yp=soundPool.load(this,R.raw.yjikup,1);mp3_ym=soundPool.load(this,R.raw.yjikum,1);mp3_zp=soundPool.load(this,R.raw.zjikup,1);mp3_zm=soundPool.load(this,R.raw.zjikum,1);Buttonran=findViewById(R.id.Ran);Buttonend=findViewById(R.id.End);ran.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewview){if(null!=timer1){timer1.cancel();timer1=null;}xp=yp=zp=xm=ym=zm=0;Stringdelay=((EditText)findViewById(R.id.Delay)).getText().toString();Delay=Long.parseLong(delay);timer1=newTimer();timerTask1=newmTimerTask1();timer1.schedule(timerTask1,0,Delay);timer2=newTimer();timerTask2=newmTimerTask2();timer2.schedule(timerTask2,0,Delay);}});end.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewview){if(null!=timer1){timer1.cancel();timer1=null;}finalStringaddress=((EditText)findViewById(R.id.IP_Address)).getText().toString();Stringport=((EditText)findViewById(R.id.Port)).getText().toString();intPort=Integer.parseInt(port);Stringexit="exit";bytebuf[]=newbyte[exit.length()];try{buf=exit.getBytes("SHIFT_JIS");}catch(UnsupportedEncodingExceptione){e.printStackTrace();}InetSocketAddressinetSocketAddress=newInetSocketAddress(address,Port);finalDatagramPacketdatagramPacket=newDatagramPacket(buf,buf.length,inetSocketAddress);AsyncTask<DatagramPacket,Void,Void>task=newAsyncTask<DatagramPacket,Void,Void>(){@OverrideprotectedVoiddoInBackground(DatagramPacket...datagramPackets){DatagramSocketdatagramSocket=null;try{datagramSocket=newDatagramSocket();datagramSocket.send(datagramPackets[0]);datagramSocket.close();}catch(SocketExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}returnnull;}};task.execute(datagramPacket);}});}@OverrideprotectedvoidonResume(){super.onResume();//Event Listener登録Sensoraccel=sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);sensorManager.registerListener((SensorEventListener)this,accel,SensorManager.SENSOR_DELAY_NORMAL);}@OverrideprotectedvoidonPause(){super.onPause();//Event Listener登録解除sensorManager.unregisterListener((SensorEventListener)this);}@OverridepublicvoidonSensorChanged(SensorEventevent){if(event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){data_X=(500+event.values[0]*25);data_Y=(500+event.values[1]*25);data_Z=(500+event.values[2]*25);data_x=(int)data_X;data_y=(int)data_Y;data_z=(int)data_Z;Data=data_x+" "+data_y+" "+data_z;X_Data_TextView.setText(String.valueOf(data_x));Y_Data_TextView.setText(String.valueOf(data_y));Z_Data_TextView.setText(String.valueOf(data_z));}}@OverridepublicvoidonAccuracyChanged(Sensorsensor,intaccuracy){}privateclassmTimerTask2extendsTimerTask{@Overridepublicvoidrun(){handler.post(newRunnable(){@Overridepublicvoidrun(){if(data_X>=700){LED1.setImageResource(R.drawable.en_gleen);xp+=1;if(xp==1){yp=zp=xm=ym=zm=0;soundPool.play(mp3_xp,2,2,0,0,1f);}}elseif(data_X<=300){LED1.setImageResource(R.drawable.en);xm+=1;if(xm==1){xp=yp=zp=ym=zm=0;soundPool.play(mp3_xm,2,2,0,0,1f);}}elseif(data_Y>=700){LED2.setImageResource(R.drawable.en_red);yp+=1;if(yp==1){xp=zp=xm=ym=zm=0;soundPool.play(mp3_yp,2,2,0,0,1f);}}elseif(data_Y<=300){LED2.setImageResource(R.drawable.en);ym+=1;if(ym==1){xp=yp=zp=xm=zm=0;soundPool.play(mp3_ym,2,2,0,0,1f);}}elseif(data_Z>=700){LED1.setImageResource(R.drawable.en_gleen);LED2.setImageResource(R.drawable.en_red);zp+=1;if(zp==1){xp=yp=xm=ym=zm=0;soundPool.play(mp3_zp,2,2,0,0,1f);}}elseif(data_Z<=300){LED1.setImageResource(R.drawable.en);LED2.setImageResource(R.drawable.en);zm+=1;if(zm==1){xp=yp=zp=xm=ym=0;soundPool.play(mp3_zm,2,2,0,0,1f);}}}});}}privateclassmTimerTask1extendsTimerTask{@Overridepublicvoidrun(){handler.post(newRunnable(){@Overridepublicvoidrun(){finalStringaddress=((EditText)findViewById(R.id.IP_Address)).getText().toString();Stringport=((EditText)findViewById(R.id.Port)).getText().toString();intPort=Integer.parseInt(port);bytebuf[]=newbyte[Data.length()];try{buf=Data.getBytes("SHIFT_JIS");}catch(UnsupportedEncodingExceptione){e.printStackTrace();}InetSocketAddressinetSocketAddress=newInetSocketAddress(address,Port);finalDatagramPacketdatagramPacket=newDatagramPacket(buf,buf.length,inetSocketAddress);AsyncTask<DatagramPacket,Void,Void>task=newAsyncTask<DatagramPacket,Void,Void>(){@OverrideprotectedVoiddoInBackground(DatagramPacket...datagramPackets){DatagramSocketdatagramSocket=null;try{datagramSocket=newDatagramSocket();datagramSocket.send(datagramPackets[0]);datagramSocket.close();}catch(SocketExceptione){e.printStackTrace();}catch(IOExceptione){e.printStackTrace();}returnnull;}};task.execute(datagramPacket);}});}}}

C#のアプリケーション

このアプリケーションでは、UDP通信で受け取ったAndroidの加速度センサの値をrichTextBoxに記録し、各軸の値をそれぞれTextBox表示するように作成した。

アプリケーションのGUI

ソースコード

Form1.cs
usingSystem;usingSystem.Windows.Forms;usingSystem.Net.Sockets;usingSystem.Net;namespaceUDP_Server{publicpartialclassForm1:Form{inti;int[]d;string[]D;privateUdpClientudpClient=null;//受信用クライアントpublicstringrcvMsg=null;//受信メッセージ格納用publicForm1(){InitializeComponent();}//ボタンをクリックしたときの処理privatevoidbutton1_Click(objectsender,EventArgse){//UDPの接続があるときにボタンを押した場合//その処理をなかったことにする(少し違う)if(udpClient!=null){return;}((Button)sender).Enabled=false;stringIPString="127.0.0.1";IPAddressIPAdd=IPAddress.Parse(IPString);//IPアドレスを指定intPort=8080;//ポート番号を指定//UdpClientを作成し、指定したポート番号にバインドするIPEndPointEP=newIPEndPoint(IPAdd,Port);UdpClientudp=newUdpClient(EP);richTextBox1.BeginInvoke(newAction<string>(ShowReceivedString1),"受信を開始します");//非同期的な受信を開始するudp.BeginReceive(UdpServer,udp);((Button)button1).Enabled=true;}//データを受信した時の処理privatevoidUdpServer(IAsyncResultar){UdpClientudp=(UdpClient)ar.AsyncState;for(;;){//一度非同期受信を終了するIPEndPointremoteEP=null;byte[]rcvBytes=udp.Receive(refremoteEP);//受信したデータを文字列に変換stringrcvMsg=System.Text.Encoding.UTF8.GetString(rcvBytes);//"exit"を受信したら終了if(rcvMsg=="exit"){break;}D=rcvMsg.Split(' ');for(i=0;D[i]==null;i++){d[i]=int.Parse(D[i]);}//受信したデータをTextBoxに表示するstringdisplayMsg=string.Format("{0}",rcvMsg);richTextBox1.BeginInvoke(newAction<string>(ShowReceivedString1),displayMsg);X_Data.BeginInvoke(newAction<string>(ShowReceivedString_x),D[0]);Y_Data.BeginInvoke(newAction<string>(ShowReceivedString_y),D[1]);Z_Data.BeginInvoke(newAction<string>(ShowReceivedString_z),D[2]);}rcvMsg="終了しました";//UdpClientを閉じるudp.Close();richTextBox1.BeginInvoke(newAction<string>(ShowReceivedString1),rcvMsg);}privatevoidShowReceivedString1(stringstr){if(richTextBox1.Text==""){richTextBox1.Text=str;richTextBox1.SelectionStart=richTextBox1.Text.Length;richTextBox1.Focus();richTextBox1.ScrollToCaret();}else{richTextBox1.Text=richTextBox1.Text+"\r\n"+str;richTextBox1.SelectionStart=richTextBox1.Text.Length;richTextBox1.Focus();richTextBox1.ScrollToCaret();}}privatevoidShowReceivedString_x(stringstr){X_Data.Text=str;}privatevoidShowReceivedString_y(stringstr){Y_Data.Text=str;}privatevoidShowReceivedString_z(stringstr){Z_Data.Text=str;}privatevoidForm1_FormClosed(objectsender,FormClosedEventArgse){//UdpClientを閉じるif(udpClient!=null){udpClient.Close();}}}}

今後の目標

C#に加速度センサの値で制御できるLEDを模した画像を追加しようと思っているが、そのためにはマルチスレッドでpictureBoxを操作できるようにならないといけないのでそこに力を入れていく。


Viewing all articles
Browse latest Browse all 9743

Trending Articles