置頂文字

歡迎來訪 !! 如有任何問題歡迎一起討論或是 eMail 給我 legorunmail@Gmail.com

2015年12月27日 星期日

Arduino 循跡智慧車、遙控車與Android智慧手機藍芽控制



用Arduino DIY做玩具是個很有趣的題目,既能學到組裝結構又能學習程式設計一舉兩得,看到車子沿著黑線前進遇到障礙物就自動停住跟買現成的玩具遙控車有著很不一樣的感受,跟小孩一起玩小孩也很有興趣學習。

需要的組件如下:

1.Arduino Uno 相容版。
2.藍芽 HC-06 接收與傳送訊息至Android手機
3.LED全彩燈球可以顯示循跡車狀態
4.兩顆1:48 DC馬達與輪組作為驅動力
5.萬向輪
6.L298N馬達驅動板,控制馬達正反轉與速度PWS變化
7.超音波感應器 HC-SR04讓循跡車能感應前方是否有障礙物
8.尋跡模組 TCRT5000 紅外線反射感應器,用來分辨黑白線

9.樂高Technic標準孔支架作為循跡車主結構












2015年12月24日 星期四

Arduino 機械手臂準備資料

進入Arduino通常都會作些自己有興趣的項目,例如循跡自走車、藍芽遙控車、Wifi無線網路等,這些都做過後下一個目標就是機械手臂Robot Arm,當然先從資料收集準備起。

86Duino

機械手臂介紹01  組裝過程介紹 

資料裡面提到Servo的定位要參考各種規格的差異性,在組裝前Servo要先定位不要拿到零件就開始組裝,電源供應要注意穩定性。


YouTube上有趣的應用

2015年12月18日 星期五

實做Arduino + ESP8266 WIFI無線模組與Android手機互動










接上電源準備起動 ESP8266 無線 WIFI 模組
當Arduino ESP8266 接上家中WIFI 路由器時取得DHCP 192.168.1.54,另外ESP 8266 AP模式的固定IP 192.168.4.1



螢幕顯示ESP8266 監聽Port 8015,這就是Android手機與ESP8266溝通Port

實際測試:Android手機直接連接ESP8266 AP模式 192.168.4.1 Port8015 並送出red訊息,
當Arduino收到red後把LED切到紅色



實際測試:Android手機直接連接ESP8266 AP模式 192.168.4.1 Port8015 並送出green訊息,
當Arduino收到green後把LED切到綠色


實際測試影片






2015年12月4日 星期五

Android 與Arduino 資料交換方式

當你想要從手機發送訊息給Arduino或想從Arduino收到回傳訊息時都必須知道如何使用DataInputStream /  DataOutStream

Example01  Example02

android的網路資料交換分為2種:基於socket的,和基於http協定的。

自己玩Android 與Arduino不論是透過藍芽 HC-05、HC-06或是無線網路ESP8266 都是用Socket方式來做資料交換。網路上這篇文章說明很清楚值得大家參考

基於socket的用法


  伺服器端:-----------------------------------------------------------------------------------------

  先啟動一個伺服器端的socket ServerSocket svr = new ServerSocket(8989);

  開始偵聽請求         
        Socket s = svr.accept();

  取得輸入和輸出
  DataInputStream dis = new DataInputStream(s.getInputStream());

  DataOutputStream dos = new DataOutputStream(s.getOutputStream());

  Socket 的交互通過流來完成,即是說傳送的位元組流,因此任何檔都可以在上面傳送。

        誰打開的記得要關上。

  用DataInputStream/DataOutputStream來進行包裝是因為我們想要他們對基底資料型別的讀寫功能readInt(),writeInt(),readUTF(),writeUTF()等等。

  用戶端:-----------------------------------------------------------------------------------------

  發起一個socket連接      
        Socket s = new Socket("192.168.1.16",8015);

  取得輸入和輸出
     DataInputStream dis = new DataInputStream(s.getInputStream());
  DataOutputStream dos = new DataOutputStream(s.getOutputStream());

  之後就可以相互通信了。誰打開的記得要關上。


 InputStream is = new FileInputStream("test");
    //暫存BYTE陣列
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    //緩衝
    byte buffer[] = new byte[512];
    //紀錄讀進來長度
    int length = 0;
    //假如等於-1代表沒有資料了
    while( (length = is.read(buffer)) != -1){
            //從緩衝區讀取buffer裡面0~length-1的位置
            baos.write(buffer, 0, length);
    }
    //ByteArrayOutputStream轉成位元陣列
    byte data [] = baos.toByteArray();
    is.close();
    baos.close();





基於Http協定


  一般是發送請求到某個應用伺服器。此時需要用到HttpURLConnection

  先取得HttpURLConnection urlConn = new URL("http://www.google.com").openConnection();

  設置標誌 

    urlConn.setDoOutput(true); urlConn.setDoInput(true);//post的情況下需要設置DoOutput為true

    urlConn.setRequestMethod("POST");

    urlConn.setUseCache(false);//設置是否用緩存

    urlConn.setRequestProperty("Content-type","application/x-www-form-urlencoded");//設置content-type

  獲得輸出流,便於想伺服器發送資訊。

    DataOutputStream dos = new DataOutputStream(urlConn.getOutputStream());

  望流裡面寫請求參數

    dos.writeBytes("name="+URLEncoder.encode("chenmouren","gb2312");

    dos.flush();dos.close();//發送完後馬上關閉。

  獲得輸入流,取資料

    BufferReader reader = new BufferedReader(new InputStreamReader(urlConn.getInputStream()));

    reader.readLine();//用 !=null來判斷是否結束

    reader.close();

  讀完了記得關閉connection  urlConn.disconnect();


//-----------------------------------------------

import java.io.*;
import java.net.*;

public class client
{
 public static void main(String [] argv)throws IOException
 {
  StartClient(1234);
 }
 public static void StartClient(int port)
 {
  try
  {
   //設定連線的主機位置
   InetAddress add = InetAddress.getByName("ecc.johnsonlu.org");
   SocketAddress sc_add= new InetSocketAddress(add,port);
   Socket sc = new Socket();
   int timeout = 2000 ; //timeout 2秒
   System.out.println("連線中....");
   //與主機連線
   sc.connect(sc_add,timeout);
   System.out.println(sc.getLocalAddress() + "連線到" + sc.getInetAddress());
   
   //傳送資料到Server端
   DataOutputStream out = new DataOutputStream(sc.getOutputStream());
   out.writeUTF("我是Client");
   out.flush();
   
   //接收Server端資料
   DataInputStream in = new DataInputStream(sc.getInputStream());
   System.out.println("Server:" + in.readUTF());
   
   
  }
  catch(SocketTimeoutException e)
  {
   System.out.println("Timeout");
  }
  catch(IOException e)
  {
   e.printStackTrace();
  }
 }
}






//----------------------------------------------
Client:
try{

Socket socket = new Socket(mDestinationIP,mDestinationPort);

DataInputStream dataInputStream = new

            DataInputStream(socket.getInputStream());

int data;
//read data from server

while ((data=dataInputStream.read()) != -1) {
            //do sth
}

} catch (IOException e){
            //handle socket IOExceptions
}

Client Buffered data streaming
try{

Socket socket = new Socket(mDestinationIP,mDestinationPort);
BufferedInputStream bufferedInputStream = new
 BufferedInputStream((socket.getInputStream());
int data;
//read date from server

while ((data= bufferedInputStream.read()) != -1) {
            //do sth
}

} catch (IOException e){
            //handle socket IOExceptions
}

//---------------------------------------


import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class AndroidClient extends Activity {

EditText textOut;
TextView textIn;

 /** Called when the activity is first created. */
 @Override
 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.main);
  
     textOut = (EditText)findViewById(R.id.textout);
     Button buttonSend = (Button)findViewById(R.id.send);
     textIn = (TextView)findViewById(R.id.textin);
     buttonSend.setOnClickListener(buttonSendOnClickListener);
 }

 Button.OnClickListener buttonSendOnClickListener
 = new Button.OnClickListener(){

@Override
public void onClick(View arg0) {
 // TODO Auto-generated method stub
 Socket socket = null;
 DataOutputStream dataOutputStream = null;
 DataInputStream dataInputStream = null;

 try {
  socket = new Socket("192.168.1.101", 8888);
  dataOutputStream = new DataOutputStream(socket.getOutputStream());
  dataInputStream = new DataInputStream(socket.getInputStream());
  dataOutputStream.writeUTF(textOut.getText().toString());
  textIn.setText(dataInputStream.readUTF());
 } catch (UnknownHostException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 } catch (IOException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 finally{
  if (socket != null){
   try {
    socket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  if (dataOutputStream != null){
   try {
    dataOutputStream.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  if (dataInputStream != null){
   try {
    dataInputStream.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }
 }
}};
}



2015年12月1日 星期二

Arduino 字串處理

Serial.begin(9600);
  String str="Hello World!";
  Serial.println(str.length());    //輸出 12
  Serial.println(str.indexOf(" "));        //輸出 5 (有找到傳回索引)
  Serial.println(str.indexOf(" ", 6));    //輸出 -1 (沒找到傳回 -1)
  Serial.println(str.lastIndexOf("!"));  //輸出 11
  Serial.println(str.substring(6));         //輸出 World!
  Serial.println(str.substring(0,7));      //輸出 Hello W
  str.replace("World","Tony");           
  Serial.println(str);                              //輸出 Hello Tony!
  str.concat(" Good Day!");               
  Serial.println(str);                              //輸出 Hello Tony! Good Day!
  str.remove(16);                                  //從 Day 前面空格開始刪
  Serial.println(str);                              //輸出 Hello Tony! Good
  str.remove(11,5);                               //從 G 前面空格開始刪
  Serial.println(str);                              //輸出 Hello Tony!
  str.toLowerCase();                           
  Serial.println(str);                              //輸出 hello tony!
  str.toUpperCase();                   
  Serial.println(str);                              //輸出 HELLO TONY!
  Serial.println(str.charAt(1));             //輸出 E
  str.setCharAt(5,'+');                           //將空格改為 +
  Serial.println(str);                              //輸出 HELLO+TONY!
  String str2="Hello+Tony!";
  Serial.println(str.equals(str2));          //輸出 0
  Serial.println(str.equalsIgnoreCase(str2));    //輸出 1
  Serial.println(str.compareTo(str2));  //輸出 -32 (不同,  str 在前)
  Serial.println(str.compareTo("HELLO+TONY!"));   //輸出 0 (雷同)
  Serial.println(str.startsWith("HELLO"));   //輸出 1
  Serial.println(str.endsWith("TONY!"));     //輸出 1
  str=" HELLO ";
  str.trim();
  Serial.println(str.length());   //輸出 5 (已刪除前後空格)
  str="180 Days";
  Serial.println(str.toInt());     //輸出 180
  str="65.245KG";
  Serial.println(str.toFloat());  //輸出 65.25 (四捨五入到小數第二位)

2015年11月25日 星期三

Android 手機與Arduino 藍芽HC-05 / 06 連結應用

讓Android、iPhone手機與Arduino連結交互應用是很有趣的程式設計,因此有些要注意的地方就留下紀錄

首先是Arduino部分

網路資源  搜尋藍芽裝置  網路資源   Arduino送資料給手機接收   收機接收資料

藍芽搜尋  藍芽傳送程式  透過藍芽上傳程式02

Arduino 資料型態   執行序資料傳遞  執行序Run與Start差異性

透過藍芽燒縙Arduino 程式取代USB


Part 1

#include
#include
#include 2C
.h>


#define MAX_BTCMDLEN 128

// 建立一個軟體模擬的序列埠
// HC-06    Arduino
// TX       RX/Pin10
// RX       TX/Pin11
SoftwareSerial BTSerial(10,11); // Arduino RX/TX

// Addr, En, Rw, Rs, d4,d5,d6,d7 backlight, polarity
LiquidCrystal_I2C lcd(0x27,2,1,0,4,5,6,7,3,POSITIVE); 

byte cmd[MAX_BTCMDLEN]; // received 128 bytes from an Android system
int len = 0; // received command length

void setup() {
    Serial.begin(9600);   // Arduino起始鮑率:9600
    BTSerial.begin(9600); // HC-06 出廠的鮑率:每個藍牙晶片的鮑率都不太一樣,請務必確認
   
    // 初始化LCD1602
    lcd.begin(16, 2);
    lcd.clear();
    lcd.backlight();
}

void loop() {
    char str[MAX_BTCMDLEN];
    int insize, ii;  
    int tick=0;
    while ( tick// 因為包率同為9600, Android送過來的字元可能被切成數份
        if ( (insize=(BTSerial.available()))>0 ){  // 讀取藍牙訊息
            for ( ii=0; ii
                cmd[(len++)%MAX_BTCMDLEN]=char(BTSerial.read());
            }
        }
        else {
            tick++;
        }
    }
    if ( len ) { // 用LCD1602顯示從Android手機傳過來的訊息
        sprintf(str,"%s",cmd);
        // Serial.println(str);
        // 將對串列埠的輸出改為對LCD1602輸出
        lcd.clear();
        lcd.print(str);
        cmd[0] = '\0';
    }
    len = 0;
}

---------------------------------------------------------------------------------------------

Part 2
//-------------------------------------------------------------
// Controlling a servo position using serial port 
// Controlling a 360 continuous rotation servo using bluetooth
// 2015.02.04
// by gsyan  
//-------------------------------------------------------------
#include  

long serialBaudRate = 115200;         //藍牙(序列埠)通訊的速率(鮑率 baud rate)

int rightPin = 9; //右邊 servo 控制腳接在哪一個腳位
int leftPin = 10; //左邊 servo 控制腳接在哪一個腳位

//底下角度的值必須自行測試, 依 servo 來設定
int rightStopAngle = 95; //右邊 servo 停止轉動的值
int leftStopAngle = 106; //左邊 servo 停止轉動的值
int maxAngle = 75; //正轉、逆轉(加減)最大的值

const int delayMilliseconds = 20; // 每隔多少 MS 讀取一次資料

Servo rightServo;   // create servo object to control right servo 
Servo leftServo; // create servo object to control leftt servo 

int angle = 0; //記錄目前 servor 動力的值(真正給 servo 的值還會加上 rightStopAngle或leftStopAngle

//讓兩顆 servo 停止
void servoStop() {
  rightServo.write(rightStopAngle);
  leftServo.write(leftStopAngle);
} 
//讓兩顆 servo 暫停指定的時間
void servoPause(int t) {
   servoStop();
   delay(t);
}  

//初始程序    
void setup() 
{ 
  Serial.begin(serialBaudRate); //Arduino起始鮑率:38400
  
  rightServo.attach(rightPin);  // attaches the servo on pin "rightPin" to the right servo object 
  leftServo.attach(leftPin); // attaches the servo on pin "leftPin" to the left servo object 
  angle = 0;
  servoStop();
} 

//循環執行的程序
void loop() 
{ 
  byte inBytes[20]; //暫存所有外部傳來資料用
  byte inByte; //暫存用
  int inSize; //計算已取得多少資料用
    
  if ((inSize=(Serial.available()))>0){  //讀取藍牙訊息
    for (int i=0; i
      inByte = Serial.read();
      if(i<19 div="">
        inBytes[i] = inByte;
      }
    }
    //執行指定的動作 F(前進)、f(後退)、t(右轉)、T(左轉)和 S(停止)
    switch(char(inBytes[0])) {
      case 'F' :    //Forward
        if(angle > 0) {
          servoPause(500);
        }
        angle = -1*maxAngle;
        rightServo.write(rightStopAngle+angle);
        leftServo.write(leftStopAngle-angle);
        break;
      case 'f' :    //Backword
        if(angle < 0) {
          servoPause(500);
        }
        angle = maxAngle;
        rightServo.write(rightStopAngle+angle);
        leftServo.write(leftStopAngle-angle);
        break;
      case 'T' :    //Left turn
        servoPause(500);
        angle = -1*maxAngle;
        rightServo.write(rightStopAngle+angle);
        leftServo.write(leftStopAngle+angle);
        break;
      case 't' :    //Right turn
        servoPause(500);
        angle = maxAngle;
        rightServo.write(rightStopAngle+angle);
        leftServo.write(leftStopAngle+angle);
        break;
      case 'S' :    //stop
        servoStop();
        break;
      default :    //others: stop
        servoStop();
        break;
      
    }
  }  
  
  delay(delayMilliseconds);        // 暫停多少 MS 後繼續
  
} 

Arduino 與無線WIFI ESP8266 使用

Arduino 與無線WIFI ESP8266 使用

參考文章   參考文章  ESP8266與Android溝通   ESP8266與Web應用  ESP8266

克里斯遊戲自己做文章  ESP8266-12應用  DIY想像力Blog

ESP8266設定AP   ESP8266Code  ESP8266 AT Command

資料上傳到Web

這幾篇文章寫的太好了幾乎ESP8266的問題從接線、設定到韌體升級都寫的非常詳細,照著做幾乎都能成功。

3.3V電源供電的方式很多,我是從Arduino UNO 3.3V供電升級韌體,Baud Rate設成9600
注意事項:韌體升級要求的電源比較嚴格,我用Arduino UNO 3.3V一孔拉出2條接ESP8266在RealTerm執行 AT Command都沒問題,但韌體升級就會出現無法連接的錯誤訊息,後來用3.3V電源才能正常升級。


常用AT Command如下

AT ------------------->回應OK代表連線正常
AT+GMR----------->取得目前的韌體版本號碼


ESP8266的Wifi連線有三種模式:
  1. Station模式:扮演連線到現有Wifi的裝置。
  2. AP模式:扮演無線基地台,提供Wifi環境供連線。
  3. Station+AP混合模式:允許同時使用以上兩種模式的特有功能
取得目前Wifi連線模式:
指令「AT+CWMODE」
「AT+CWMODE?」查詢當前模式
「AT+CWMODE=2」將模式設定為第2種(AP模式)。

指令「AT+CWLAP」
顯示可連線的Wifi網路清單。

指令「AT+CWJAP」
「AT+CWJAP=,」連線到已存在的無線網路。
「AT+CWJAP?」查詢已連線到的無線網路。
:無線網路的識別名稱(要加引號)。
:無線網路的密碼(要加引號)。
如果需要切斷 Wifi連線,我們可以也可使用這個指令:
指令「AT+CWQAP」
切斷已連線的無線網路。 




一鍵燒錄更新軟體   GITHUB


測試ESP8226與電腦連線使用TelNet方式

如果你想使用自己設定的Port 可以用Telnet方式來測試
1.先把ESP8226連上WIFI設備
 Wifi連線模式設為 Station模式:AT+CWMODE=1   確認OK

2.列出目前的Wifi清單:AT+CWLAP
請先看是否有目標 wifi名稱出現

3.準備與WIFI連線:AT+CWJAP="PALMONE","123456789"  確認OK

4.如果連線成功 AT+CIFSR 會有一組IP:192.168.1.185  如果沒連上WIFI回傳IP:0.0.0.0

5.把ESP8266當Server端讓筆電連上:把ESP多重連線打開 AT+CIPMUX=1 確認OK

6.ESP8266 開啟伺服器與Port :AT+CIPSERVER=1,8087  ,Port:8087 確認OK

以上步驟ESP8266就準備完成等待Client端請求連線

筆電部份:
我是用MacBook 
1.先連上與ESP8266相同的WIFI,這動作讓筆電與ESP8266在同一網域,不同網域請先設定的路由器讓不同網域可以溝通

2.打開超級終端機 Ping 192.186.1.185 你會看到回應訊息代表IP位置存在

3.在超級終端機輸入telnet 192.168.1.185 8087  連線,如果成功ESP8266會出現Link訊息

4.測試訊息傳送在ESP8226這邊AT+CIPSEND=0,5 表示跟第1個連線裝置溝通 長度5,ESP8266最多同時能跟5個Client連線代碼 0 ~ 4

5.輸入Hello字串按Send ASCII鈕,接著在筆電的電超級終端機會收到Hello這5個字串顯示,代表ESP8266與筆電可以互傳訊息了


前前後後花了3天重複閱讀克里斯的文章與執行步驟,先幫ESP8266更新韌體把Baud Rate設成9600


非常感謝網友克里斯對 ESP8266 各種疑難雜症的分享與解釋讓我能順利的測試成功,不然像我這種對電子學完全不懂得門外漢是不可能理解 ESP8266每支腳位的代表意義

Arduino 程式
#include "ESP8266.h"
#include 

SoftwareSerial mySerial(3, 2); /* RX:D3, TX:D2 */
ESP8266 wifi(mySerial);
ESP8266_TX->RX(D3)
ESP8266_RX->TX(D2)
ESP8266_CH_PD->3.3V
ESP8266_VCC->3.3V
ESP8266_GND->GND