Tag Archives: android

[App Inventor] Microbit磁力感測器控制小蜜蜂圖示

本文章教各位讀者如何用手機撰寫App Inventor的應用程式,並透過Buletooth Low Energy 來取得 Micro:bit 磁力感測器訊號,讓app上的小圖示飛來飛去。

作者/攝影  曾吉弘
時間  1小時
成本
難度  * * * *
材料表
  • 個人電腦
  • App Inventor開發環境
  • 支援BLE的Android手機
  • BBC Micro:bit開發板

 

本文要介紹如何藉由最近非常熱門的BBC Micro:bit開發板上的磁力感測器來控制App畫面上的小圖示轉動。Micro:bit板子上已經具備了BLE藍牙通訊功能,搭配app Inventor寫好的micro:bit extesion,就能有更多互動的效果。

 

範例 aia檔下載請按我

 

藍牙配對

 

Micro:bit端設定:

  1. 同時按住Microbit 正面A、B按鍵,不要放掉
  2. 按住A、B鍵時,把背面的Reset 鍵按下後再放開。
  3. 這時應該可以看到 “PAIRING MODE!” 以跑馬燈方式出現在Microbit LED 螢幕上,若看到這訊息,便可以放開A、B鍵。
  4. PAIRING MODE! 結束後,會看到一個圖形出現在Microbit LED 螢幕上,不同的Microbit 出現的圖案也不同,這是Microbit 不同裝置獨特的”簽名” (Signature) 。

5.這時候的Microbit 已經準備好跟其他裝置配對,請看以下影片教學

 

 

 

Android手機端設定:

  1. 進入Android手機的設定–>藍牙
  2. 確認Micro:bit 已進入配對模式
  3. 當Micro:bit上的‘PAIRING MODE!’ 顯示完,搜尋(每隻Android手機這個選項的文字不一定相同,但意思差不多),應該會看到類似 micro:bit [XXXXX]的選項,其中XXXXX 會根據每片micro:bit而不同。點選該裝置來配對。

4.micro:bit 會出現向左的箭頭,然後Android裝置上會跳出畫面要求輸入配對PIN碼的視窗。

5.按住Micro:bit 的按鍵A ,這時microbit 會連續出現六個數字,這就是配對碼。

6.回到Android裝置上,輸入這六個數字。如果Microbit 出現[V],代表配對成功。如果是[X]代表沒成功,請再試一次。

 

編寫程式來取得Micro:bit磁力感測器

匯入BLE 與 micro:bit extension

 

請登入MIT App Inventor官方網站,建立新專案,在Designer葉面中點選Palette左下角的Extension,再點選”Import extension“與”URL:

  1. 貼入以下兩個 extension link:
  2. 請加入 Microbit_Magnetometer這個元件,這是一個非可視元件。並把它的 BluetoothDevice 屬性設為 “BluetoothLE1″。這步驟很容易忘記,別漏掉了
  3. 加入四個按鈕放入 horizontalArrangement元件中,分別用於掃描、停止掃描連線與斷線
  4. 加入1個顯示訊息用的label,用於顯示連線狀態
  5. 加入一個 ListVeiw,當掃描到鄰近的BLE裝置時會顯示在這裡 (到此與MIT所提供的基礎連線測試程式相同)
  6. 加入一個Canvas,寬高皆為320像素
  7. 在Canvas中加入一個ImageSprite,使用任何您喜歡的圖案都可以,在此使用MIT App Inventor新的小蜜蜂logo。
  8. 最後加入4個顯示訊息用的label,用於顯示連線狀態、X、Y、Z軸與方位角(bearing)

Blocks頁面

  1. 掃描與連線

在此的做法都差不多,先點選ScanButton來掃描鄰近可用的BLE裝置(以本專案來說目標是micro:bit,但當然也會出現其他裝置例如手機筆電之類的)。找到裝置之後就會出現在畫面中的ListView中,選取micro:bit後點選ConnectButton就可以連線(BluetoothLE.Connect指令)。

  1. 連線成功後開始更新磁力感測器值

在此設定更新速度(reporting period) 為20ms,並要求micro:bit開始回報方位角與各軸磁力資料更新。

  1. 顯示磁力偵測值並控制ImageSprite

Microbit_Magnetometer1.MagnetometerBearingReceivedMagnetometerDataReceived事件中,我們取出各參數並顯示於對應的Label。並用X、Z軸數值來控制ImageSprite的X. Y座標,您可以改為其他的軸向資料或用於控制其他的效果,很多效果都可以嘗試。

斷線

斷線時會呼叫 bluetoothLE元件來中斷藍牙連線,確認斷線之後則顯示相關訊息。

完工了!來試試看吧。請確認您的Micro:bit與Android已經配對好了。按下按鈕應該可以看到畫面上有一些數字不斷跳動,試著拿個小磁鐵在Micro:bit附近晃晃(別拿太強的,弄壞我不負責喔),看看數字與小圖案的變化。試試看用 Micro:bit搭配 App Inventor 做出更多功能吧

 

相關文章:

 

 

完成如下圖:

 

放課後限定 – AR拍照體驗 (Android) 與拍照機上傳Google相本 (Raspberry Pi)

放課後倒數4天了,我們精心準備了很多好玩的東西,本篇來介紹 AR拍照體驗 (Android)拍照機 (Raspberry Pi)。一定要來玩玩看喔!

AR拍照體驗 (Android + Unity)

使用 Unity 做的 Android app,開啟相機之後掃描[放課後](放心,這三個字在現場到處都是~),就會跳出可愛的小圖框,火箭框會旋轉喔~   旋轉到喜歡的位置就拍照吧~

圖像裡可能有文字

請先下載Android app吧,記得給我們評分喔

拿新書與鋼彈合照是一定要的

沒有自動替代文字。

拍照機 (Raspberry Pi)

剛好公司有現成的 pitop CEED,有片不錯的螢幕與外殼,就直接拿來用了。拍照之後就會上傳到放課後的 Google 相本(會加上圖框喔)

歡迎您來現場玩玩看這台拍照機,後續要改造或用於上課都非常棒喔

拍照後會自動把照片加上放課後圖框傳到放課後的 Google 相本,來看看拍照的效果吧

150613 海洋大學微處理機課程 期末展示-使用 LinkIt ONE

今年的海洋大學微處理機課程順利完成了,本文要來看看各位同學的作品。與去年不一樣的是,今年使用 LinkIt ONE (去年是 Arduino UNO),因此上課內容針對物聯網所需之WiFi、藍牙與GPS (GPRS需要SIM卡所以沒有使用) 都設計了不同的專題讓同學可以逐步學習。當然也必須要整合到期末專題中喔。再次感謝 MediaTek Labs 贊助上課所需的 LinkIt ONE 開發板 (看到這句話的老師,您也可以向他們提出教學計畫來申請板子喔!

認識阿吉的師長朋友們都知道,我希望學生能夠具備一定的口頭表達能力,因此每一位同學都一定要開口講話,也要說明在組裡的分工(變成吉祥物就不好了…)。畢竟你得先打造一個夢,或是現實生活中的某個問題。接下來才是為了做到這件事,我需要怎樣的技術以及過程所碰到的困難等等。所以報告時不要拿一堆程式碼出來嚇人啊,嚇不倒我的。

在這些過程中,你一定會有很多想法與錯誤的累積,好好把他們記錄下來吧,這就是別人拿不走,屬於你的養分。總有一天這些隱性的東西會大大幫你一把的。

另一方面,在一組裡面一定有人投入多,有人會找機會摸魚(說不定還會捅你一把)。如何學習人和,這也是之後出社會的真實縮影,試著體會吧。

學無速成,重在踏實

Continue reading

[雙A計畫]Part6:Arduino 傳兩筆資料到 Android 手機

大家久等了, 本篇文章告訴您如何在 Android 手機端接收兩筆 Arduino 的資料,這次是以 A0, A1 兩隻腳位來處理。本範例感謝嘉義高工張老師提供。

如果您要換成其他元件,例如數位感測器的話,做法是一樣的。請先看一下這個元件的資料範圍是多少。對於本範例的架構來說,最後就是透過藍牙傳一個陣列出去,因此重點在於您是否可先在 Serial Monitor 中看到正確的資料範圍。不過一般來說都會有讀值得範例程式,所以不用太擔心啦!

您可以擴充這個架構到 N 筆,但是筆數愈多,掉資料的機會也愈高。請自行斟酌喔!

[雙A計畫] 常見問題整理

[雙A計畫] 藍芽模組(HC05/06)常用指令教學

[雙A計劃] Part0:App Inventor 透過藍牙傳送訊號給 Arduino

[雙A計劃] Part2:App Inventor 經由藍牙控制 Arduino LED 漸明漸暗

[雙A計劃] Part3:Android 手機透過藍牙接收 Arduino 類比腳位狀態

[雙A計劃] Part4:App Inventor 藍牙遙控 Arduino 雙輪機器人

[雙A計劃] Part5:Paperduino 藍牙控制 LED 閃爍

[雙A計畫] Part6:Arduino 傳兩筆資料到 Android 手機

[雙A計劃] Part7:Arduino超音波感測距離回傳數值給Android手機

[雙A計劃] Part8:Android 手機對 Arduino 同時進行資料收發

English version

Arduino LED Blink

Arduino LED PWM

Arduino LED Blink (Arduino 101 with BLE)

Arduino LED PWM (Arduino 101 with BLE)


在撰寫程式前我們先準備以下材料:範例程式請點我下載(App Inventor中文學習網檔案庫)

材料清單:

1 Android系統智慧型手機

2.Arduino相容開發板

3.藍牙收發接收器 (本系列使用JY-MCU04 or JY-MCU05)

4. 電位計

5. 光敏電阻

6. 1k~10k 歐姆電阻,用於光敏電阻

請按照電路圖將電路接上,接了一個電位器(A0)與光敏電阻(A1)。當然啦,您也可以兩個腳位都用相同的元件,方便就好。為了不讓大家眼花,藍牙發射器另外獨立出來表示 (藍牙RX – Arduino D11, 藍牙TX – Arduino D10腳位):

未命名
A0:電位計。A1:光敏電阻
螢幕快照-2014-10-30-上午12.41.36
TX: Arduino D11, RX: Arduino D10

 


App Inventor 端程式:

由於連線斷線的做法都是差不多的,在此把連線相關指令整理如下圖。請注意Clock timer 一開始是關閉的,我們會在連線成功之後才會將其啟動來發送藍牙指令,否則會一直跳出錯誤訊息(因為還沒連線啊!)
在 Clock.timer 事件中,首先發送一個數字49給Arduino,代表”我要發資料囉!” Arduino 則是先用 BluetoothClient.ReceiveText 指令,如果讀到’a’,就接續讀取後面兩筆資料,這就是 A0 腳位的數值。請注意在此之所以要判斷 text 變數之否小於0再加上 256,是由於Arduino 的 8 bit 整數範圍是 -127 ~ 128 的緣故。
反之如果App 收到字元 ‘b‘ 就是 A1 腳位。作法同上。
接著在Clock.timer 事件最後將這兩筆數值(value_A0value_A1) 顯示於 Textbox,並且用這兩筆數值來控制 Canvas 上面的小飛機移動,快點來玩雷電遊戲吧!
螢幕快照 2015-04-05 上午1.11.29
因為資料傳輸過程中難免會遺漏,因此我們都是先抓到火車頭(就是’a’ 與 ‘b’),確定這是一筆新的資料開頭之後,再去讀取數值,否則可能會發生數值亂跳的情形。另一方面,App Inventor 在藍牙傳輸的延遲狀況較明顯,請注意喔

Arduino 端程式如下,我們把 A0 腳位的資料用 ‘a‘ 作為標頭,由於資料長度大於 1 byte ( 2的8次方),因此需要用到 2 bytes 才能把 A0 的數值範圍 (0~1023) 涵蓋進去,因此 Data[1]~Data[2] 就代表A0 腳位的資料,Data[4]~Data[5] 就是A1 腳位的資料:(Data [0] = ‘a’, Data[3] = ‘b’ 這兩個火車頭別忘記囉~)
#include <SoftwareSerial.h>
#include <Wire.h>
SoftwareSerial I2CBT(10,11); // TX:10, RX:11
byte serialA;

void setup(){ 
  Serial.begin(9600);
  I2CBT.begin(9600);
}
 
void loop (){
    byte Data[6];
    byte cmmd[20];
    int insize;
    int x=analogRead(A0);//read sensor value
    int y=analogRead(A1);//read sensor value
    serialA=I2CBT.read();
    Data[0]='a';
    Data[1]=x/256;
    Data[2]=x%256;
    Data[3]='b';
    Data[4]=y/256;
    Data[5]=y%256;
     Serial.print(x);
     Serial.print(" , ");
     Serial.println(y);
 
     if (serialA == 49){
         for(int j=0;j<5;j++)
         I2CBT.write(Data[j]);
         serialA=0;
      }
  delay(100);
}

[3/29_C-Day有什麼?]系列之七:leJOS Wifi 遙控多台樂高EV3 機器人

手機遙控樂高機器人在以往 NXT 的時代,只能用藍牙點對點,手機端是 master,樂高機器人則是 slave。手機端能連多少台藍牙裝置是根據胎手機而定,不過一般來說兩台是沒問題的。今天如果改用 Wifi 的話就不會受限於Android 手機的藍芽配對裝置數量了。本文說明如何透過 Wifi 來控制兩台樂高 EV3 機器人,同步或非同步控制都可以,請看以下影片。

延伸閱讀:

[leJOS] 準備開機用 SD記憶卡 – 用 Java 程式控制樂高EV3機器人

這是使用 App Inventor 來控制兩台樂高 NXT 機器人:

接著來看程式碼,這是 Android 端的src,重點在於建立兩個 socket 來對兩台機器人發送指令(line 179,205):

package com.cavedu.ev3_socketremote;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends ActionBarActivity implements OnClickListener {

	//Device 1
	Socket clientSocket1;
	BufferedReader inbound;
	PrintWriter outbound;

	String sendStr = "";

	Button Connect, FWD, BACK, LEFT, RIGHT, STOP;
	EditText deviceIP, devicePort;
	
	//Device 2
	Socket clientSocket2;
	BufferedReader inbound2;
	PrintWriter outbound2;

	String sendStr2 = "";

	Button Connect2, FWD2, BACK2, LEFT2, RIGHT2, STOP2;
	EditText deviceIP2, devicePort2;

	//初始化
	void init(){
		FWD = (Button) findViewById(R.id.FWD);
		BACK = (Button) findViewById(R.id.BACK);
		RIGHT = (Button) findViewById(R.id.RIGHT);
		LEFT = (Button) findViewById(R.id.LEFT);
		STOP = (Button) findViewById(R.id.STOP);

		FWD.setOnClickListener(this);
		BACK.setOnClickListener(this);
		LEFT.setOnClickListener(this);
		RIGHT.setOnClickListener(this);
		STOP.setOnClickListener(this);
		
		deviceIP = (EditText) findViewById(R.id.device1_ip);
		devicePort = (EditText) findViewById(R.id.device1_port);
		Connect = (Button) findViewById(R.id.Connect);

		FWD2 = (Button) findViewById(R.id.FWD2);
		BACK2 = (Button) findViewById(R.id.BACK2);
		RIGHT2 = (Button) findViewById(R.id.RIGHT2);
		LEFT2 = (Button) findViewById(R.id.LEFT2);
		STOP2 = (Button) findViewById(R.id.STOP2);
		
		FWD2.setOnClickListener(this);
		BACK2.setOnClickListener(this);
		LEFT2.setOnClickListener(this);
		RIGHT2.setOnClickListener(this);
		STOP2.setOnClickListener(this);
		
		deviceIP2 = (EditText) findViewById(R.id.device2_ip);
		devicePort2 = (EditText) findViewById(R.id.device2_port);
		Connect2 = (Button) findViewById(R.id.Connect2);
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		init();		//初始化

		//設定前進、後退、左轉、右轉按鈕Enabled為Flase 在未連線時無法點選
		setDeviceButton(false);
		setDevice2Button(false);
		
		//按下Connect使Device1連線
		Connect.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				
				//Device 1 Socket Client連線
				if (Connect.getText().equals("Connect")) {
					
					//建立Socket連線
					Thread t1 = new Thread(runnable);	
					t1.start();
					
				} 
				
				//Device 1 Socket Client斷線
				else if (clientSocket1.isConnected()) {
					try {
						Log.w("AndyDebug", "ClientSocket1 Close");
						clientSocket1.close();
						Connect.setText("Connect");
						setDeviceButton(false);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});
		
		//按下Connect使Device2連線
		Connect2.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				
				//Device 1 Socket Client連線
				if (Connect2.getText().equals("Connect")) {
					Thread t1 = new Thread(divice2runnable);
					t1.start();
				} 
				
				//Device 2 Socket Client斷線
				else if (clientSocket2.isConnected()) {
					try {
						Log.w("AndyDebug", "ClientSocket1 Close");
						clientSocket2.close();
						Connect2.setText("Connect");
						setDevice2Button(false);
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		});

	}

	//Device 1 建立Socket連線
	Runnable runnable = new Runnable() {
		public void run() {
			try {

				String ip = deviceIP.getText().toString();
				int port = Integer.parseInt(devicePort.getText().toString());

				clientSocket1 = new Socket(ip, port);	//建立Socket連線

				if (clientSocket1.isConnected()) {
					runOnUiThread(new Runnable() {
						public void run() {
							Connect.setText("Close");
							setDeviceButton(true);
						}
					});
				}

				Log.d("AndyDebug", "is?" + clientSocket1.isConnected());

				//Socket 接收
				inbound = new BufferedReader(new InputStreamReader(
						clientSocket1.getInputStream()));

				//Socket 發送
				outbound = new PrintWriter(clientSocket1.getOutputStream(),
						true);

			} catch (IOException ioe) {
				System.err.println("IOException: " + ioe);
				runOnUiThread(new Runnable() {
					public void run() {
						Connect.setText("Connect");
						setDeviceButton(false);
					}
				});
			}
		}
	};

	//Device 1 透過Socket收發資料
	Runnable runnable2 = new Runnable() {
		public void run() {
			try {

				String sss = sendStr + "\r\n";

				char send[] = sss.toCharArray();

				Log.d("AndyDebug", "送出: " + sss);

				outbound.println(send);		//送出資料

				String inputLine = "";

				//接收資料
				while ((inputLine = inbound.readLine()) == null) {
				}
				Log.d("AndyDebug", "收到:" + inputLine);

			} catch (Exception e) {
				System.err.println("IOException: " + e);
			}
		}
	};
	
	//Device 2 建立Socket連線
	Runnable divice2runnable = new Runnable() {
		public void run() {
			try {

				String ip = deviceIP2.getText().toString();
				int port = Integer.parseInt(devicePort2.getText().toString());

				clientSocket2 = new Socket(ip, port);		//建立Socket連線

				if (clientSocket2.isConnected()) {
					runOnUiThread(new Runnable() {
						public void run() {
							Connect2.setText("Close");
							setDevice2Button(true);
						}
					});
				}

				Log.d("AndyDebug", "clientSocket2"+clientSocket2.toString());

				//Socket 接收
				inbound2 = new BufferedReader(new InputStreamReader(
						clientSocket2.getInputStream()));

				//Socket 發送
				outbound2 = new PrintWriter(clientSocket2.getOutputStream(),
						true);

			} catch (IOException ioe) {
				System.err.println("IOException: " + ioe);
				runOnUiThread(new Runnable() {
					public void run() {
						Connect2.setText("Connect");
						setDevice2Button(false);
					}
				});
			}
		}
	};

	//Device 2 透過Socket收發資料
	Runnable device2runnable2 = new Runnable() {
		public void run() {
			try {

				String sss = sendStr2 + "\r\n";
				Log.e("AndyDebug", sendStr2);
				char send[] = sss.toCharArray();

				Log.d("AndyDebug", "送出: " + sss);

				outbound2.println(send);		//送出資料

				String inputLine = "";

				//接收資料
				while ((inputLine = inbound2.readLine()) == null) {
				}
				Log.d("AndyDebug", "收到:" + inputLine);

			} catch (Exception e) {
				System.err.println("IOException: " + e);
			}
		}
	};

	@Override
	public void onClick(View v) {
		switch (v.getId()) {

		case R.id.FWD:
			sendStr = "FWD";
			sendCommand();
			break;

		case R.id.BACK:
			sendStr = "BACK";
			sendCommand();
			break;

		case R.id.LEFT:
			sendStr = "LEFT";
			sendCommand();
			break;

		case R.id.RIGHT:
			sendStr = "RIGHT";
			sendCommand();
			break;

		case R.id.STOP:
			sendStr = "STOP";
			sendCommand();
			break;
		case R.id.FWD2:
			sendStr2 = "FWD";
			sendCommand2();
			break;

		case R.id.BACK2:
			sendStr2 = "BACK";
			sendCommand2();
			break;

		case R.id.LEFT2:
			sendStr2 = "LEFT";
			sendCommand2();
			break;

		case R.id.RIGHT2:
			sendStr2 = "RIGHT";
			sendCommand2();
			break;

		case R.id.STOP2:
			sendStr2 = "STOP";
			sendCommand2();
			break;
		default:
			break;
		}
	}

	private void sendCommand() {
		Thread t2 = new Thread(runnable2);
		t2.start();
	}
	private void sendCommand2() {
		Thread t2 = new Thread(device2runnable2);
		t2.start();
	}

	private void setDeviceButton(boolean b) {
		FWD.setEnabled(b);
		BACK.setEnabled(b);
		LEFT.setEnabled(b);
		RIGHT.setEnabled(b);
		STOP.setEnabled(b);
	}
	
	private void setDevice2Button(boolean b) {
		FWD2.setEnabled(b);
		BACK2.setEnabled(b);
		LEFT2.setEnabled(b);
		RIGHT2.setEnabled(b);
		STOP2.setEnabled(b);
	}
}
Wifi 遙控,Android 端程式

樂高機器人端的程式,使用 leJOS 編寫。一樣是去判斷 socket 收到的內容之後執行對應的動作即可:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

import lejos.hardware.Button;
import lejos.hardware.Key;
import lejos.hardware.KeyListener;
import lejos.hardware.lcd.LCD;
import lejos.hardware.motor.Motor;

class LeJOS_WiFi {

	static int angle = 270; // 馬達轉動的角度

	private static boolean OutServer = false;
	private static ServerSocket server;
	private final static int ServerPort = 1234; // 要監控的port

	public static void main(String[] args) {

		//按下ESCAPE鍵離開程式
		Button.ESCAPE.addKeyListener(new KeyListener() {
			public void keyReleased(Key k) {
				System.exit(0);
			}
			public void keyPressed(Key k) {}
		});

		print("Start");
		
		Thread socketServer_thread = new Thread(socketServer_runnable);
		socketServer_thread.start();

		while (true);
	}

	//建立SocketServer
	public static void SocketServer() {
		try {
			server = new ServerSocket(ServerPort);

		} catch (java.io.IOException e) {
			print("Socket Error!");
			print("IOException :" + e.toString());
		}
	}

	static Runnable socketServer_runnable = new Runnable() {
		public void run() {
			SocketServer();

			Socket socket;

			print("Socket Server OK!");

			while (!OutServer) {
				socket = null;
				try {
					synchronized (server) {
						socket = server.accept();
					}
					print(socket.getInetAddress().toString()); //印出目前連線設備的ip

					//Socket接收
					BufferedReader inbound = new BufferedReader(
							new InputStreamReader(socket.getInputStream()));

					//Socket發送
					PrintWriter outbound = new PrintWriter(
							socket.getOutputStream(), true);

					while (true) {
						String data = "";

						outbound.println("Success");

						while ((data = inbound.readLine()) == null)
							;

						if (data.length()>=3)
							print("getData:" + data);

						if (data.equals("FWD")) {
							go();
							outbound.print(data + " OK");
						} else if (data.equals("BACK")) {
							back();
							outbound.print(data + " OK");
						} else if (data.equals("LEFT")) {
							left(angle);
							outbound.print(data + " OK");
						} else if (data.equals("RIGHT")) {
							right(angle);
							outbound.print(data + " OK");
						} else if (data.equals("STOP")) {
							stop();
							outbound.print(data + " OK");
						}
					}

				} catch (java.io.IOException e) {
					print("Socket Error");
					print("IOException :" + e.toString());
					Thread socketServer_thread = new Thread(socketServer_runnable);
					socketServer_thread.start();
				}
			}
		}
	};
	
	//前進
	private static void go() {
		Motor.A.forward();
		Motor.B.forward();
	}

	//後退
	private static void back() {
		Motor.A.backward();
		Motor.B.backward();
	}

	//左轉
	private static void left(int angle) {		
		Motor.A.rotate(-angle, true);
		Motor.B.rotate(angle, true);
	}

	//右轉
	private static void right(int angle) {
		Motor.A.rotate(angle, true);
		Motor.B.rotate(-angle, true);
	}

	//停止
	private static void stop() {
		Motor.A.stop();
		Motor.B.stop();
	}

	//在EV3螢幕印出字串
	private static void print(String str) {
		LCD.clear();
		LCD.drawString(str, 0, 3);
	}

}
Wifi 遙控,機器人端程式

 

[App Inventor] 模擬器新選擇 – GenyMotion

使用  App Inventor 的師長朋友們,覺得 Android 官方的模擬器版本太舊嗎?螢幕解析度不夠嗎?想要執行在更新 Android 版本的模擬器嗎?今天和您介紹一款好用的 Android 模擬器軟體: GenyMotion

除了無法像 App Inventor 有同步功能以外(換言之,每次修改之後就要下載 apk 再安裝到 GenyMotion 模擬器上),其他各方面都好太多了。推薦大家一定要玩玩看。

GenyMotion 有分為免費版(只限個人使用) 以及完整功能的企業版( 每個月 25 歐元,但現在大特價中) 。免費版本與完整版相比,

不過,就個人用途來說,相當足夠喔!

請下載免費版本即可,並且要註冊一個帳號。到時候啟動軟體時需要登入這個帳號才能繼續。請下載包含 VirtualBox 的檔案 (117MB),依序安裝完成即可。

首次啟動  GenyMotion 時,請點選 Add 來新增一個裝置。

g001

接著會詢問您要用哪一個版本,基本上 4.0 之後的差異並不大。要玩玩看 5.0 也可以。在此我選 4.3,預設解析度為 768  x 1280。這實際上有點大,等一下可以改小一點,不然系統資源會被吃光,筆電螢幕也放不下。

G002

確認要新增的裝置名稱與各種參數,在此直接按 Next 就好。這些參數之後都可以修改。

g003

這時候會上網下載這個版本模擬器所需的資料,請稍等一下

g004

完成了!這時候就可以看到剛剛所新增的模擬器了。請點選 右側的扳手符號來修改設定,在此要把解析度調低一點,不然有可能模擬器一開就把系統資源吃光光。在此調整為 480 x 854 , 240dpi。您可以找一下您所使用的實體手機解析度為何,這樣就能更符合您的個人需求。

g005

完成之後請按 Start 鍵來啟動模擬器,一樣請稍等一下。請拉動畫面解鎖就可以看到熟悉的 Android 畫面囉!

g006   g007

GenyMotion 可以連到電腦的 Webcam喔,這樣要做攝影相關功能就更方便啦

g008

接下來請由您的 App Inventor 下載任何一個專案的 apk 檔,以拖拉的方式直接丟到 GenyMotion 模擬器中就可以了。

g009

旋轉畫面改成橫向握持也是沒問題的。

g010

開心使用吧!唯一麻煩的地方就是每次修改都要重新包 apk 再執行。

 

 

淡江城區部Android職訓課程,18堂=4.5月,結訓囉!

大家…   辛苦了。從三月開訓到今天,一共18周共54個小時,一起走過 Android UI設計、觸碰與手勢、感測器、2D3D繪圖、網路(Wifi/藍牙)、樂高機器人、Google Map、Facebook、Google API(AdSense、Picasa與Youtube等)、資料儲存等課題。

機器人與Processing 是很有趣的課程,也算是阿吉老師的特色(雜七雜八)吧。與其在課堂上一直帶程式碼,我覺得告訴同學有哪些可能性正在發生更重要。所以有同學也跑去 FabCafe 喝過咖啡了,也有來 Maker Faire 找老師聊天,或是帶家裡的小朋友去參加 MakerBar 的活動。有時候無目的亂晃亂看,說不定會有意想不到的收穫呢。

也感謝大家在工作繁忙之餘,都還是有作回家作業,真感動。我對同學的期許(其實很多是業界資深前輩)就是:結訓的時候比自己進來的時候厲害,這樣就好了。每個人經歷與背景都不一樣,不需要和別人比。

今天是大家專案demo的日子,是不是有點緊張呢?來看看一些有趣的專題吧

IMG_2262 - 複製

拖吊資訊查詢,這是 SQlite 的畫面,Android app 藉此來查各拖吊場的資訊並取出各個欄位,可以打電話給拖吊場、定位與叫計程車等等,一氣呵成QQ…

2014-07-09 19.36.18

2014-07-09 19.30.41

電視節目查詢。可以查詢民視的節目,還可以查詢經典台詞:9527 之類的

2014-07-09 20.02.38

小強!小強你怎麼了小強!周星馳系列真是華人經典

2014-07-09 20.03.57

藍牙遙控 LED燈條。手機發送訊號給,這位大哥本身硬體底子不錯,使用12V的電源,並用 TI 的晶片來控制 LED 的顏色、多種閃爍模式與呼吸燈效果。

2014-07-09 20.31.29

實際demo的效果非常好喔!請看影片

[youtube=http://youtu.be/ORCovzOklY0]

2014-07-09 20.31.15

爸爸寫給孩子的英文生字小遊戲,真是好爸爸啊

2014-07-09 20.57.02

會出現題目(南瓜),要在時限之內點選正確的英文字母,有趣的是點了某個字母之後,字母會消失然後樓上的字母會掉下來,很像Candy Crush喔。最下面的題號、答對答錯數目以及得分也都做出來了。

2014-07-09 20.58.16

[Android 結合 Google Chart API] 機器人原地轉一圈產生雷達圖

機器人原地轉一圈之後,將超音波感測器值透過藍牙送給Android 手機,再呼叫 Google Chart API 雲端圖表功能來取得雷達圖。可以畫出非常精美的圖表。重點在於靈活應用 Google Chart API  的語法就可以囉!

直接點選以下連結就可以看到雷達圖,詳細參數設定請參閱 Google Chart API 官網或以下延伸閱讀

https://chart.googleapis.com/chart?cht=r&chs=320×320&chxt=x&chxl=0:|0|45|90|135|180|225|270|315&chd=t:60,40,30,100,76,99,22,57,80

本範例是結合樂高機器人的超音波感測器來達到簡易地圖掃描的效果,歡迎試試看。以下範例是2014年淡江大學智慧型行動裝置整合機器人控制課程的作業之一。感謝電機系周煜同學(已畢業)做出相當好的版本呢。

 

12345

[youtube=http://www.youtube.com/watch?v=DBvhrxkb24M]

延伸閱讀:

Google Chart API 教學

Google Chart 隨機產生折線圖

淡江電機 Android 機器人整合課程網站

140523淡江電機 Android 行動裝置整合機器人控制課程,期末專題展示

Code Android端

package com.example.nxtsense;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;



import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Build;

public class MainActivity extends ActionBarActivity {
	private BluetoothAdapter adapter;
	private BluetoothSocket nxtSocket;
	public DataInputStream nxtDataIn;
	public DataOutputStream nxtDataOut;
    public final int MODE_CONNECT_NXT = 0, MODE_CONTROL = 1;
    private int mode;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_main);
        adapter = BluetoothAdapter.getDefaultAdapter();
    	if(adapter==null)
        {
        	Toast.makeText(this, "No Bluetooth adapter found", Toast.LENGTH_SHORT).show();
        	this.finish();
        }
    	if(!adapter.isEnabled())
			startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 1);
    	
    	try {
			setMode(MODE_CONNECT_NXT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	Button getvalue=(Button)findViewById(R.id.get);
    	getvalue.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				try {
					CommandNXT();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		});
        
    }

    public void CommandNXT() throws IOException{
    	String y="";
    		nxtDataOut.writeInt(1);
    		nxtDataOut.flush();
    	
    	//	int x=nxtDataIn.readInt();
    		y=String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt())+","
    				+String.valueOf(nxtDataIn.readInt());
    	
					//TextView tv=(TextView)findViewById(R.id.value);
			    	//tv.setText(String.valueOf(x));
		
    	String myURL =" https://chart.googleapis.com/chart?cht=r&chs=320x320&chxt=x&chxl=0:|0|45|90|135|180|225|270|315&chd=t:"+y;         
        WebView myBrowser=(WebView)findViewById(R.id.mybrowser);  
  
        WebSettings websettings = myBrowser.getSettings();   
        websettings.setJavaScriptEnabled(true);  
         
        myBrowser.setWebViewClient(new WebViewClient());  
  
        myBrowser.loadUrl(myURL);  	
    	
    	
    	
    }
    public void setMode(int _mode) throws IOException
    {
    	Button connect=(Button)findViewById(R.id.buttonConnect);
    	mode = _mode;
    	if(mode==MODE_CONNECT_NXT)
    	{
    		
    		connect.setOnClickListener(new Button.OnClickListener() {
    			public void onClick(View arg0) {
    				connectNxt();
    				}
            });
    	}
    	
    	else if(mode==MODE_CONTROL)
    	{
    		connect.setEnabled(false);
    	}
    	else 
    		throw new IllegalArgumentException();
    }
    
    private void connectNxt()
    {
    	if(mode!=MODE_CONNECT_NXT) //檢查模式
    		throw new IllegalArgumentException();
    	
    	String name;
    	BluetoothDevice nxt = null;
    	
    	if((name = ((EditText) findViewById(R.id.editNxtName)).getText().toString()).equals("")) //檢查是否為空字串
    	{
    		Toast.makeText(this, "Please provide the name of your NXT", Toast.LENGTH_SHORT).show();
    		return;
    	}
    	
        Set<BluetoothDevice> devicesSet = adapter.getBondedDevices(); //取得裝置清單
        
        if(devicesSet.size()==0) //找不到裝置
        {
        	Toast.makeText(this, "No devices found", Toast.LENGTH_SHORT).show();
        	return;
        }
        
        for (BluetoothDevice device : devicesSet) //搜尋裝置
        {
            if (device.getName().equals(name))
            {
            	nxt = device;
                break;
            }
        }
        
        if(nxt==null) //找不到裝置
        {
        	Toast.makeText(this, "NXT not found", Toast.LENGTH_SHORT).show();
        	return;
        }
        
        try
        {
        	//建立nxt socket
			nxtSocket = nxt.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
			nxtSocket.connect();
			nxtDataOut = new DataOutputStream(nxtSocket.getOutputStream());
			nxtDataIn = new DataInputStream(nxtSocket.getInputStream());
		}
        catch(IOException e)
		{
        	Toast.makeText(this, "Connection failure", Toast.LENGTH_SHORT).show();
        	return;
		}

    	Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
		try {
			setMode(MODE_CONTROL);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }




   

}
Code. Android receive ultrasonic value from Lego robot

Code 機器人端使用 leJOS

import lejos.nxt.*;
import lejos.nxt.comm.*;
import lejos.util.Delay;

import java.io.*;
public class motor_control{
	public static void main(String args[]) throws IOException{
		Button.ESCAPE.addButtonListener(new ButtonListener(){
				public void buttonPressed(Button b){
					System.exit(0);
					}
				public void buttonReleased(Button b){
					
				}
		});
		System.out.println("Waiting");
		BTConnection btc = Bluetooth.waitForConnection(0, NXTConnection.RAW);
		DataInputStream dis = btc.openDataInputStream();
		DataOutputStream dos = btc.openDataOutputStream();
		System.out.println("Connected");
		UltrasonicSensor ultrasonic1 = new UltrasonicSensor(SensorPort.S2);
		int Ultrasonicvalue1;
		while(true){
			int a=dis.readInt();
			if(a==1){
				for(int i=0;i<7;i++){
					Motor.A.setSpeed(100);
					Motor.B.setSpeed(100);
					Motor.A.backward();
					Motor.B.forward();
					Delay.msDelay(822);
					Ultrasonicvalue1=ultrasonic1.getDistance();
		//	System.out.println(Ultrasonicvalue1);
			
				try {
					dos.writeInt(Ultrasonicvalue1);
					dos.flush();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			
			}
				Motor.A.setSpeed(0);
				Motor.B.setSpeed(0);
				Motor.A.backward();
				Motor.B.backward();
			}
		}
			}
}
Code. Robot send out ultrasonic value to Android (leJOS)

Maker Faire 結束了, 接著是 CAVEDU六月的研習喔

未命名

 

Maker Faire 結束了, 是不是心中也躍躍欲試想要做些什麼呢? 歡迎參加  CAVEDU 六月份的研習

一共有4場, 另外在 MakerBar 也會有 Arduino 實作工坊與電子實作超入門, 歡迎報名喔!!

06/07 Raspberry Pi – Linux 嵌入式電腦研習營 – 台中場@【享實做樂 Good work!】

06/08 Scratch for Arduino 趣味工作坊

06/15 Raspberry Pi – Linux 嵌入式電腦研習營

06/22 Intel Galileo Linux 嵌入式電腦研習營

這張圖是我們到 9月 CAVEDU day 之前的所有活動(請給我們好天氣與健康的身體), 也是在 Maker Faire 現場的DM, 您有拿到嘛?

1234

140523淡江電機 Android 行動裝置整合機器人控制課程,期末專題展示

今天是阿吉老師淡江電機智慧型行動裝置整合機器人控制課的最後一堂課,也是我們課程的期末專題發表。主要的內容是於 Eclipse IDE 中使用 Java程式語言來開發各種機器人控制專題。

主題有保全機器人、路面避障機器人、發射機器人、生活便利機器人、繪圖機器人、堆高機、分類機器人、測速照相機器人、搬運機器人、搖擺彈彈球、搬運機器人、大嘴鱷魚、全景拍照機器人等等。而從期中到期末的課程這段期間,老師教了更多更難的google API跟Facebook程式碼。還記得Facebook程式碼那堂課大家驚呼連連。原來打了幾行指令之後就可以看到那個人所打過卡的所有地方等等的訊息,難怪大家都說Facebook對於個人資料並沒有做很好的隱私。

不過還是建議大家不要把太多隱私的東西放在網路上喔!上次期中報告的時候,大家都只完成了一些進度,希望在期末的時候大家都能夠有更多進步空間。

 

教學網站請按我 <- 投影片與code 學生專題都在這邊下載喔!!

 

阿吉老師今天穿的很正式,想必是對同學的期末報告非常的重視。

IMG_0278

這組同學報告的是倉儲搬運機器人

IMG_0267

還有指定地點送物品的機器人

IMG_0288

IMG_0287

全景拍照機器人,不過拍照功能必須要手按才能。

IMG_0313

IMG_0317

圈圈叉叉遊戲機器人,還蠻有創意的一組報告,可以跟人互動玩遊戲。

IMG_0319

IMG_0320

鈴鐺分類機器人,但是因為鈴噹的表面太過反光,導致機器人在判讀的時候總是錯誤。

希望同學可以將鈴鐺加工之後Demo會表現更好喔!!

IMG_0327

IMG_0335

街機遊戲機器人,構想很棒。但是並沒有做出遊戲該有的介面。

如果有把平常玩遊戲介面的那種計分、秒數、路徑都顯示在手機上會更完整喔!

IMG_0367

大嘴鱷魚,是小編覺得最棒的一組專題。跟其中比起來多了更多功能,還有背景音樂。

而且Demo的時候讓全班的同學都圍了過來,被嚇人的機器人逗得笑聲連連。

IMG_0383IMG_0390

偵測機器人,可以手機遙控機器人進入災區探查。這組同學對於程式碼的部分非常認真。報告的時候還分享自己遇到的Bug以及解決辦法。

IMG_0399

IMG_0404

自動平衡橋機器人,到了某個快掉下去的角度就會使橋面歸正。

IMG_0415

IMG_0424

測速機器人,不過這組的同學可能一開始的構想沒有查好測速的原理。導致期末的時候誤解了測速的意思。

IMG_0481

課程結束之後不免俗地要來一個大合照,感謝老師這學期的教導喔!

IMG_0496

【機器人機構近拍】

操控抓取機器人

IMG_0501

測速機器人

IMG_0503

全景拍照機器人

IMG_0504

鈴鐺分類機器人

IMG_0505

勘查機器人

IMG_0507

平衡橋機器人

IMG_0508

 

140521 海洋大學Arduino微處理機課程 Android遙控Arduino機器人

不管怎麼說, 遙控機器人最好玩. 在連續一個月都比較偏靜態的專題之後, 今天要用 App Inventor  來寫按鈕控制程式來控制 Arduino 機器人. 我們之後會在雙A計畫系列教學文中來介紹如何做出這樣功能的互動機器人專題

您可以從先前的文章中找到上課的內容。請參閱[海洋大學機械系 Arduino 微處理機教學網站]

[youtube=http://youtu.be/xeLjGcejtsQ]

2014-05-20 19.49.20

另外也有同學用 Wii 手把來控制機器人, 雖然只是用搖桿(概念就是兩個可變電阻), 但還是很吸睛哩

2014-05-20 19.22.51

Android Google Map API – Eclipse 環境建置

本篇是幫大家整理出在 Eclipse 中建置 Android Google Map API V2 環境時,可能會遇到的種種狀況。說真的狀況真的很多, 不知道 Google 為什麼要改得這麼複雜, code 本身不是問題, 環境才是問題.

本文件整理自 Google Map Android API V2 教學頁面 。投影片可直接下載,也請點這裡下載 source code (HelloMap.rar)。基本上來說就是以下幾個步驟:

  1. 安裝 Google Play services SDK
  2. 在本機取得SHA1 憑證
  3. 到Google APIs Console 網站申請API key
  4. 新增專案、設定權限
  5. 加入地圖

在除錯過程時,也幫大家準備了一些溫馨小提醒,這些也都寫在投影片中了。

  1. 如果程式一執行就閃退,那八成是 API Key 有問題,請檢查或乾脆重新申請一個 key。
  2. 如果程式可以執行但是沒有畫面(白底), 請檢查是否有新增 INTERNET 的 uses-permission 以及您的手機是否可以上網。
  3. 換不同的電腦來開發,就要重新申請一個 key (因為 SHA1 不同).
  4. 確認認使用 debug.keystore 來產生 SHA1
  5. 記得在 AndroidManifest.xml 中加入 API Key 、meta data與相關權限
  6. 如果使用別人的範例來修改時,請記得更改 package name。因為 API Key 是用 SHA1 + 自訂的package name 去申請所以一定不一樣。 
  7. 有無匯入 Google Play services libraries

請注意的是由於模擬器上沒有 Google Play,所以無法執行在模擬器上。以下畫面都是執行在實體手機上截圖。網路上有教您如何在模擬器上安裝 Google Play,但我覺得還是直接裝在手機上比較乾脆…

投影片我們上傳到 Slideshare 了, 請點選以下投影片就可以下載.


下圖是範例程式執行的畫面

2014-05-07 05.31.33

 

也請參考由南開科大老師所維護的 [智慧生活科技專業社群] 中的 Google Map 教學,有一個點兩下呼叫 Google Map 規劃路徑的範例,非常方便。

2014-05-07 07.07.24

 

 

140408 海洋大學Arduino微處理機課程 期中專題展示

最近許多學校都到了期中考周,海洋大學機械系的Arduino 微處理機課程也該是來看看同學們的 idea 實踐得如何。我喜歡教大一的小朋友,雖然會的東西可能還不夠多,但是比較乖而且勇於嘗試。

您可以從先前的文章中找到上課的內容。請參閱[海洋大學機械系 Arduino 微處理機教學網站]

share 與 demo 在我的課是很重要的一環。學生必須在學期第四或第五周就提出這學期預計完成的專題。會有一次 proposal 預演,然後在期中考時要展示專題功能的 40%,期末當然就是見真章了。在demo 時,需要著整齊服裝,準備好紙本、投影片,上台時間八分鐘不可以超過。也只有在上台的時候,一些基本功才會看出來,例如 pptx 不能讀、影片格式不能播、機器人突然沒電等等,沒有事先彩排的話,在台上一定很抖。

雖然沒有紙本考試,但 loading 說真的也不小哩。

另一方面,好東西也需要好的表達。所以每位同學都要能完整地對其他人說明專題內容。由此可以看出誰是沈穩型、人來瘋型,或是江湖賣藥型的…   總歸理工科系學生上台 present 的機會比較少。能在課堂中補強這件事,我認為很重要。

學生文件的格式也要好好要求,魔鬼就藏在細節裡。一份錯字連篇的報告很難說服別人說你有在這上面下功夫。

有關阿吉老師對於學生的囉囉梭梭,可以看這一篇

看到大家很努力去達到目標,上網找資料、問老師、問助教、問學長。不管怎樣,做出來就對了。現在網路這麼方便,應該有更好的方法來讓自己的成果被更多人看到才對(想想以前出門辦研習還要帶一顆行動硬碟,現在只要問有沒有網路就好了啊!)這樣當同學大三大四要準備研究所的時候,已經有相當豐富的專題庫可以用了,不是嗎?

Always be prepared.

來看照片吧。這組同學做的是超音波避障掃地機器人,自己去弄了車身開始挖洞(聽說工具只有打火機和螺絲起子,可以和學校借啊孩子)。完成度很不錯喔

IMG_8066

IMG_8086

[youtube=https://www.youtube.com/watch?v=GLTy9SP6_5Q]

IMG_7930 IMG_7950

很有藝術感的投影片

IMG_7962

這組要做聲控水舞,不過有關幫浦、防水以及如何呈現還在思考

IMG_8002

 

IMG_8159

手機藍牙遙控機器人

IMG_8169

這台機器人真是有maker(土炮)精神,學期末要整理得漂亮一點噢

IMG_8178

釣魚機器人,看起來像車子,實際上運作的概念類似夾娃娃機。

IMG_8209

專題[會跑的鬧鐘],手機連線畫面。

IMG_8228

更多照片在這裡喔!(Wordpress 真好用,現在多了相片藝廊的功能,太棒了)

140418 淡江電機 Android 行動裝置整合機器人控制課程,期中專題展示

今天阿吉老師到淡江大學上課,而今天的課程是期中的專題展示,主要的內容是於 Eclipse IDE 中使用 Java程式語言來開發各種機器人控制專題。

這次的主題有保全機器人、路面避障機器人、發射機器人、生活便利機器人、繪圖機器人、堆高機、分類機器人、測速照相機器人、搬運機器人、搖擺彈彈球、搬運機器人、大嘴鱷魚、全景拍照機器人等等。

既然是Android,同學們就要思考Android手機資源要如何與機器人整合,而不是換個程式語言玩碰碰車而已。手機上的動作感測器、GPS、照相機、網路連線、麥克風等等,對機器人來說都是很關鍵的功能啊!

另一方面,各種 Google API例如 Google Map、Google Chart、Google Application Engine 或是較簡單的語音輸入/輸出等,都能讓機器人更豐富。

來看看CAVEDU之前做的 Google Map 結合機器人的概念影片以及 openCV / Android 實作,讓機器人可以透過手機的影像辨識結果來移動。

[youtube=https://www.youtube.com/watch?v=qvI04snZRuU] [youtube=https://www.youtube.com/watch?v=k6Lelf7SNWI]

軟滑小編也有修這堂課喔!會修這堂課是因為,之前大三有修過 leJOS 樂高機器人的課程。想說要更進一步的學更多相關的課程才修的。不過本學期的課程內容比起以往難度提高很多很多,許多同學都為了把專題做的更好,準備了很久。

寫app的方式有很多種,相較起來App Inventer,java的變化更多更複雜,也代表著程式碼更多更難。所以App Inventer真的是很適合學習Android入門的程式語言喔!但換個角度來說,如果要做到更完整的功能,還是要回到 Android 正規開發環境哩,真難抉擇啊

同學們都很認真的上台報告

這組的目標是藉由手機的姿態感測器讓機器人保持在翹翹板中央,做到簡易的動態平衡控制。

來看一下同學們的作品有哪些,有些的機構設計的很不錯!

分類機器人
分類機器人Demo
大嘴鱷魚
全景拍照機器人
推高機

最後由老師講評整個專題展示結果,大家的表現… 還有很大的進步空間啦,希望學期末報告的時候都可以更棒!

阿吉老師講評

閱讀延伸

AppInventor – 圖形化Android

Android相關文章

Arduino 躍然紙上 -> Paperduino

http://paperduino.eu/doku.php

最近網路上很有趣的專題:Arduino躍然紙上 (自己先想的中文名稱,還不錯吧)。取得相關零件之後,樣板印出來之後,拉好線焊接就是一片Arduino!

所有零件都可以在網路商店買齊 (光華商場萬歲!),也許 CAVEDU 之後辦這樣的研習也會提供材料包~

CAVEDU 已取得作者的同意,正在進行整體網頁中文化。請大家拭目以待。

fb740e4f16e6bdb5e09f94efcd115258.media.900x577 48e51928c211f4ab923374a552f357f8.media.600x250 35600d6ce45545687b00392f4b46e275.media.600x239 707886777a6695d11335c6b69b5c9faa.media.600x239

處理器使用 ATtiny85,官方網路上有教學如何自行燒錄 bootloader。還可以直接用 Raspberry Pi 來燒錄 bootloader, 真方便(拿出 Pi 來)

8f84fee0e8bf84e60bc563a10a60f2a9.media.400x364