Tag Archives: ev3

[五十川芳仁老師來台] 150813 體驗工作坊 台南場

今天早上的台南下了一場大雨,幸好到了九點半,老天爺非常賞臉,給了來參加五十川老師樂高講座的各位大朋友小朋友一個涼爽舒適的好天氣。 本日講座是體驗工作坊,地點在晶英酒店采風廳,飯店人員非常熱心地佈置會場,工作人員們也非常認真地講解展示各作品給孩子們看。

撰文&日文口譯 沈佩誼

IMG_7003

新聞連結:[自由時報]高市創客工作坊 樂高大師秀經驗 / [中時電子報]創客工作坊邀樂高大師與創客見面

[五十川芳仁老師來台] 150814 體驗工作坊&教師工作坊高雄場

[五十川芳仁老師來台] 150812 體驗工作坊&教師工作坊台中場

[五十川芳仁老師來台] 150811 體驗工作坊新竹場

[五十川芳仁老師來台第一天] 150810 台北漫遊美食之旅

五十川老師來台體驗工作坊與教室工作坊,活動說明與報名頁面請按我

Continue reading

[五十川芳仁老師來台] 150814 體驗工作坊&教師工作坊高雄場

今天我們來到了豔陽高照的高雄舉辦兩場工作坊。本次活動地點在光線充足、寬敞舒適的高雄市勞工教育生活中心,裡面的文創相關展品也十分有特色,用色大膽的作品也呈現了高雄人的鮮明個性。

撰文&日文口譯 沈佩誼

IMG_7304

本次活動感謝高雄市政府勞工教育生活中心的大力支持,也感謝徐主任到場一起同樂

IMG_7244

新聞連結:[自由時報]高市創客工作坊 樂高大師秀經驗 / [中時電子報]創客工作坊邀樂高大師與創客見面

[五十川芳仁老師來台] 150812 體驗工作坊&教師工作坊台中場

[五十川芳仁老師來台] 150811 體驗工作坊新竹場

[五十川芳仁老師來台第一天] 150810 台北漫遊美食之旅

五十川老師來台體驗工作坊與教室工作坊,活動說明與報名頁面請按我

早上十點準時開始的「體驗工作坊」來了四十幾位小朋友,大家對於老師的作品都十分感興趣,個個都迫不及待想要親自操作。小朋友對於五十川老師相當生活化的提問都踴躍回答,老師覺得高雄的小孩子個個都好活潑好可愛喔!

IMG_7264  IMG_7286

下午的「教師工作坊」從兩點開始,今天的創作題目也是非常有趣 (台中場的題目是 “15 秒的魔術秀” ,五十川老師為高雄的學員特別發想的唷(早上才決定!熱騰騰的題目!)。五十川老師要大家以MINDSTORM EV3這套組合結合小時候常見的色紙,創造出充滿個人特色的作品。雖然一公佈題目時台下的學員有些一頭霧水,但是經過不到一小時的製作時間,每位學員呈現的作品都令老師十分驚艷呢!比如有學員用色紙做成一隻魚,再結合MINDSTROM EV3,表現魚兒在水中自在悠遊的景象。老師說這個作品也讓他聯想到日本兒童節時家家戶戶卦在外面的鯉魚旗!

IMG_7419

IMG_7450   IMG_7467

IMG_7443

今天最令老師開心的事,就是五十川老師的兩本新書以急件包裹送到活動會場了!甫一得知老師新書即將發行,CAVEDU立即和台灣的基峰出版社聯絡,希望能在五十川老師來台的時候搶先發行,因此這兩本集結了各式各樣實例的樂高結構參考書的中文版甚至比將在美國、日本發售的英文版還要提早兩個月出版了呢!今天參加工作坊的學員也非常捧場,一下子就將兩冊共四十本書全數銷售一空!五十川老師非常開心地為大家簽名,也把熱騰騰的新書拍照上傳到臉書與全世界的粉絲一起分享!

IMG_7478

IMG_7302

[五十川芳仁老師來台] 150811 體驗工作坊新竹場

今天是樂高達人五十川老師來台灣舉辦樂高巡迴分享會的第一天。 我們起了一大早,一行人浩浩蕩蕩從台北搭高鐵到新竹舉辦體驗工作坊。

レゴ達人五十川先生の台湾ツアーは今日から始まりました。 私たちは朝早く起きて、高速鉄道で台北から新竹へ行きました。

IMG_6289

五十川老師來台體驗工作坊與教室工作坊,活動說明與報名頁面請按我

[五十川芳仁老師來台第一天] 150810 台北漫遊美食之旅

撰文&日文口譯 沈佩誼

Continue reading

樂高達人五十川芳仁老師要來啦 8/11~8/16 體驗工作坊與教師工作坊

各位師長、家長與好朋友們,CAVEDU 很榮幸能邀請到樂高達人五十川芳仁老師來台辦理為期一周的親子手作坊與專業研習。五十川芳仁老師對於各式樂高零件的運用已經到了出神入化的地步,CAVEDU 很早就開始從老師那邊偷靈感來用啦~  每次看了之後都會恍然大悟:”原來可以這樣用啊!

當然也是因為我們翻譯了老師的 “樂高機器人創意寶典:181種絕妙新組合“這本書 (說真的字數不多啦),所以五十川老師很爽快就答應我們的邀請來台灣了。在書信來往的過程中,真的體會到老師是位充滿童趣、熱情又專業,也對於老師在行程與活動細節上的一絲不苟感到欽佩。

活動分為體驗工作坊與教師工作坊兩種,詳細資訊請看以下說明,期待您一起來看看五十川老師的有趣作品!

體驗工作坊(按我報名)

內容:五十川芳仁老師分享他數十年來在創作上心路歷程,並攜帶多組難得一見的創作與在場來賓互動。

適合對象:親子同遊,無積木組裝經驗者可。

場次資訊:

  1. 新竹場:104年8月11日,10:00~12:00。人文年代咖啡館,新竹市東區北大路140號。(https://www.facebook.com/agecafe)
  2. 台中場:104年8月12日,10:00~12:00。Habitat 棲息地咖啡,台中市西區英才路534號B1。(https://www.facebook.com/HabitatCaowu)
  3. 台南場:104年8月13日,9:30~12:00。台南晶英酒店,台南市中西區和意路1號。(http://www.silksplace-tainan.com.tw/zh-tw/aboutus.php)
  4. 高雄場:104年8月14日,10:00~12:00。高雄勞工教育生活中心,高雄市前鎮區中山三路132號。(http://recreation.kcg.gov.tw/)
  5. 台北場1:104年8月15日,14:00~16:00。CLBC 肥皂箱,台北市中山區明水路575號B2(樂群二路口) 。(http://clbc.tw/)
  6. 台北場2:104年8月16日,14:00~16:00。CLBC 肥皂箱,台北市中山區明水路575號B2(樂群二路口) 。(http://clbc.tw/)

教師工作坊(按我報名)

內容:五十川芳仁老師帶領學員進行樂高EV3機器人的進階組裝與程式設計技巧,想知道更多不為人知的達人秘辛,請千萬不要錯過。

適合對象:需熟悉樂高EV3機器人與其程式開發環境。

場次資訊:

  1. 台中場:104年8月12日,13:00~16:00。Habitat 棲息地咖啡,台中市西區英才路534號B1。(https://www.facebook.com/HabitatCaowu)
  2. 高雄場:104年8月14日,14:00~17:00。高雄勞工教育生活中心,高雄市前鎮區中山三路132號。(http://recreation.kcg.gov.tw/)
  3. 台北場:104年8月15日,09:00~12:00。CLBC 肥皂箱,台北市中山區明水路575號B2(樂群二路口) 。(http://clbc.tw/)

以下是五十川老師對大家的問候,他也很期待與大家見面喔!

老師要攜帶的作品

おさるのかごや キカイ1 / Machine 1 2 足歩行する 2 匹のお猿さんが、日本古来のカゴをかついで歩くキカイ。どうなっているのか、近くでよく見てみよう。廟會機器人 這兩隻站立的猴子要怎麼在廟會中抬著轎子慶祝呢?讓我們一起來瞧瞧吧!osaruno_kagoya
デカタイヤキカイ 2 / Machine 22つの大きなタイヤを持つキカイ。リモコンのレバー操作で前後に動かして遊ぼう。巨輪機器人  可以利用遙控器上的搖桿前後移動這兩個巨大的輪胎。原作網頁deka_tire
いろいろ・とれいんロボット 3 / Robot 3小さな車をトレイン(列車)に乗せるとトレインが動き出し、車と同じ色の車庫に車を運び入れるロボット。どこで色を調べているのだろ。可愛小火車會將不同顏色的汽車載回各自車庫裡。iroiro_train
こまわりくんロボット 2 / Robot 2 、小回り(こまわり)ができるライントレーサー。どうやって、小回りを実現しているのか調べてみよう。擺頭循線機器人是一台進行小幅度轉彎的循跡機器人,讓我們看看它究竟能轉多小的彎度吧komawarikun
Firebirdロボット1 / Robot 1オムニホイールを使ったロボット。リモコン操作で、どんな動きをするのか試してみよ。火鳥號使用EV3 完成的四輪全向輪機器人,可以用遙控器操作。原作網頁firebird
あしのはやいむしキカイ 5 / Machine 5リモコンで操作すると、虫のようなおもしろい動きをする キカイ。足がどのように動いているのかじっくり観察してみよう。敏捷機器人利用遙控器操作如多足昆蟲般快速移動的機器人。ashinohayaimushi
しゅぽしゅぽエアカーキカイ4 / Machine 4空気で動く車。ポンプやシリンダーもレゴブロックのパーツ。蒸気機関車の原理を使っている。空氣動力車利用蒸汽機原理製作的空氣動力車,車子上的幫浦和汽缸都是樂高官方零件喔。shuposhupo_aircar
2 分の 6 輪車キカイ 3 / Machine 3車輪の半分が欠けている車。どのように動くのか、走らせて確認してみよう。半輪機器人這些輪胎怎麼只有半圈?由六個半圓形輪胎組成的車子動得起來嗎?大家一起來猜猜看吧原作網頁2bunno6rinsha
うちわでゴーロボット 5 / Robot 5うちわを使って、進む方向を変えるロボット。友達どうして遊んでみよう。風向車  您可以用扇子搧風來改變機器人的前進方向。uchiwade_go
あくしゅくんロボット 4 / Robot 4友達になりたい相手を選んで握手をするロボット。あなたも友達になれるかな。握手機器人  會向朋友伸出友誼之手的握手機器人,你也想成為他的朋友嗎?akusyu_kun

主辦單位

台灣青少年機器人協會CAVEDU 教育團隊、萬能科技大學資訊管理系

協辦單位

[成就達成] 魔動王顏色對對碰

我承認這篇真無聊,只是在玩玩具的時候,突然想到好像可以把魔動王與書的顏色搭起來,來吧!知道魔動王的朋友,應該和阿吉老師差不多年紀喔

超級火王 – LabVIEW 高階機器人教戰手冊 (第二版 EV3 + NXT)

2015-04-20 18.56.21

超級水王- LabVIEW for Arduino 控制與應用的完美結合

2015-04-19 23.01.50

超級風王:LabVIEW 高階機器人教戰手冊(初版 for NXT)

2015-04-20 18.57.57

150402 木柵國中EV3機器人體驗課程

木柵國中輔導室為了讓小朋友接觸不同的課程、吸收更多的資訊,特別開了一天半的機器人課程,本日只有半天三小時,時間相當緊湊,參加的小朋友人數多達15位,EV3七套,只好採用分組方式,2-3人一組,雖然如此,小朋友還是很認真的在「玩」積木、學程式,透過不斷的嘗試錯誤,小朋友和機器人都愈來愈進步,讓我們來看看過程吧:

首先當然要組裝車子,透過觀察事先準備好的範例車體來進行組裝,看似簡單,實則考驗耐心與細心,而且有限時二十分鐘喔!!!

3

分組的好處就是每個人透過討論都能有參與感,壞處就是要討論出一個共識需要花很久的時間,而範例提供了一個清楚的目標讓組員去達成,目標有了,所有的討論都會集中於一點,每個人的參與度提高,效率不錯!!

1

 

加上有限定時間二十分鐘,緊張度提高,在最後五分鐘的時候,幾乎每一組都拿著積木跑到台前來組裝!!

2

 

再來就是讓車子動起來,透過EV3-G的馬達方塊,除了基本的前進、後退、轉彎外,還利用差速方式讓車有擁有三種轉彎方式,最後再加裝觸碰感測器,做出讓車子碰到牆壁後能再走回來的效果。

4

 

透過不斷地嘗試錯誤,慢慢修改出聰明的車子

5

 

回車競賽:看誰的車子碰到牆壁後最先跑回起點!!

6

 

車子衝出去的瞬間,大家都笑了…

7

 

第二回合稍微調換了一下位置後,再出發!!

9

8

雖然只有短短的三個小時,但大家都玩得很高興,過程中甚至大家都還會改裝車子,期待下次再相會囉!!

[2015 3月號 Robocon雜誌專欄]輕鬆使用Android 裝置控制樂高機器人:

感謝各位讀者的支持,連載終於邁入最終回了!本期專題要介紹如何使用Android 手機上的姿態感測器來控制樂高EV3 機器人。有接觸過App Inventor 的師長朋友們,歡迎從App Inventor 中文學習網的檔案庫下載本程式的aia 原始檔與apk 安裝檔。

文章原文刊載於《ROBOCON》國際中文版2015/3月號


什麼是Direct Command?為什麼需要它?

根據樂高官方文件, 您可以使用Direct Command做到的重要功能有:

• 啟動/停止主機上指定檔名的程式。
• 控制馬達啟動、停止、轉向、電力與角度上限。
• 取得感測器值與狀態

其餘功能,請參考官方文件(註1)。

開始玩機器人

本範例的機器人與2013 年1 月號的「翻轉控制」專欄是一樣的,只是由NXT 換成EV3 機器人而已。機器人不須加裝任何感測器,只要用兩顆馬達組裝成雙輪機器人即可。本範例是將馬達接在EV3 主機的輸入端A 與B。請確認EV3 主機的藍牙已啟動,接著將EV3 主機與Android 手機進行藍牙配對(註3),完成之後就可以把機器人放到一邊了。啟動藍牙之後,您可以從EV3主機的螢幕左上角看到藍牙的符號。

接下來依序介紹程式的各個功能:

STEP1 登入畫面:

首次進入程式的畫面如圖1a ,這時只有「EV3 裝置/ 連線」按鈕可以按,其它所有按鈕都無法操作。點選「EV3裝置/ 連線」按鈕後進入藍牙裝置清單(圖1b),請找到剛剛配對完成的EV3主機名稱(本範例為abc),點選之後就會由Android 裝置對EV3 主機發起藍牙連線。順利連線成功的話,「EV3裝置/ 連線」按鈕會變成不可按的狀態,其他按鈕則都可按(圖1c)。

圖1a 程式首次執行的畫面。 圖1b 點選連線按鈕後進入藍牙裝置清單。 圖1c 連線成功後的畫面。

STEP2 程式初始化:

在點選連線清單之前(ListPicker_EV3 清單選取器的BeforePicking 事件),需先將清單內容指定為Android裝置上的藍牙配對清單(圖2a),其中connected 這個布林變數是用來指示現在手機是否已和機器人成功連線。

圖2a 指定藍牙配對裝置清單。

點選之後, 會先測試連線是否成功,成功則將「EV3 裝置/ 連線」按鈕設為不可點選,「斷線」等按鈕設為可點選(圖2b)。

圖2b 連線成功後啟動相關元件。

STEP3 直接控制副程式start與stop:

直接控制的奧妙之處在於直接對EV3 發送位元陣列, 只要按照樂高官方文件(註1)的說明,以正確的格式來發送資料即可。以 start 副程式來說, 它可接受兩個參數:port/ speed。您可以看到每次呼叫它時, 都會初始化一個名為 data 的空清單,以本範例來說,每一個清單元素代表一個位元組長度的內容。格式為:(13, 0, 0, 0, 128, 0, 0, 165,
0, port , 129, speed , 166 ,0, port),如圖3a。這當然需要您去查找官方文件中各個欄位所代表的意義。在此我們是將port 與 speed 用變數來控制, 代表所要控制的馬達與其轉速。最後透過BluetoothClient 元件將整個data 清單經由藍牙發送給EV3 機器人即可。

圖3a start 副程式

到了stop 副程式,資料格式當然也有所改變。我們還用一個if 判斷式去檢查stop 參數是否為true , 如果是則在data 清單最後加入1 ,反之則加入0。這樣發送出去之後就能控制機器人是否要停止動作(圖3b)。

圖3b stop 副程式。

藉由這樣的架構,當您要改用姿態控制、觸碰點控制、語音控制時,整體架構是不變的,差別只在於如何修改speed 變數值而已。

STEP4 姿態感測器:

當手機的姿態發生變化時,就會自動呼叫它的姿態改變(OrientationChanged) 事件, 並會把XYZ 的軸向變化以pitch、roll 與azimuth 這三個事件變數呈現, 供我們取用。由圖4a 可知, 我們要透過X 軸向傾斜來控制機器人前進,Y 軸向傾斜來控制左右轉彎等。在本範例中我們使用另外一個Angle 參數(回傳一個角度代表手機往哪個方向傾斜)求出兩顆馬達的轉速。

圖4a Android 手機軸向示意圖。

在此有兩個重要的變數angle 與power:angle 代表手機的傾斜角度,這是由姿態感測器的Angle 參數再減去45 所決定,45 代表座標軸的偏移量。接著是power 變數,這是一個介於0 ∼ 1 之間的小數,代表手機的傾斜程度,數字愈大代表愈斜。power 變數值是由姿態感測器的Magnitude 變數再乘上200 所決定,200 是一個調控用的參數,數字愈大,代表在同樣的傾斜度下,機器人會跑得愈快,但是也更敏感而不好操控。樂高EV3 機器人的馬達電力範圍為100(正向全速旋轉)到-100(反向全速旋轉),數值超過上下限則就限制在100 或-100 ,如圖4b。

圖4b 姿態感測器的姿態改變事件(上半)

這四個重要的參數(pitch、roll、左馬達轉速與右馬達轉速)都會更新在畫面中間的四個Label 標籤元件上。先呼叫一次 stop 副程式,讓馬達先短暫停頓。接著呼叫兩次start 副程式,分別傳入「port =1;speed = cos(angle x power)」與「port =2;speed= sin( angle x power)」這組參數,代表根據姿態感測器的姿態變化量,進行三角函數運算結果,來決定左右馬達的轉速。

最後,把夾角與左右輪轉速捨去小數點之後(round 指令),將計算結果更新在Screen 的狀態列上,如圖4c。

圖4c 姿態感測器的姿態改變事件(下半)。

STEP5 斷線:

按下「斷線」按鈕之後,會中止藍牙連線(BluetoothClient.Disconnect指令),並使畫面上的各個元件恢復到程式一開始時的狀態。

操作

實際執行的時候,請先確認EV3 已經開機且藍牙也啟動了。接著在您的Android 裝置上點選畫面中的「EV3裝置/ 連線」按鈕, 會進到如圖1b的藍牙清單畫面,點選您所要的EV3主機名稱並連線成功後,試著把手機左右搖晃看看。朝前方傾斜,機器人就會前進,傾斜愈多,機器人跑得愈快(圖5a)。左右傾斜的話則是控制機器人左轉或右轉(圖5b)。在App Inventor 官方推出EV3 的元件之前,您也可以用這樣的方法來直接控制樂高EV3 機器人喔!

圖5a 手機朝前方傾斜43 度,X 軸向姿態發生 變化(pitch),機器人朝前方移動,左右馬達電力(38, 39)。

圖5b 手機朝左方傾斜44 度,Y 軸向姿態發生變化(roll),機器人原地左轉,左右馬達電力(-37, 41)。

本程式已上架Google play,請到Google Play 搜尋「CAVE 教育團隊」就找得到我們的樂高機器人系列app 了。歡迎大家到App Inventor 中文學習網的檔案庫下載本程式的aia 原始檔與apk 安裝檔。

註1:樂高EV3 直接控制指令的相關文件請參閱此網頁:http://botbench.com/blog/2014/02/19/ev3-buildyour-own-block-and-hdksdk-docs-available/

註2: 想學如何開發App Inventor 程式嗎? 請到App Inventor 中文學習網(http://www.appinventor.tw)與
我們一同學習。

註3: 與EV3 連線後如果出現「Error 402」之錯誤訊息請不必理會,程式依然能正確執行。

 

[Mindsensors測試]馬達與感測擴充(NXTMMX-v2、SensorMUX-v1、TouchMux、SPLIT-Nx-v2)

Mindsensors有許多有趣的感測器與擴充,但並不是每個都可以讓EV3使用,而有些長得一樣,功能並不一樣,近日也被人問到這些東西到底有哪裡不一樣,今天我們就以這四款擴充器來一一比較解釋:

T1

觸碰感測器擴充(TouchMux),顧名思義就是專門來裝觸碰感測器用的,EV3/NXT都可使用,範例和使用者手冊可點此前往查看。

touchmux1touchmux

感測器擴充(SensorMUX-v1),顧名思義也是讓你裝感測器用,如果裝馬達,則全部的馬達會同時動,但裝馬達則需要額外接電池,NXT用,無EV3專用的BLOCK,相關範例及使用者手冊點此前往。

mux1mux

馬達與感測器擴充(NXTMMX-v2),有二個馬達埠和一個感測器埠,需額外裝電池,EV3/NXT可用,相關範例及使用者手冊可點此前往。

mmx1mmx

最後一個分接器,只能接數位感測器,支援的裝置這裡有說明,目前並沒有專用的BLOCK,而是需要輸入感測器的I2C值來讀取,點此前往查看使用者手冊,目前測試分接器接NXT超音波感測器可以讀得到值。

Matlab & Simulink 的支援硬體:Raspberry Pi、Arduino與樂高機器人

Matlab 可說是所以電機、機械、資工相關科系必備良藥,具備了完整的數學運算功能,尤其是複雜的多維矩陣運算。另外還可以連接外部硬體,從一開始的樂高機器人與Arduino,現在也支援了 Raspberry Pi喔。現在不論是 Matlab 或是 Simulink 圖形化介面,都支援這三種硬體了,您可以使用慣用的硬體來作為資料擷取切面,例如主機狀態與感測器資料(數位/類比)就可以透過 Matlab 來分析出有趣的結果了。

這樣的架構其實用 LabVIEW 也可以,就看您喜歡青菜還是蘿蔔。也請參考 CAVEDU 研究室的 LabVIEW for Arduino 教學

Matlab 網頁介紹

以 Raspberry Pi 來說,以下介面的資訊都能直接取得,很方便。您只要有 Matlab 軟體(有試用版可以先玩玩看,或是大專院校應該都有校園版)以及 Raspberry Pi 就可以開始囉!

  • 攝影機模組
  • I2C 介面
  • SPI 介面
  • Serial 介面
  • GPIO 腳位

參考網頁:

Raspberry Pi support from Matlab  /  Raspberry Pi support from Simulink

 

[即將出版] 樂高機器人創意寶典 181種絕妙新組合 – 五十川芳仁老師大作

五十川芳仁老師的 EV3 Idea book,英文版由 no starch press 出版,繁體中文就由 CAVEDU 翻譯完成囉(其實沒幾個字…)

每每在設計機構卡關時,就會到五十川老師的網站來尋找靈感,因此這本書之後也會用在 CAVEDU 的基礎組裝與機器人課程中喔,多玩就對了~

ach018700-01

[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 遙控,機器人端程式

 

MindSensors 推出的 Grove Sensor Adapter,可用於樂高 EV3 與 NXT 機器人主機

Grove 感測器系列是 Seeed Studio 推出的感測器套件包,搭配自家的擴充板,讓複雜的接線變得簡潔許多。現在 MindSensors 推出了 Grove Sensors 轉接頭,可將各種Grove 感測器轉接到樂高 EV3 與 NXT 主機上使用。

 

GSAwithsensorsw1024

 

當然,也提供了 EV3 的指令,請在本頁面下載後匯入 EV3 環境即可使用。但由下圖可知,提供的是底層的讀寫指令,並未針對特定的感測器提供專屬的讀寫指令。分別有 I2C Read, I2C Write, Analog 與 Digital 等四大類指令。

螢幕快照 2015-02-28 下午11.53.39 螢幕快照 2015-02-28 下午11.53.50

[python 與 EV3] 讀取 MindSensors LightSensorArray 光感測器模組的原始值

在樂高 EV3 上安裝 Debian 作業系統之後, 來讀取MindSensors LightSensorArray 光感測器模組的原始值。這是一個把八個光感測器整合在一起的模組,可說是循線利器。每個感測器都可以根據光量變化回傳 0~100 的數值。

10934431_10203429295989662_60478272_n

先來看影片,配音員聽說很帥

相關資訊:

python on EV3 機器人 – 整理好的 img 檔送給您!

python on EV3 機器人-基礎python撰寫

 

程式碼:

from ev3.ev3dev import Key,Msensor
import time

key=Key()
light=Msensor(port = 1)  #將感測器接在1號輸入端

while key.backspace != True:  #按下EV3 的灰色退出鍵就跳出程式
	val=[]
	val.append(light.value0)
	val.append(light.value1)
	val.append(light.value2)
	val.append(light.value3)
	val.append(light.value4)
	val.append(light.value5)
	val.append(light.value6)
	val.append(light.value7)
	for i in range(7):
		print val[i],
	print val[7]
	time.sleep(0.1)   #等候0.1秒
Get MindSensors LightSensor Array module's raw value

python on EV3 機器人-使用python控制EV3馬達

這次分享的是由ev3主機的python檔案,讓EV3的A、B兩個馬達持續轉動,

2_4_python

想用python控制EV3馬達,需要(1)先安裝dev-ev3的環境(python on EV3 機器人 – 整理好的 img 檔送給您!),

建議(2)先體驗dev-ev3環境下控制馬達(Python EV3 速記 – 控制馬達轉速與方向)

與(3)基本的python語法(python on EV3 機器人-基礎python撰寫)

這是這次分享的的程式碼,程式的內容由python on EV3 機器人-基礎python撰寫所改編,

不一樣的是這次加入python-ev3模組的內容,我們可以使用這個模組裡的語法。

執行此程式後,輸入”A”可以讓馬達A轉動,輸入”B”可以讓馬達B轉動,輸入”stop”可以讓所有馬達停止轉動,

2_1_python

以下皆為使用python-ev3模組的內容:

(1)將模組ev3.lego輸入至檔案中

(2)由LargeMottor決定控制哪一個馬達(A、B、C、D)

(3)使用reset重新設置馬達,重複宣告使用馬達時,需要重新將數值設置

(4)開啟regulation_mode模式(on、off),開啟會使你的馬達輸出比較穩定,比較不受剩餘電池電量的影響

(5)使用run_forever讓馬達持續運轉(-900~900)

(6)使用stop讓馬達停止

你可以在dev-ev3的環境下編寫python的檔案,也可以在你的電腦編寫好檔案之後再把檔案傳送到ev3,

小編我是在電腦寫好主要程式後再傳送,推薦這款好用的軟體cyberduck,支援Windows與Mac系統

2_3_python

選擇SFTP傳輸協定後,輸入EV3主機的ip並輸入帳號與密碼,你的電腦就可以與EV3進行檔案傳輸了

馬上來體看看吧~