Author Archives: 徐 豐智

[Electric Imp 物聯網小惡魔]以網頁模式觀看溫濕度感應器

Electric IMP小惡魔,除了可以在ElectricIMP的網頁上進行coding與上傳資料,我們還能在agent code pane(代理人程式碼區),撰寫程式碼,將我們感測到的溫度數字上傳到一般網頁中。

如果想深入了解IMP小惡魔可以看下列幾篇文章

認識 Electric Imp 線上開發環境環境建置與 BlinkUp app溫濕度感應計

imp01

在執行程式之後,在agent code pane(代理人程式碼區),點選這個device(裝置)專用的網址,我們不僅可以將IMP的數值顯示在開發網頁中,IMP也可以將數值呈現在一個獨立的頁面

imp02

IMP的程式是以C語言、JAVESCRIPT與HTML的語法為基礎做撰寫,要達成下列效果,必須下列使用IMP專屬的函式,將agent code pane(代理人程式碼區)、device code pane(裝置程式碼區)之間做連結,進行資料傳遞。

1、agent.on(string, function)

2、agent.send(string, object)

3、device.on(string, function)

 

我們在device code pane(裝置程式碼區)使用agent.on(string, function)agent.send(string, object)這兩個函式,裝置接險與程式碼可以參考這篇溫濕度感應計,文章最下方有附device code pane的完整程式碼,主要傳遞訊息的部分在176-213行,讓我們先直接看這個部分。

1、我們使用agent.on(“pong”, returnFromImp)等待從agent code pane(代理人程式碼區)傳來的識別資訊”pong”,並將資訊的數值傳送到副函式returnFromImp之中。

2、將溫度感應器的溫度數值藉由agent.send(“ping”, data_temp)函式,將一個識別資訊”ping”,以及想要傳送的溫度資訊data_temp,傳送至agent code pane(代理人程式碼區)

function loop() {
    imp.wakeup(INTERVAL, loop);
    local data = dht11.read();
    local data_hum,data_temp;
    server.log("Running "+imp.getsoftwareversion()+", Free Memory: "+imp.getmemoryfree());
    data_hum= data.rh;
    server.log(format("Relative Humidity: %0.1f",data_hum)+" %");
    //server.log(format("Relative Humidity: %0.1f",data.rh)+" %");
    data_temp= data.temp;
    server.log(format("Temperature: %0.1f C",data_temp));
    //server.log(format("Temperature: %0.1f C",data.temp));
    ping(data_temp);
}

spi         <- hardware.spi257;
clkspeed    <- spi.configure(MSB_FIRST, SPICLK);

dht11 <- DHT11(spi, clkspeed);
////////////////////////////////////////////////////////////////////////////////////
function ping(data_temp) 
{
    // Send a 'ping' message to the server with the current millis counter
    
    agent.send("ping", data_temp);
}

function returnFromImp(startMillis)
{
}

agent.on("pong", returnFromImp);
 
// Start the ping-pong

//ping();

//////////////////////////////////////////////////////////////////////////////
loop();

 

 

接著在agent code pane(代理人程式碼區)使用device.on(string, function)http.onrequest(function)這兩個函式,

1、使用device.on(“ping”, startTime)函式等待從device code pane(裝置程式碼區)傳來的識別資訊”ping”並將溫度資訊data_temp傳送至副函式startTime

2、副函式startTime會先在網頁下方的 log pane(記錄區)顯示一次接收到的溫度數值

3、http.onrequest(requestHandler)會更新這個裝置專屬網頁的內容,每當我們對網頁進行重新整理,http.onrequest(requestHandler),便會到副函式requestHandler抓取最新數值response.send(200, format(“Temperature: %0.1f C”,global_data_temp));

 

agent code pane(代理人程式碼區)的完整程式碼

global_data_temp <- 45.5;
global_data_hum <- 45.5;

function startTime(data_temp)
{
    server.log(format("agent Temperature: %0.1f C",data_temp));
    server.log(data_temp);
    
    global_data_temp = data_temp;
    // Send the device a 'pong' message immediately
    //device.send("pong", time);
}


function requestHandler(request, response) {
  // send a response back to whoever made the request
  server.log("http refresh");
  response.send(200, format("Temperature: %0.1f C",global_data_temp));
  //response.send(200, "LED OK ");
}
http.onrequest(requestHandler);


device.on("ping", startTime);

 

device code pane(裝置程式碼區)的完整程式碼

// Copyright (c) 2014 Electric Imp
// This file is licensed under the MIT License
// http://opensource.org/licenses/MIT
// Class for DHT11/RHT03 Temp/Humidity Sensor

const SPICLK = 937.5;
const INTERVAL = 5; // time between readings in seconds


// Class to read the DHT11/DHT22 family of temperature/humidity sensors
// See http://akizukidenshi.com/download/ds/aosong/DHT11.pdf
// These sensors us a proprietary one-wire protocol. The imp
// emulates this protocol with SPI. 
// To use:
//  - tie MOSI to MISO with a 10k resistor
//  - tie MISO to the data line on the sensor
class DHT11 {
    static STARTTIME_LOW     = 0.020000;    // 20 ms low time for start
    static STARTTIME_HIGH    = 0.000020;  // 20 us min high time for start
    static STARTTIME_SENSOR  = 0.000080;  // 80 us low / 80 us high "ACK" from sensor on START
    static MARKTIME          = 0.000050;  // 50 us low pulse between 0 or 1 marks
    static ZERO              = 0.000026; // 26 us high for "0"
    static ONE               = 0.000075;  // 70 us high for "1"
    
    _spi                 = null;
    _clkspeed            = null;
    _bittime             = null;
    _bytetime            = null;
    _start_low_bits      = null;
    _start_low_bytes     = null;
    _start_high_bits     = null;
    _start_high_bytes    = null;
    _start_ack_bits      = null;
    _start_ack_bytes     = null;
    _mark_bits           = null;
    _mark_bytes          = null;
    _zero_bits           = null;
    _zero_bytes          = null;
    _one_bits            = null;
    _one_bytes           = null;
    
    // class constructor
    // Input: 
    //      _spi: a pre-configured SPI peripheral (e.g. spi257)
    //      _clkspeed: the speed the SPI has been configured to run at
    // Return: (None)
    constructor(spi, clkspeed) {
        _spi = spi;
        _clkspeed = clkspeed;
    
        _bittime     = 1.0 / (_clkspeed * 1000);
        _bytetime    = 8.0 * _bittime;
        
        _start_low_bits      = STARTTIME_LOW / _bittime;
        _start_low_bytes     = (_start_low_bits / 8);
        _start_high_bits     = STARTTIME_HIGH / _bittime;
        _start_high_bytes    = (_start_high_bits / 8);
        _start_ack_bits      = STARTTIME_SENSOR / _bittime;
        _start_ack_bytes     = (_start_ack_bits / 8);
        _mark_bits           = MARKTIME / _bittime;
        _mark_bytes          = (_mark_bits / 8);
        _zero_bits           = ZERO / _bittime;
        _zero_bytes          = (_zero_bits / 8);
        _one_bits            = ONE / _bittime;
        _one_bytes           = (_one_bits / 8);
        
        // // Pull the signal line up
        _spi.writeread("\xff");
        imp.sleep(STARTTIME_LOW);
    }
    
    // helper function
    // given a long blob, find times between transitions and parse to 
    // temp and humidity values. Assumes 40-bit return value (16 humidity / 16 temp / 8 checksum)
    // Input: 
    //      hexblob (blob of arbitrary length)
    // Return: 
    //      table containing:
    //          "rh": relative humidity (float)
    //          "temp": temperature in celsius (float)
    //      if read fails, rh and temp will return 0
    function parse(hexblob) {
        local laststate     = 0;
        local lastbitidx    = 0;
        
        local gotack        = false;
        local rawidx        = 0;
        local result        = blob(5); // 2-byte humidity, 2-byte temp, 1-byte checksum
    
        local humid         = 0;
        local temp          = 0;
        
        // iterate through each bit of each byte of the returned signal
        for (local byte = 0; byte < hexblob.len(); byte++) {
            for (local bit = 7; bit >= 0; bit--) {
                
                local thisbit = (hexblob[byte] & (0x01 << bit)) ? 1:0;
                
                if (thisbit != laststate) {
                    if (thisbit) {
                        // low-to-high transition; watch to see how long it is high
                        laststate = 1;
                        lastbitidx = (8 * byte) + (7 - bit);
                    } else {
                        // high-to-low transition;
                        laststate = 0;
                        local idx = (8 * byte) + (7 - bit);
                        local hightime = (idx - lastbitidx) * _bittime;
                        
                        // we now have one valid bit of info. Figure out what symbol it is.
                        local resultbyte = (rawidx / 8);
                        local resultbit =  7 - (rawidx % 8);
                        //server.log(format("bit %d of byte %d",resultbit, resultbyte));
                        if (hightime < ZERO) {
                            // this is a zero
                            if (gotack) {
                                // don't record any data before the ACK is seen
                                result[resultbyte] = result[resultbyte] & ~(0x01 << resultbit);
                                rawidx++;
                            }
                        } else if (hightime < ONE) {
                            // this is a one
                            if (gotack) {
                                result[resultbyte] = result[resultbyte] | (0x01 << resultbit);
                                rawidx++;
                            }
                        } else {
                            // this is a START ACK
                            gotack = true;
                        }
                    }
                }
            }
        }
        
        //server.log(format("parsed: 0x %02x%02x %02x%02x %02x",result[0],result[1],result[2],result[3],result[4]));
        humid = (result[0] * 1.0) + (result[1] / 1000.0);
        if (result[2] & 0x80) {
            // negative temperature
            result[2] = ((~result[2]) + 1) & 0xff;
        }
        temp = (result[2] * 1.0) + (result[3] / 1000.0);
        if (((result[0] + result[1] + result[2] + result[3]) & 0xff) != result[4]) {
            return {"rh":0,"temp":0};
        } else {
            return {"rh":humid,"temp":temp};
        }
    }
    
    // read the sensor
    // Input: (none)
    // Return:
    //      table containing:
    //          "rh": relative humidity (float)
    //          "temp": temperature in celsius (float)
    //      if read fails, rh and temp will return 0
    function read() {
        local bloblen = _start_low_bytes + _start_high_bytes + (40 * (_mark_bytes + _one_bytes));
        local startblob = blob(bloblen);
        for (local i = 0; i < _start_low_bytes; i++) {
            startblob.writen(0x00,'b');
        }
        for (local j = _start_low_bytes; j < bloblen; j++) {
            startblob.writen(0xff,'b');
        }
        
        //server.log(format("Sending %d bytes", startblob.len()));
        local result = _spi.writeread(startblob);
        return parse(result);
    }
}



function loop() {
    imp.wakeup(INTERVAL, loop);
    local data = dht11.read();
    local data_hum,data_temp;
    server.log("Running "+imp.getsoftwareversion()+", Free Memory: "+imp.getmemoryfree());
    data_hum= data.rh;
    server.log(format("Relative Humidity: %0.1f",data_hum)+" %");
    //server.log(format("Relative Humidity: %0.1f",data.rh)+" %");
    data_temp= data.temp;
    server.log(format("Temperature: %0.1f C",data_temp));
    //server.log(format("Temperature: %0.1f C",data.temp));
    ping(data_temp);
}

spi         <- hardware.spi257;
clkspeed    <- spi.configure(MSB_FIRST, SPICLK);

dht11 <- DHT11(spi, clkspeed);
////////////////////////////////////////////////////////////////////////////////////
function ping(data_temp) 
{
    // Send a 'ping' message to the server with the current millis counter
    
    agent.send("ping", data_temp);
}

function returnFromImp(startMillis)
{
}

agent.on("pong", returnFromImp);
 
// Start the ping-pong

//ping();

//////////////////////////////////////////////////////////////////////////////
loop();

[3/29_C-Day有什麼?]系列之三:台北市校際盃機器人選拔賽(二)-使用Raspberry Pi Model B與Brick Pi 擴充板

本篇內容是由  CAVEDU 的實習生-袁佑緣提供的使用心得

首先我們先挑選時下流行的微電腦Raspberry Pi 來做測試,本次使用的是B板並搭配Dexter公司所生產的BrickPi來控制LEGO的馬達與感測器。(上面是Raspberry Pi B,下面是BrickPi)

02

如果好奇什麼是BrickPi的人,請參看這篇

首先我們將BrickPi與Raspberry Pi B組裝起來,並鎖上BrickPi的塑膠殼,注意到它上面有許多小洞是專門設計來結合LEGO零件的插銷,所以要將控制器裝置在你的LEGO機器人上完全不是問題喔!

03

接著組裝機器人,這個機器人的設計是用前面的框框綁上兩條橡皮筋當作網子,利用手臂往下壓來取乒乓球,並把乒乓球放回身上的籃子當中,而機器人行走的馬達則是使用LEGO EV3的大馬達。

04 05

前面手臂的動力來源則是用LEGO EV3的中型馬達,並且作一系列的小帶大的齒輪將馬達的力量放大,以防舉不起物件的情況。

06

接著是下面裝的感應器,分別是顏色感應器,與光源感應器,這兩個感應器都是使用NXT的感應器,光源感應器可以用來循線行走,而顏色感應器則可以用來判斷色卡

07

注意到BrickPi無法直接使用EV3的感應器,如果真的需要使用,可以參考官方的教學文件( http://www.dexterindustries.com/site/?p=1822 ),只要將BrickPi的firmware更新就可以使用了!

 

接著我們必須在Raspberry Pi B上安裝對應的系統,才能透過BrickPi控制LEGO元件,下載官網提供的映象檔(http://sourceforge.net/projects/dexterindustriesraspbianflavor/ ),然後燒錄成SD開機卡,插在Raspberry Pi B並開機,成功後便可以透過SSH從電腦連線到Raspberry Pi B,然後就可以開始撰寫程式啦!

 

例如:我想用Python來撰寫機器人的程式,那麼我打開桌面一個叫BrickPi_Python的資料夾(這裏的桌面當然指的是Raspberry Pi B裏Linux系統的桌面),就可以看到許多範例,相關的函式則可以參照其中一個BrickPi.py檔案,裏面有各種函式與變數的定義。

 

此外,如果你想使用其他的語言撰寫,BrickPi也支援像C語言,甚至是圖形化介面的Scratch也可以喔!

 

使用心得:

 

使用Raspberry Pi B搭配BrickPi來做機器人,自然有一些明顯的好處,像是你可以像管理電腦一樣,在上面撰寫程式、管理檔案,也可以由筆電透過遠端連線來進行操作、傳輸檔案,而連上網路也不是問題,這些都是一般的控制器無法做到的地方,此外在官網上的BrickPi Projects裡面也有許多的範例可以參考(http://www.dexterindustries.com/BrickPi/projects/ ),非常適合maker專題的實作喔!

 

但是它做為「比賽用的機器人」有些許不足的地方,像是Raspberry Pi B對於熱插拔很容易當機,在電力上如果不在BrickPi接上額外的電源實在很難驅動馬達運作,而接上的電源又不能影響到Raspberry Pi B,很容易導致當機,筆者在嘗試的時候多次就遇到終端機畫面無反應而必須重開的慘況。

 

這是為什麼呢?熱插拔容易當機的原因是Raspberry Pi B要到B+的板本後才有在5V電源供應那邊加上2A的保險絲,所以要到B+才支援熱插拔(Raspberry Pi A 與A+也是同樣的道理喔)。

另一方面,BrickPi官方提供的馬達控制函式並不多,以python語言為例,可以見github上對於brickPi.py的定義(https://github.com/DexterInd/BrickPi_Python/blob/master/BrickPi.py ),裡面直接定義馬達轉動的函式只有一條,剩下的必須用變數來控制馬達,此外,由於沒有詳細的library reference,只能參照原本的函式庫當案中的說明,其上手難易度也高了不少,對於「機器人駕訓班」這個圍繞在如何控制馬達轉動,而且現場題目變化靈活度相當高的比賽,或許我們可以有更好的選擇……

 

零件提供來源在這裡

[3/29_C-Day有什麼?]系列之四:台北市校際盃機器人選拔賽(三)- 使用Arduino uno與NXShield

本篇內容是由  CAVEDU 的實習生-袁佑緣提供的使用心得

這次採用Arduino UNO搭配mindsensors公司所生產的NXShied來控制我們的機器人(本次使用的是NXShield-D),Arduino相比Raspberry Pi功能雖然比較簡單,但是卻相對容易操作而且穩定,而NXShield則是讓我們可以透過這塊板子來控制LEGO的電子零件,以下是以「機器人駕訓班」中的一個任務:將指定物件(例如:乒乓球)推開或取得,取得有額外加分。

首先我們先來看看機器人的核心:左邊是Arduino UNO控制板,右邊則是NXShield,NXShield主要可以接四個馬達與四個感應器,其他的特殊的針腳則可以用來接servo或I2C用

08注意到NXShield對感應器的支援上僅有NXT,如果想要支援EV3的話,則需另外購買轉接線,而馬達的部分則是NXT與EV3皆可使用,而mindsensors公司不愧是專門出產LEGO機器人相關的配備,對於支援的函式庫與感應器種類相當多,對於新手算是相當友善的選擇。

緊接著是機器人手部的設計,這次改用EV3的大馬達來取代先前的EV3中馬達,大馬達的扭力大概是中馬達的2~3倍,所以這次就直接裝在馬達上,而不用再另外裝齒輪組來加大扭力。

09

 

而電源供應的部分,筆者實際測試過的情況是必須要將兩塊板子各自都接上電源才行正常運作,只有接其中一塊板子的話,有可能會發生”插著USB線的時候可以正常運作,可是拔掉USB線(也就是只有吃電池的電源時)會發生運作不正常的現象,常常跑幾個步驟後就arduino就突然重新啟動了”。因為LEGO馬達的運作電壓是9V,所以筆者的作法是為兩個板子各自接上9V的電源,跑起來就是相當的有力啊

11_2 11

 

再來就是軟體的部分啦,開發環境的設定相當容易,先下載官方提供的函式庫(附上連結http://sourceforge.net/projects/nxshield/files/ ),然後打開電腦中的Arduino IDE->點選上方的草稿碼->點選匯入程式庫->匯入程式庫,然後選擇你剛剛下載的檔案就行大功告成了!

那麼我們就來看看實際跑起來的樣子,以下是簡單的範例程式:

#include <Wire.h>
#include <NXShield.h>

NXShield nxshield;
//引入必要函式庫與新增NXShield變數
void setup() {
 
  delay(500);
  nxshield.init(SH_HardwareI2C);//初始化I2C
  nxshield.bank_a.motorReset();//初始化馬達
  nxshield.bank_a.motorReset();
  nxshield.waitForButtonPress(BTN_LEFT);//等待按下左鍵才開始(NXShield板子上有四個按鍵分別是RIGHT,LEFT,RESET,GO)
 
}

void loop() {
  
  delay(5000);
  nxshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, 20);//Bank B 的Motor-1以馬力20正轉,機器人將手臂往下壓
  delay(2000);
  nxshield.bank_a.motorRunUnlimited(SH_Motor_Both, SH_Direction_Reverse, 20);//Bank A 的Motor-1,Motor-2以馬力20反轉,向前進
  delay(2000); 
  nxshield.bank_a.motorRunUnlimited(SH_Motor_Both, SH_Direction_Forward, 30);//Bank A 的Motor-1,Motor-2以馬力20反轉,碰到蓋子後向後退
  delay(500); 
  nxshield.bank_a.motorStop(SH_Motor_Both, SH_Next_Action_BrakeHold);//Bank A 的Motor-1,Motor-2停止鎖死
  nxshield.bank_b.motorRunDegrees(SH_Motor_1, 
                     SH_Direction_Reverse, 
                     60,
                     70, 
                     SH_Completion_Wait_For,
                     SH_Next_Action_BrakeHold);//Bank B 的Motor-1以馬力60反轉70度,機器人手臂向上抬一個角度
                     
   nxshield.bank_a.motorRunDegrees(SH_Motor_Both, 
                     SH_Direction_Reverse, 
                     30,
                     230, 
                     SH_Completion_Wait_For,
                     SH_Next_Action_BrakeHold);
                     //Bank A 的Motor-1,Motor-2以馬力30反轉230度,機器人向前進一小段距離,只要改變這段距離就可以解決正方形或者是三角形的題型
                     
   nxshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Forward, 100);//Bank B 的Motor-1以馬力100正轉,機器人將手臂全力往下壓
   for(int i = 0; i < 5; i++)
   {
     nxshield.bank_a.motorRunUnlimited(SH_Motor_Both, SH_Direction_Reverse, 30);
     delay(130);
     nxshield.bank_a.motorRunUnlimited(SH_Motor_Both, SH_Direction_Forward, 30);
     delay(100);
   }//前後來回壓球,使得進球率變高
   nxshield.bank_a.motorStop(SH_Motor_Both, SH_Next_Action_BrakeHold);//Bank A 的Motor-1,Motor-2停止鎖死
   
   nxshield.bank_b.motorRunUnlimited(SH_Motor_1, SH_Direction_Reverse, 100);//Bank B 的Motor-1以馬力100轉,機器人將手臂全力往下上舉,把球收今去
   delay(300);
   nxshield.bank_b.motorStop(SH_Motor_1, SH_Next_Action_BrakeHold);//Bank B 的Motor-1停止鎖死

   nxshield.bank_a.motorRunDegrees(SH_Motor_Both, 
                     SH_Direction_Forward, 
                     30,
                     210, 
                     SH_Completion_Wait_For,
                     SH_Next_Action_BrakeHold);//機器人退回原位
   while(true){;}//無限迴圈當作程式的終點,方便觀察
   
}

 

實際運作的情形:

一、收取正方形區塊的物件

注意到影片中的機器人雖然一開始放得很歪,但是卻可以靠前面的導角來修正回來,是個可以參考的設計喔!

12

 

二、收取三角形區塊的物件

同樣的程式架構,也使用同樣的網子,只是改變了舉起手後機器人前進的角度,也是可以輕鬆入袋!

 

三、那如果網子裡面有上次的取得物件呢?

也是可以滿載而歸喔!

 

四、當然最安全的還是分開一次一次的收好啦

以上,希望透過這次一系列簡單的範例測試來吸引更多人一起來使用各種控制器來比這種開放是硬體的比賽,也預祝即將參賽的各位選手們比賽順利!

零件提供來源在這裡

[3/29_C-Day有什麼?]系列之二:手機遙控雙足機器人

本篇內容是由  CAVEDU 的實習生-黃筱晏提供的使用心得

介紹用二足步行機器人入門這本書做出的機器人

這裡是我們團隊買書的地方:機器人王國商城

01

依照書中作法做出的樣子如下

馬達一顆控制頭部用來改變重心,另一顆為前進後退

02

單一顆9V無法供應motoduino+馬達,所以要用外接電源

→把板子上的J5 移到Ext. Vin 的地方

03

電源馬達連接:

04

藍芽接法:

藍芽設定可以參造Cooper Maa

http://coopermaa2nd.blogspot.tw/2012/06/hc-0x-bluetooth-module.html

05

將motoduino及兩顆9v電池固定後:

06

 

改用motoduino控制馬達及藍芽,軟體方面使用app inventer2

Arduino程式:

const int Motor_E2 = 5;      // digital pin 5 of Arduino (PWM)   

const int Motor_E1 = 6;     // digital pin 6 of Arduino (PWM) 

const int Motor_M2 = 7;     // digital pin 7 of Arduino

const int Motor_M1 = 8;    // digital pin 8 of Arduino

char val; //variable to receive data from the serial port(bluetooth)

 

void setup()

{

  // initialize serial communications at 57600 bps:

  Serial.begin(57600);

 

  pinMode(Motor_M1, OUTPUT);

  pinMode(Motor_M2, OUTPUT);

  Serial.println("Start here");

}

 

void loop()

{

  if(Serial.available())

  {

    val = Serial.read();

    switch(val)

    {

      case 'f':   // car forward

                forward(0, 255);

                break;

      case 'b':   // car backward

                backward(0, 255);

                break;

      case 'l':   // car turn left

                left(0, 255);

                break;

      case 'r':   // car turn right

                right(0, 255);

                break;

      case 's':   // car stop

                motorstop(0, 0);

                break;

     

    }

  }

}

 

void motorstop(byte flag, byte motorspeed)

{

  Serial.println("Stop!");

  digitalWrite( Motor_E1, motorspeed);

  digitalWrite( Motor_E2, motorspeed);

 

}

 

void forward(byte flag, byte motorspeed)

{

  Serial.println("Forward!");

 

  digitalWrite( Motor_M1, HIGH);

  digitalWrite( Motor_M2, HIGH);

 

  analogWrite( Motor_E1, motorspeed);

  analogWrite( Motor_E2, 0);

 

}

 

void backward(byte flag, byte motorspeed)

{

  Serial.println("Backward!");

 

  digitalWrite( Motor_M1, LOW);

  digitalWrite( Motor_M2, LOW);

 

  analogWrite( Motor_E1, motorspeed);

  analogWrite( Motor_E2, 0);

  

}

 

void right(byte flag, byte motorspeed)

{

  Serial.println("Head Turn Right! ");

 

  digitalWrite( Motor_M1, HIGH);

  digitalWrite( Motor_M2, HIGH);

 

  analogWrite( Motor_E1, 0);

  analogWrite( Motor_E2, motorspeed);

 

}

 

void left(byte flag, byte motorspeed)

{

  Serial.println(" Head Turn Left!");

 

  digitalWrite( Motor_M1, LOW);

  digitalWrite( Motor_M2, LOW);

 

  analogWrite( Motor_E1, 0);

  analogWrite( Motor_E2, motorspeed);

 

}

app inventer2程式:

在程式初始化時,設定各元件可否點選

07

在 ListPicker 點選之前設定藍牙的配對裝置位址與名稱

08

當 ListPicker 被點選之後,對藍芽發起連線,若成功則設定各元件能不能點選。

09

當按下按鈕後,Android 手機會經由藍牙發送一個字元給Arduino

10

按下Button7時,斷開藍牙連線,各元件恢復成連線前的樣子。

11

在手機上顯示:

12

Finish:

13

零件提供來源在這裡

台北市校際盃公開賽(一)介紹

採訪小記者:袁佑緣

剛開學不久就馬上有一個機器人的比賽囉!

今天要來介紹的是台北市校際盃機器人選拔賽

2015年台北市校際盃選拔賽分為三種: 創意賽、挑戰賽、公開賽,(附上官方網站連結http://robot.thjh.tp.edu.tw/),參賽資格從國小到高中,報名時間從3/9(一)~3/13(五),大家要報名要快喔!

以下簡單介紹一下這三種比賽:

  • 創意賽: 主題「宜居城市」,配合2016台北設計之都政策,設計出關於「生命健康」、「生態永續」、「智能生活」、「都市再生」的機器人,且不限制任何的控制器與程式語言。
  • 挑戰賽: 題目「機器人駕訓班」,機器人將在比賽場地進行一系列的任務挑戰,任務是讓機器人模擬駕訓班考試一樣,有S型彎道挑戰、倒車入庫與路邊停車、過窄道與紅綠燈等,再加上許多的題型是當場宣布細則的,算是相當重視選手臨場的反應與動手操作,甚至是不能帶之前已經寫好的程式進場,非常挑戰選手們的臨機應變能力呢!

雖然國小組到高中組都是使用同一款場地,但是任務挑戰內容不盡相同,此外,挑戰賽有限制使用的控制器必須是LEGO® MINDSTORMS™,程式語言的部分則只有國小組限制必須使用ROBOLAB 或 LEGO® MINDSTORMS™軟體。

  • 公開賽: 今年新增的題目一樣是「機器人駕訓班」,基本規則跟挑戰賽相同,但是不再限制任何的控制器與程式語言。

 機器人駕訓班的比賽場地

01

以前類似的比賽幾乎都是LEGO® MINDSTORMS™的天下,大家不是用NXT就是EV3,既然今年新增了一個開放控制器的公開賽,那我們不妨來試試使用其他控制器來解題吧!

[Raspberry Pi 2]樹莓派2效能測試,使用Chrome 瀏覽器與 openCV

RaspberryPi 2號稱CPU效能比過去快上六倍,快六倍究竟是什麼樣的感覺呢?這次使用Linux系統的Google Chrome與opecncv這兩個需要消耗較大CPU運算來做測試。剛拿到樹莓派2的朋友們,要讓過去系統可以相容於Pi 2請看這篇

這次使用top指令來觀察Pi2的系統執行能力,首先輸入:

$top

002

出現上圖的視窗,以灰色的一行作分類,上半部顯示的是Pi2的四核心運算率,分別是:CPU0、CPU1、CPU2、CPU3,如果沒有出現,按數字鍵[1]即可

下半部顯示的是正在執行的命令,如果出現的資料太多,按下鍵盤的[i]鍵就會切換顯示方式

  • USER:顯示執行命令的帳號
  • %CPU:顯示CPU的使用率
  • %MEN:顯示記憶體的使用率
  • COMMAND:執行的命令名稱

讓我們來看看在Pi B+執行 Google Chrome 的速度如何?

我們可以看到執行 Chrome需要使用CPU 高達 70%的運算,在整個系統上資源使用量是排第一名,右下角的圖形化CPU也是整片都滿滿的綠色,代表CPU全部的使用率達百分之百。Pi B+只有CPU0可以進行運算,系統跑起來會LAG,如果要執行其他程式需要等待約一到數分鐘才能打開。

接著來看看Pi2執行 Chrome 又是如何?

如圖所見,這個瀏覽器開了兩個分頁,但是CPU只使用了百分之30,而且在運算上會分擔給四個CPU,所以每個CPU執行的速度還是很快,由於我還開了其他的程式,例如截圖軟體,所以Chrome在使用整個系統的資源量是排第七第八名。

接著來看看Pi B+執行OPENCV佔的資源如何:

CPU使用率佔百分之七十,系統使用資源量排名第一,不用說整個CPU圖片為滿滿的綠色。

接著看Pi2執行opencv

CPU使用為 59%,我們看看右下角,CPU使用量顯示,綠色居然沒超過四分之一,小編實地測試,使用Pi2時,opencv只要畫素高,經過計算會照成圖片顯示DELAY,但是總CPU使用量不會超過四分之一,應該是Pi2作業系統(OS)的使用預設是不會讓單一程式佔走大部分的運算資源,在使用時,不會讓使用者感覺系統LAG,經過測試,Pi2在需要較高運算的程式上,的確比之前的Pi快上許多。

目前CAVEDU 已經開始供貨給玩家囉,Raspberry Pi2售價是台幣1500元,Raspberry Pi B+是900元,Raspberry Pi B 降價成500元!!歡迎到我們的FB粉絲頁商城訂購~~

[Raspberry Pi 2]樹莓派2來了!!開箱文~

樹莓派2來到CAVEDU了!!趕緊來看看~

一拿到這次的樹莓派外盒覺得變比較重,盒子的厚度也比想像的大,盒子的外觀也和第一代的Pi不同,樹莓的背後寫了一個大大的2

20150209_151230

相關文章

Raspberry Pi 相關產品購買

Raspberry Pi 樹莓派2專用觸控螢幕開箱文-組裝篇

[Windows IoT on Raspberry Pi 2] 下載 Windows 10 Preview 與 燒錄 Raspberry Pi 映像檔

[Windows-IoT-on-Raspberry-Pi-2] 使用-PowerShell-連接及部署您的Windows-IoT-Core設備

[Windows 10 IoT ] Raspberry Pi 網頁遙控檯燈

Continue reading

[Electric Imp 物聯網小惡魔教學] 溫濕度感應計

本篇內容是由  CAVEDU 的實習生-呂東翰使用Electric Imp學習溫溼度感應器的心得,讓我們一起來看看

這個禮拜從老闆那拿到一顆imp單晶片,小弟是對於電子晶片實在是沒什麼FEEL,一時之間實在想不出這顆小惡魔到底能做些什麼,好在imp的開發網站有好多的範例可以玩,這次就用這顆小惡魔搭配溫溼度感測器試著做一個簡單的測試吧!

硬體設備:

Electric IMP *1                                                      DHT11            *1

01  03

麵包板            *1                                                      USB線            *1

02  04

電源            *1                                                          1kΩ 電阻       *1

06  05

電線         *5

07

接線方式:

這張圖是小惡魔與DHT11的接腳圖,如果你的小惡魔的前置環境建置已經設定好,那就可以將小惡魔與DHT11插在麵包板上,照著圖示接線囉,接線的時候要注意DHT11有洞的那面是參考面,不要插錯了。

08

(參考圖源)

需要:

  1. 一台智慧型手機
  2. 到APP商店下載Electric imp的程式,安裝並執行
  3. 到官網申請帳號
  4. 模組起始設定-BlinkUp(注意一定要用手指蓋住接收訊號的那一端,不然會因為光源的干擾而失敗喔)

我們的重點不在這,如果你還有疑問,可以到electric imp的官方網站看詳細的設定說明或參考我們上一篇文章[Electric Imp 物聯網小惡魔教學] 環境建置與 BlinkUp app。前置作業完成後,就可以接線囉。

 

接下來我們要小惡魔的開發網站找裝置DHT11的使用範例:

STEP1:到小惡魔的官網,案右上方進入DEV CENTER,進入後可以看到下圖的網頁,這裡是初學者學習如何設計與開發小惡魔的寶藏庫阿,如果對於小惡魔的使用與開發有任何疑問的話,在這裡幾乎都可以找到解決的方法。

09

STEP2:因為小弟我是完全的新手,所以我選右邊的Sample Code,先找找有什麼比較容易的設計可以玩吧,進入後可以看到以下的網頁。

10

STEP3:這次要做的是有關硬體的類別,我選擇Ready-To-Use Classes的Hardware Drivers,進入後可以看到很多別人測試過的裝置,竟然還有人測試Nokia 5110的LCD面板耶真有趣,再往下拉找到Sensors類別的Aosong DHT11的範例,就是我們這次要做的目標。

11

STEP4:找到Aosong DHT11(如下圖)後點擊Class Electric Imp’s Github Repo 就會看到完整的範例檔案囉,接線圖跟程式都有。

12

STEP5:最後將程式碼複製到Device就完成囉,接著小弟我便帶著小惡魔溫濕感測器到房間的不同角落測試溫度與濕度,DHT11測到的數值就會透過小惡魔顯示在Device Logs視窗內囉,雖然在同一個空間內,但濕度還是有些微的差異的喔。

13

有關程式碼的部分,一開始看到程式碼有一長串看不懂的代碼,實在是有點小畏懼阿,好在經過阿吉大大與偉哲大大的講解後,發現前面的程式碼是讀取DHT11資料封包的細節與物件導向的變數設定,偵測溫溼度的程式是從172行的function loop的程式迴圈開始,相關的解釋都寫在註解上:

 

function loop() {

    imp.wakeup(INTERVAL, loop);

    local data = dht11.read();  //讀取DHT11

    server.log(“Running “+imp.getsoftwareversion()+”, Free Memory: “+imp.getmemoryfree());

//在Device Log視窗顯示Running+imp版本+記憶體剩餘量

    server.log(format(“Relative Humidity: %0.1f”,data.rh)+” %”);

                                //在Device Log視窗顯示濕度(以浮點顯示到小數點後一位)

    server.log(format(“Temperature: %0.1f C”,data.temp));

}                               //在Device Log視窗顯示溫度(以浮點顯示到小數點後一位)

spi         <- hardware.spi257;

clkspeed    <- spi.configure(MSB_FIRST, SPICLK);

 

dht11 <- DHT11(spi, clkspeed);

loop();

 

 

 

 

Raspberry Pi 教學-使用網路線讓電腦與樹莓派進行連線(For Mac OS X)

本篇內容是由cavedu的實習生-袁佑緣使用MAC學習樹莓派的心得,用網路線將樹莓派與MAC連接再一起,使用MAC內建的終端機就可以控制樹莓派,讓我們一起來看看~

事前準備工作可以參考Raspberry Pi 教學-燒錄SD卡(For Mac OS X)

試問使用這一個方法究竟有什麼好處?好處是:

1、不需要為樹莓派連接一個螢幕

2、不需要為樹莓派另外接鍵盤、滑鼠

3、樹莓派上網可以直接透過筆電的網路進行上網,不需要另外接網路線或使用WIFI連線

一、設定Mac與Raspberry Pi連線設定

1.將燒好的SD卡插入Raspberry Pi,並將網路線兩端接上Mac與Raspberry Pi,然後插上電源開機,這時候你會看到Raspberry Pi的指示燈有四顆亮著:PWR,FDX、LNK、100,PWR是3.3V電源而其他三個是跟網路相關,另一顆在閃爍的ACT是SD卡讀寫。

2.設定Mac的網路連線:System Preferences -> Network,左欄選擇Ethernet,右欄設定Using DHCP,上面Location設定Automatic,等一陣子後就能看Status變成Connected,這樣就代表連上Raspberry Pi囉!

Rpi_mac05

 

3.設定Mac的網路分享:System Preferences -> Share,在這裡要分成兩個case

(1)如果你處在沒有無線網路的環境下,那就選擇從Ethernet分享到Ethernet

Rpi_mac06

(2)如果你處在有無線網路的環境下,那就可以選擇從Wifi分享到Ethernet,

這樣一來你的Raspberry Pi就可以透過這條網路線上網,相當於你真的接上一條數據機分出來的網路線!

Rpi_mac07

 

4.獲得Raspberry Pi的IP

先安裝mac port(官方安裝網址),安裝完後,

再開啟終端機,輸入指令:sudo port install nmap,安裝Nmap這款網路掃描工具,

完成後再在終端機輸入指令:ifconfig,如下圖並注意下面框起來的IP(192.168.2.1),也就是我們Mac的IP

Rpi_mac08

現在我們必須去掃描DHCP分配給Raspberry Pi的IP,通常是192.168.2.XXX,於是我們使用剛剛安裝的nmap,

在終端機中輸入指令:nmap -sn 192.168.2.1-255 ,從1掃到255如下圖我們掃到了一個IP(192.168.2.22),

這個IP就是Raspberry Pi的IP

Rpi_mac09

5.透過ssh連上Raspberry Pi

接下來讀者只要透過ssh(Secure Shell)遠端連線上Raspberry Pi,就可以在Mac上使用Raspberry Pi了,

首先在終端機裡輸入指令:ssh pi@”剛剛搜到Raspberry Pi的IP”,pi是預設的使用者帳號,範例如下:ssh pi@192.168.2.22,出現問你要不要連線時,輸入yes,然後輸入預設的密碼raspberry

Rpi_mac10

 

如果你的終端機顯示pi@raspberry~$,代表你已經成功與樹莓派進行連線,可以對樹莓派進行控制,如果你對只有使用終端機控制樹莓派感到困難,只要你知道樹莓派的IP,你也可以尋找有GUI介面的連線程式,這樣就更加貼近你平常使用的樹莓派囉~~

Raspberry Pi 教學-燒錄SD卡(For Mac OS X)

本篇內容是cavedu實習生-袁佑緣使用MAC學習樹莓派的心得,使用Mac內建的終端機就可以燒錄樹莓派的IMG檔案到樹莓派,我們一起來看看吧~~

一、準備材料:

1.Raspberry Pi BB+

2.下載最新Raspbian作業系統的映像檔(官方版本)(cavedu樹莓派opencv版本)

3.一張容量大於4GBSD卡(使用opencv版本容量最少需要8G)

4.網路線(於網路連線和電腦連線時使用)

5.micro USB傳輸線+USB充電器

Rpi_mac01

二、燒錄Raspbian映像檔

1.SD卡插入mac筆電

2.在mac的系統程式開啟終端機(Termminal)

3.輸入指令:diskutil list,查詢筆電的硬體狀態,列出如下圖的表

Rpi_mac02

 

這個表會列出這台mac筆電所擁有的硬碟,也包括Mac筆電內建的SSD固態硬碟

 

我們所使用的是16GBSD卡,上表所顯示的記憶體容量可以判斷disk1是SD卡,而它的位置為/dev/disk1,請記下這個位置

4.輸入指令:diskutil unmountDisk “SD卡的位置,將SD卡卸除,

例如:diskutil unmountDisk /dev/disk1

Rpi_mac03

 

5.輸入指令:sudo dd if=”要燒錄的映像檔的位置“ of=”SD卡的位置” bs=2m,將映像檔燒進去SD卡,

dddisk dumpifinput fileofoutput filebsblock size

    小技巧1:要得到燒錄的映像檔的位置可以直接將.img檔的圖示拖曳進終端機裡就可以了

    小技巧2dd指令通常都需要等一段時間,而且終端機的畫面會一直停留在那裏,請大家稍安勿躁,千萬不要以為它失敗就強制取消!但如果想要加快燒進去的速度的話,可以將“disk“改成“rdisk”rraw的意思,原理是raw disk會有較高的讀寫速度

例如:sudo dd if=~/Desktop/2014-12-24-wheezy-raspbian.img of=/dev/rdisk1 bs=2m ,幾分鐘後便燒錄完成了!

Rpi_mac04

 

下一篇是使用網路線讓筆電可以直接控制樹莓派,敬請期待~~~

Scratch設計:射擊遊戲:火龍鬥勇者

這次分享的是之前製作的專題-火龍鬥巫婆,這次讓這個射擊遊戲增加了主角可以累積必殺技量表,發射必殺技

圖片2

除了發射必殺技之外,火龍的攻擊也有普通攻擊,每擊敗一隻巫婆就可以一點累積能量表

圖片1

累積量表是使用Scratch的畫筆功能,在想要的座標點上面往右邊畫一條線,每每積一點就畫一截

累積滿五點的時候,必殺技量表彙編成紅色的,並且不會再累計能量表

圖片3

圖片4

 

火龍按下鍵盤的上移鍵發出大絕招

圖片6

當巫婆碰到火龍的普通攻擊或必殺攻擊就會被消滅

圖片5

 

 

下載的檔案在這邊-火龍鬥巫婆

下次再繼續分享相關的功能~~~

python on EV3 機器人-使用超音波感測器偵測與障礙物之間的距離

這次分享的內容,是由Python開啟EV3的超音波偵測,為了確定有確實的開啟超音波感測器,

我們設定讓EV3的兩組馬達前進十秒鐘,在這10秒內,如果超音波偵測前方15公分內有障礙物,

則立即停止馬達的旋轉。

3_2_python

以python on EV3 機器人-使用python控制EV3馬達為基礎,改編的超音波感測器程式碼,改編內容如下

3_10_python

(1)在輸入ev3.lego的模組中,新增UltrasonicSensor的功能

(2)新增python內建的time模組

(3)宣告超音波模組接入的孔為 一號孔

(4)在while迴圈設定10秒後跳出

(5)印出超音波感測器量測的距離

(6)如果量測距離校於150mm馬達停止,大於的話馬達繼續前進

檔案撰寫完畢後,首先將撰寫好的檔案傳送至EV3之中,以下是使用Cyberduck的SFTP模式傳送檔案,使用者帳號為:root,密碼為r00tme,密碼的0是數字零

3_3_python

 3_5_python

傳送完檔案後,使用putty連線到EV3並執行檔案,使用者帳號為:root,密碼為r00tme,密碼的0是數字零

3_7_python

執行結果如下:

3_8_python

有人或許會問,傳送檔案不能用putty傳送嗎?其實是可以的,不過小編在這推薦cyberduck另外做檔案傳輸,

因為使用putty傳送檔案需要指定檔案的名稱、傳送檔案和被傳送檔案的路徑才能完成。

相較之下,cyberduck只需要把想傳送的檔案拖曳到想放置的地方即可,十分方便。

喜歡都用指令控制的朋友也可以用puuty的SCP方法傳送檔案,或是直接在EV3的環境撰寫python檔案喔

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進行檔案傳輸了

馬上來體看看吧~

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

本篇暫時不會連線EV3,想學習python,卻沒有學習過的人,

可以參考這篇文章進行練習,體驗一下python的功能。

還沒有安裝python的人,可以到官方網站進行下載,本篇以windows系統python2.7進行分享。

安裝程式完畢後,進入[開始]列表的[python27]點選[IDLE(python GUI)],進入python介面。

1_1

這是python直接執行命令的地方,開一個新的文字檔案,進行比較長的文字編寫

對python不熟的人可以練習這三段程式碼體驗python,之後將會以這三個範例為基礎,改為控制EV3的馬達

1、體驗輸入文字,電腦會輸出文字並重複十次

1_3

接著F5執行這段檔案,執行結果如下:

1_4

2、對輸入的文字進行判斷,輸入yes時,會進行特定的回答

1_5

按下F5,執行後:

1_6

3、讓電腦可以對複數的回答進行回應,無窮迴圈while中,輸入”end”可以跳出迴圈

1_7

按下F5,執行後:

1_8

141220_RaspberryPi樹莓派研習營 使用GPIO控制外接電路@未來廠房

樹莓派研習營已經進入倒數第二週了,上週使用Webcam,

掛載opencv讓樹莓派可以進行視覺辨識這週進入GPIO的實戰教學,

本週讓少接電路的學員挑戰控制LED燈的明亮、讀取按鈕是否被按下

還讓樹莓派使用馬達外接晶片L293D,控制直流馬達前進後退!!

首先在樹莓派掛載python專用的GPIO函式庫RPi.GPIO

$sudo apt-get install RPi.GPIO

接著體驗由樹莓派晶片進行的腳位輸出

141222_1

 

再來體驗由樹莓派的針腳高電位與低電位,判斷是否按鈕按下

141222_2

 

 

將以上兩個範例結合,就能直接按按鈕控制LED燈亮案囉

141222_3

 

接著進入樹莓派控制直流馬達,一般控制直流馬達會以PWM訊號為主,

不過實際體驗過後會發現,單單以晶片的供電是很難讓馬達正常的運轉

141222_4

 

 

這時候使用L293D晶片控制馬達,讓我們能夠從外部給予電源供應,樹莓派則是提供

是否讓外部電源給電與停止供電,L293D晶片總共有四個腳位輸入、四個腳位輸出

讓我們最多可以控制四個馬達,這次是使用兩個輸入輸出腳位控制直流馬達正轉或反轉

141222_5

 

 

最後一週會使用機械手臂進行控制伺服馬達的教學,經請期待~