RoBoard魔人的機器人日誌

2016/2/11

[86Duino] 機器人動態同步的物聯網應用

今天本魔已將先前提到的機器人動態同步上傳至Github,
當環境都架設好之後便可以使用,
而機器人動態同步的主系統為ROS,
所以在Linux上架設好ROS環境後,
開啟ROS Serial Server,
讓所有機器人連線到同一區域網路下,
確認所有機器人皆連到主機後,
就可以開始同步動作啦~。



而這機器人分別是史加納以及86小六足,
在此奉上它們的開源Github,
要做幾隻就做幾隻,
只要WIFI AP夠強,
要做一整個小巨蛋的小六足跳舞也不是問題呢XD
Github中已有編好的妖怪舞給各位做為範例!
86Hexapod: https://github.com/roboard/86Hexapod
86小六足
Skarner: https://github.com/RoBoardGod/Robot-Skarner
史加納(偽娘型態)






而史加納與86小六足接線圖也請參考下圖:
86Hexapod for 86Duino Zero
86Hexapod for 86Duino One

Skarner for 86Duino One





Share:

2016/2/2

[86Duino] 在SPI上使用ESP8266

ESP8266,是一個極為便宜的Wifi晶片,
因為網路上已經有許多的介紹文,所以本魔在此就不多贅述。

首先先講講一般ESP8266的接法及使用,
標準接線圖
實際範例
將ESP8266接上86duino後,
就可以將下列程式碼燒入86duino,
這樣就可以透過來做AT Command的控制。

void setup()
{

 Serial.begin(9600);
 Serial1.begin(115200);
}
void loop()
{
 while (Serial1.available()) {
  Serial.write(Serial1.read());
 }
 while (Serial.available()) {
  Serial1.write(Serial.read());
 }
}


燒入後可以用
這樣就可以做一些基本連線及設定的控制,
至於下AT Command的方法請參考文件。



然而為什麼要改裝到SPI上呢?
請看下圖!

改裝後
沒錯,這樣就可以牢牢的插在86Duino上,
因為在本魔實驗時常常遇到因機器人晃動造成ESP8266電源接觸不良導致斷線,
而且這樣也不用考慮整線的問題。

那麼就開始進入我們的教學,
首先要做出我們的轉接座。
轉接座及ESP8266
材料也很簡單,
兩顆母座2x5 ROHS及一條cable
母座2x5 ROHS

或許你會問,
為什麼需要多一條線?
SPI不就有電源輸出了嗎?
為什麼還要再跳線?
這是因為SPI是只有5v輸出,
而ESP8266的電源必須3.0V至3.6V間,
所以多拉一條跳線接3.3v。
本魔測試過ESP8266接5v電源也是可以工作的
,只是有過熱燒壞的風險,或其他狀況,所以也不是很推薦這樣使用。


SPI腳位圖
本魔再對照過後認為將SPIDI改TX、SPICS改RX會比較好焊。

轉接圖
也就是轉接頭只焊3PIN,其餘兩PIN3.3v直接跳線。
本魔的方法是,將不需要的PIN腳拔掉,再將PIN腳折至相連。
焊接前
焊接後
當然,只有三根腳支撐是相當不牢固的!
所以本魔在中間灌入熱熔膠,固定並防止短路。
切記接上ESP8266時不要接反了,
為防止接錯本魔還貼了辨識用的紅紙。
熱熔膠及辨識用的紅紙



結束後就可以撰寫轉換的程式囉!

在86Duino libraries中的io.h有一個io_outpb,
io_outpb它是可以直接存取硬體IO的function,
這function是非常低階的控制,
基本上是要到Hacker等級的才會玩的!
所以如果你不是Hacker的話就不要亂玩唷!
因為很重要所以要標紅字。

直接存取硬體IO的話就可以將你要的腳位切換成你要的功能,
所以首先要先去了解86Duino的IO Port,
可以在官方找到86Duino CPU的Datasheet(Vortex86EX Datasheet V1.4),
我們可以看到P306.文中的CrossBar Config Registers內有寫各功能的編號,
找出我們所需要的就是將COM1的TX、RX更換為SPI的CS、DI,
000001b COM1-TXD1
000010b COM1-RXD1
001001b SPI-CS1
001100b SPI-DI

而COM1的TX、RX及SPI的CS、DI的address分別為:
0x0A12 COM1 TX
0x0A13 COM1 RX
0x0A20 SPICS
0x0A22 SPIDI
如此一來我們就可以寫出接上轉接座的控制程式碼:

void setup()
{
 io_outpb(0x0A12,0x00); //enable COM1 TX pin
 io_outpb(0x0A13,0x00); //enable COM1 RX pin
 io_outpb(0x0A20,0x02); //SPICS to RX
 io_outpb(0x0A22,0x01); //SPIDI to DX
 Serial.begin(9600);
 Serial1.begin(115200);
}
void loop()
{
 while (Serial1.available()) {
  Serial.write(Serial1.read());
 }
 while (Serial.available()) {
  Serial1.write(Serial.read());
 }
}
Share:

魔人歸來



或許有人會問,
在一年多前的COSCUP演講後,
為什麼本魔怎麼就消失了?

其實答案很簡單,
因為國家需要我!本魔去盡國民應盡的義務XD
本魔甚至還去體驗了從1250英呎是跳下來的感覺呢!

回到主題,
近期本魔做了過往的機器人的精華合體,
也會陸陸續續打過程及教學文。
咦?
你問我什麼叫做「過往的機器人的精華合體」?
過往的機器人是指機械史加納還有幾台人型機器人,
那合體該不會是!?

絕對不是你想的這東西!
而是近期本魔用了最近很夯的ESP8266,
製作了機器人動態同步的IOT應用,
沒錯,IOT就是最近很夯的物連網啦!
廢話不多說,請看影片~






( 聽說今年尾牙流行跳妖怪舞 ... XD )最近用 86Duino + ESP8266 為客戶寫了一個 device 動態同步的物聯網應用 sample code, 展示如何動態增刪同步節點, 並在任意時間點同步任意 device. 因為阿宅工程師們覺得這個 sample 也蠻適合拿來做機器人跳舞同步的應用, 於是一群人就玩興大起, 搞出了下面這段新春賀歲特別節目~XDDD
由 RoBoard Lab 貼上了 2016年2月1日



或許有人會問為什麼不一開始就把機器人放著跳呢?
間單來說就是告訴各位我們沒有作弊阿XD
動態同步也就是要隨時開機隨時都能跟上舞步的唷!
如果是編動作,一鍵到底的方式可是沒辦法做出這種效果呢!
Share:

2014/5/16

[EduCake] EduCake平衡車全新再進化

在之前,本魔拿到了這台EduCake平衡車,
本魔認為相當有趣,
因為使用的是實驗用的小馬達及小型行動電源,
所以出現許許多多不同的問題,
但也將這些問題一一排解,現在就來介紹遇到的問題及解決的方法。

首先,最大的問題是平衡,
先前做的版本其實並不是相當穩定,
之後本魔加入了PID去做調整,加入了Kp與Kd雖然穩定許多,
但還是經常出現爆衝無法平衡的問題,
最後加入了Ki,情況才穩定下來。

接著是馬達力道問題,
基本上兩顆馬達的精度就不是很高,
所以有時會出現一輪轉一輪不轉的情況(即一輪未克服摩擦力),
接著就是克服摩擦力的力道有點大,
這樣使得馬達無法相當低速的旋轉,在克服摩擦力後的轉速過快,
平衡時會無法精準的調整到我要的轉速,使得平衡又再難上一個層次。

接著的問題是施力過大時,陀螺儀會當掉,
一開始本魔也是百思不得其解,
電表、示波器都測試過,結果去詢問了電路的達人,
他幫我加了幾顆電容,就解決了,
似乎是電流被拉低,導致陀螺儀重啟。

接著是要在倒地時自己站立起來,
本魔發現力道相當不夠,所以將電源做了更換,
換成7.4V的鋰電池,在加上5V穩壓電路供給控制板。

以上是近期遇到的問題,
也確實的想辦法解決了,
而之後,本魔會再加入移動控制,
請各位敬請關注!



code:

#include <EEPROM.h>

#include "FreeIMU1.h"

#include <Wire.h>

#include <stdio.h>

#include <conio.h>

#include "pitches.h"

int raw_values[9];

float ypr[3]; // yaw pitch roll

unsigned long pretime = 0;

unsigned long pretime1 = 0;

unsigned long pretime2 = 0;

int pin[4] = {10,11,31,32};

float target;

float targetoffset = 0;

float Kp,Ki,Kd;

float pid_u,pid_sum;

float pid_e[2];

char key;

boolean flag = true;

// Set the FreeIMU object

FreeIMU1 my3IMU = FreeIMU1();

void setup() {

 Serial.begin(115200);

 Wire.begin();



 delay(5);

 my3IMU.init(); // the parameter enable or disable fast mode

 delay(5);

 pinMode(10,OUTPUT);

 pinMode(11,OUTPUT);

 Kp = 70;

 Ki = 1.2;

 Kd = 20;

        target = 0;

        pid_u = 0;

        pid_e[0] = 0;

        pid_e[1] = 0;

        pid_sum = 0;

}



void loop() {

 //Get gyro value

        target += targetoffset;

 my3IMU.getYawPitchRoll(ypr);

          //PID calculate

          if(kbhit()){

            key = getch();

            if(key == '1')

              Kp += 5;

            else if(key == '2')

              Kp -= 5;

            else if(key == '3')

              Kd += 5;

            else if(key == '4')

              Kd -= 5;

          }

          if((ypr[2] > 25 || ypr[2] < -25) && flag){

              target = 0;

              targetoffset = 0;

              tone(PCSPEAKER, NOTE_G3,1000/4);

              delay(1000/4 * 1.30);

              noTone(PCSPEAKER);

              flag = false;

         pretime1 = millis();

       analogWrite(pin[0],0);

       analogWrite(pin[1],0);

       analogWrite(pin[2],0);

       analogWrite(pin[3],0);

          }

          if(ypr[2] > 25 && millis() - pretime1> 2000ul){

              target = 0;

              targetoffset = 0;

              tone(PCSPEAKER, NOTE_G4,1000/4);

              delay(1000/4 * 1.30);

              noTone(PCSPEAKER);

              pid_sum = 0;

       analogWrite(pin[0],0);

       analogWrite(pin[1],255);

       analogWrite(pin[2],0);

       analogWrite(pin[3],255);

              delay(100);

       analogWrite(pin[1],0);

       analogWrite(pin[0],255);

       analogWrite(pin[3],0);

       analogWrite(pin[2],255);

              delay(100);

       analogWrite(pin[0],0);

       analogWrite(pin[1],0);

       analogWrite(pin[2],0);

       analogWrite(pin[3],0);

              delay(75);

       pretime2 = millis();

              while(millis() - pretime2 < 2000ul){

                my3IMU.getYawPitchRoll(ypr);

         if(ypr[2] < -5 && ypr[2] > -25){

                  flag = true;

                  break;

                }

              }

          }else if(ypr[2] < -25 && millis() - pretime1> 2000ul){

              target = 0;

              targetoffset = 0;

              tone(PCSPEAKER, NOTE_G4,1000/4);

              pid_sum = 0;

       analogWrite(pin[1],0);

       analogWrite(pin[0],255);

       analogWrite(pin[3],0);

       analogWrite(pin[2],255);

              delay(100);

       analogWrite(pin[0],0);

       analogWrite(pin[1],255);

       analogWrite(pin[2],0);

       analogWrite(pin[3],255);

              delay(100);

       analogWrite(pin[0],0);

       analogWrite(pin[1],0);

       analogWrite(pin[2],0);

       analogWrite(pin[3],0);

              delay(75);

         pretime2 = millis();

              while(millis() - pretime2 < 2000ul){

                my3IMU.getYawPitchRoll(ypr);

         if(ypr[2] < 25 && ypr[2] > 5){

                   flag = true;

                   break;

                }

              }

          }

          if(ypr[2] < 25 && ypr[2] > -25){

                  pid_sum += pid_e[0];

                  pid_e[0] = target - ypr[2];

                  pid_u = Kp * (pid_e[0])

                        + Ki * (pid_sum)

                        + Kd * (pid_e[0] - pid_e[1]);

                  if(pid_u > 0){

             pid_u = pid_u > 255 ? 255: pid_u;

             pid_u = pid_u < 90 ? 0: pid_u;

                  }else{

             pid_u = pid_u < -255 ? -255: pid_u;

             pid_u = pid_u > -90 ? 0: pid_u;

                  }

                  pid_e[1] = pid_e[0];

           analogWrite(pin[1],pid_u > 0 ? pid_u : 0);

           analogWrite(pin[0],pid_u < 0 ? -pid_u : 0);

           analogWrite(pin[3],pid_u > 0 ? pid_u : 0);

           analogWrite(pin[2],pid_u < 0 ? -pid_u : 0);

          }

        if(pid_u > 90 || pid_u < -90){

            targetoffset = pid_u * 0.0003;

        }else{

          targetoffset = 0;

        }

        while(millis() - pretime> 1000ul){

  Serial.print(" Roll: ");

  Serial.print(ypr[2]);

  Serial.println("");

  pretime = millis(); 

 }

}



Share:

2014/3/23

[EduCake] EduCake平衡車首次亮相

今天本魔要來介紹的是最近拿到的一台EduCake平衡車,

來看看這台平衡車的樣子吧!



EduCake平衡車顧名思義,是使用EduCake來控制平衡車。



 車輪及車身是請U大使用3D Print印出的!



 EduCake上面就像我們常見的麵包版一樣,可以直接接線做實驗電路,省去焊電路的時間。



供電是使用5V的電源,所以本魔選購了一顆口紅型的行動電源供電。
而平衡車當然是需要陀螺儀感測的,所以在車底下有裝上一顆RM-G146。
動力的部分,採用了常見的直流馬達,在網路上看到的平衡車大多是使用伺服馬達來做的,
但考慮到伺服馬達的價格似乎不太夠親民,所以採用了一顆沒多少錢的直流馬達。



接著來介紹一下電路,由於是使用直流馬達,所以必須要用電路來控制正反轉,
這裡本魔採用的是TA7291P,控制上也不困難,只要拉兩組IO接上,
然後對應datasheet,個別送出正確的訊號即可控制電流流向。

而由於TA7291P需要3.5V以上供電,而IO腳位送出的電壓只有3.3V,所以為了穩定所以又加了一顆HD74LS04,
這顆晶片的功用就只是拉高電壓,所以不多做解釋。



然後我們來看看我目前做的程式碼,還相當簡陋,所以目前效果還不算太好。



#include <EEPROM.h>
#include "FreeIMU1.h"
#include <Wire.h>
int raw_values[9];
//char str[512];
float ypr[3]; // yaw pitch roll
float val[9];
unsigned long pretime = 0;
int pin[4] = {10,11,31,32};
int d = 10;
// Set the FreeIMU object
FreeIMU1 my3IMU = FreeIMU1();
void setup() { 
 Serial.begin(115200);
 Wire.begin();
 delay(5);
 my3IMU.init(); // the parameter enable or disable fast mode
 delay(5);
 pinMode(10,OUTPUT);
 pinMode(11,OUTPUT);
}
void loop() {
 my3IMU.getYawPitchRoll(ypr);
 if(ypr[2] > 5){
  pin[0] = 10;
  pin[1] = 11;
  pin[2] = 31;
  pin[3] = 32;
  for(int i = 0; i < 4; i+=2){
   analogWrite(pin[i],255);
   analogWrite(pin[i+1],0);
  }
 }else if(ypr[2] < 3){
  pin[0] = 11;
  pin[1] = 10;
  pin[2] = 32;
  pin[3] = 31;
  for(int i = 0; i < 4; i+=2){
   analogWrite(pin[i],255);
   analogWrite(pin[i+1],0);
  }
 }else{
  for(int i = 0; i < 4; i++)
   analogWrite(pin[i],0);
 }
 while(millis() - pretime> 1000ul){
  Serial.print(" Roll: ");
  Serial.print(ypr[2]);
  Serial.println("");
  pretime = millis();
 }
 delay(10);
}




最後,我們來看看我目前的一個小成果吧!

Share:
技術提供:Blogger.

追蹤者