2017年5月29日月曜日

I2C接続顔モジュール製作 動かしてみる 

お久しぶりです.もう二ヶ月前になりますがこれの続きです.

まずガンガン動かすことになりそうなので回路製作とハード面をもう少し
かっちり固めました

回路面は余っていたATmega328PUを使用し回路を製作.
ブートローダー書き込み済みなのでArduinoIDEでプログラミングできます.
マトリクスLEDドライバとはソフトウェアI2C,モジュールへの指示は
ハードウェアI2Cを使用します.マトリクスLEDとCPUはバスパワーですが,
サーボは別電源を使用します.試行錯誤した結果これが一番安定しました.



こちらを使用したサーボマウントは少しだけ改良.チルト軸は上から
押さえつけるようにし,取れにくくしました.パン軸はついていたアームを
なくし,サーボに直接回路をテープで止めました.簡単な処置ですが
意外と安定しています.動作中に首がポロリといったことはなくなりました.
ついでにカメラは基盤を直接固定しました.かなり軽量になりました.



別のArduinoを用いて動作確認です.





今回顔モジュール側に用いたコード.Arduino_I2C_face
プロトコルは顔モジュール側でモーションを作るのはやめて,
サーボ動作 -> ’s’+パン角[deg]+チルト角[deg]
LED表示右 -> ’r’+8byte 
LED表示左 -> ’l’+8byte
のようにしました.暫定です.
欠点は,サーボ動作させたら,終わるまで待たなければならないところです.
割り込みによるサーボ動作も試しましたが,どうもうまくいかず・・・
要改良です.

ソフトは暫定でいいとして,次回はRaspberryPiとの接続を試したいと思います.


2017年3月18日土曜日

I2C通信で動かす顔モジュール 一度形にしてみる

どうも
前回MatrixLEDドライバ,HT16K33を使用し,いくつかの表情を作成してみました.
今回はサーボ,サーボマウント,USBカメラを使用し一旦,顔として構築してみる
ことにしました.

使用したもの一覧
LOGICOOL ウェブカム HD画質 120万画素 C270
SG90用カメラマウント
マイクロサーボ SG90
マトリックスLEDドライバHT16K33
青色マトリックスLED8*8

完成したのがこれ





テープ等を使い,適当にマウントに取り付けました.
マウントは作りが甘かったため,すぐに首が取れてしまいます.
このあたりは自作する必要があるのでしょうか.
制御用のマイコンは予定通りArduinoを使用しました.
今回はボードを使用しましたが,ゆくゆくは素子単体で動作させます.

とりあえず,喜ぶ・怒る・悲しむの動作を作成し,PCからのコマンドで
動作するプログラムを作成しました.ほんちゃんのI2Cを通信に使用するため,
LEDドライバとの通信はソフトウェアI2Cライブラリを使用.
サーボは標準ライブラリのままでは速すぎるため自作関数でゆっくり
動くようにしています.ついでに使わないときは電源を切るようにしました.

メモ代わりにスケッチを載せます.
このほかにface.hにビットパターンを書き込んでいます

cam_mount.ino

//====ソフトウェアI2C関連マクロ====
#define SCL_PIN  2                 // SCLは2番ピンとする
#define SCL_PORT PORTD
#define SDA_PIN  3                 // SDAは3番ピンとする
#define SDA_PORT PORTD
#define I2C_TIMEOUT 100
#define I2C_FASTMODE 1
//=================================

#include <SoftWire.h>   //ソフトウェアI2C
#include<Servo.h>       //サーボ
#include"face.h"

#define HT16K33 (0x70)   //LEDドライバーHT16K33 アドレス

Servo servo_pan;    //サーボ宣言パン軸
Servo servo_tilt;   //サーボ宣言チルト軸
byte recv_data[256];

const char blink_Hz = 0;
const char on_off  = 1;
const char brightness = 1;

SoftWire Wire = SoftWire();   //ソフトI2C

//===============サーボ角度制御================
void Servo_move(int ang_pan, int ang_tilt, int wait_ms){
    int pan_palse = map(ang_pan, 0, 180, 800, 2300);
    int pan_now = servo_pan.readMicroseconds();
    int tilt_palse = map(ang_tilt, 0, 180, 800, 2300);
    int tilt_now = servo_tilt.readMicroseconds();
    int flg_pan=1,flg_tilt=1;
 
    while(flg_pan || flg_tilt){
      if(pan_palse > pan_now) pan_now++;
      else if(pan_palse < pan_now) pan_now--;
      else flg_pan = 0;
   
      if(tilt_palse > tilt_now) tilt_now++;
      else if(tilt_palse < tilt_now) tilt_now--;
      else flg_tilt = 0;

      servo_pan.writeMicroseconds(pan_now);
      servo_tilt.writeMicroseconds(tilt_now);
      delay(wait_ms);
    }
 
  }

//===============サーボセット================
void Servo_set(int deg_pan,int deg_tilt){
  servo_pan.attach(8, 800, 2300);
  servo_tilt.attach(9, 800, 2300);
  Servo_move( deg_pan, deg_tilt, 2);
  servo_pan.detach();
  servo_tilt.detach();
  }

//===============LEDドライバ初期化================
void matrixLED_init(void){

  //HT16K33システムオシレータON
  Wire.beginTransmission(HT16K33);
  Wire.write(0x20 | 1);
  Wire.endTransmission();

  //blink_Hz=0 点滅off, 1は2Hz, 2は1Hz, 3は0.5Hz, on_off=0は消灯、1は点灯 
  Wire.beginTransmission(HT16K33);
  Wire.write(0x80 | (blink_Hz<<1) | on_off);
  Wire.endTransmission();

  // brightness= 0~15
  Wire.beginTransmission(HT16K33);
  Wire.write(0xE0 | brightness);
  Wire.endTransmission();

  //マトリックスLED初期化
  Wire.beginTransmission(HT16K33);
  Wire.write(0x00);
  for(int i=0;i<8;i++){
    Wire.write(B00000000);                   //1つ目の8x8LED初期化
    Wire.write(B00000000);                   //2つ目の8x8LED初期化
  }
  Wire.endTransmission();
}

//================マトリックスLED出力================
void LED_Driver_DisplayOutput(byte LD_addrs, byte* DotB, byte* DotB2)
{
  int i,j;
        Wire.beginTransmission(LD_addrs);
        Wire.write(B00000000); //これは必要
        for(i = 0; i<8; i++){
          Wire.write(DotB[i]);
          Wire.write(DotB2[7-i]);
        }
        Wire.endTransmission();
}

//================action happy================
void action_happy(void){
  LED_Driver_DisplayOutput(HT16K33, dots_happy, dots_happy);
  Servo_set(90, 90);
  delay(250);
  Servo_set(110, 90);
  delay(250);
  Servo_set(90, 90);
  delay(250);
  Servo_set(110, 90);
  delay(250);
  Servo_set(90, 90);
}

//================action angry================
void action_angry(void){
 LED_Driver_DisplayOutput(HT16K33, dots_angry, dots_angry);
 Servo_set(70, 110);
 delay(250);
 Servo_set(90, 90);
}

//================action sad================
void action_sad(void){
 LED_Driver_DisplayOutput(HT16K33, dots_sad, dots_sad);
 Servo_set(110, 90);
 Servo_set(110, 70);
 delay(250);
 Servo_set(110, 110);
 delay(250);
 Servo_set(90, 90);
}

void setup()
{
  Serial.begin(115200);
  Wire.begin();
  matrixLED_init();
  LED_Driver_DisplayOutput(HT16K33,dots_usual, dots_usual);
  Servo_set(90,90);
  delay(1000);
  Serial.println("arduino_i2c_face");
  Serial.println("please_input_command:");
}

void loop()
{
   byte recv_char = Serial.read();
   switch(recv_char){
    case 'h':action_happy();
             Serial.println("happy!");
             break;

    case 'a':action_angry();
             Serial.println("angry!");
             break;

    case 's'://LED_Driver_DisplayOutput(HT16K33, dots_sad, dots_sad);
             action_sad();
             Serial.println("sad!");
             break;
           
    default:break;
   }
   LED_Driver_DisplayOutput(HT16K33, dots_usual, dots_usual);
}



動いている動画



形にはなっていますが,結構ガタガタした動作です.
仮組みしてわかったことは,ハードはもっとかっちり組んだほうが
いいということです.
Raspberry piなどと接続するのはまだまだ先になりそうです.


参考にさせていただいたサイト.
http://www.geocities.jp/zattouka/GarageHouse/micon/I2C/I2C_5.htm
http://tetsuakibaba.jp/index.php?page=workshop/ServoBasis/main
https://www.mgo-tec.com/blog-entry-ada-ledmatrix01.html

2017年3月14日火曜日

MatrixLEDドライバHT16K33を使ってみる

お久しぶりです.
最近大学が忙しく,趣味の電子工作をする時間がめっきり減っています.
それでも日々少しずつ前進したいところです.

さて,今回はMatrixLEDドライバ,HT16K33を使ってみました.
このドライバはI2C接続で16×16のマトリックスLEDを2つ制御することができます.
秋月でドライバモジュールとカッコつけて青色マトリックスLEDを購入し,
ユニバーサル基盤で回路を作成しました.



配線は,A0-A15をLEDのアノード(Col),C-0-C7をLEDのカソード(Row)
に接続し,電源,GND,SDA,SCLをそれぞれ引き出します.
回路は単純ですが,数が多いため内部はカオスです笑

ちょっと顔らしい動作をさせてみたいと思い,標準・喜ぶ・怒る・
悲しむ・疑問・驚き・寝るの表情を作ってみました.



アナログチックでちょっとかわいいですね.

今回のモジュールとサーボ,カメラを用いて「I2C通信で動かす
顔モジュール」を作って,Raspberry pi等から動かそうと計画しています.
ソフトウェア等はまたある程度出来上がってから紹介したいと思います.

2017年2月13日月曜日

Raspberry pi3 i2c経由でサーボを使う

Raspberry pi3からあらゆるモジュールをギュインギュイン
動かしたいですが,正直GPIOを制御するのはめんどくさそうです.
モータなどリアルタイム性が高いものは他のマイコンに任せるのが
いいと思いました.

そこでArduinoにサーボモータを接続し,i2c経由でアクセスしてみます.

こんな感じ.テストなのでごちゃごちゃです.



サーボは一般的なSG90です.
Rpi3 -> arduino
GPIO2 -> a4(SDA)
GPIO3 -> a5(SCL)
GND -> GND

arduino->SG90
Vcc -> Vcc
GND -> GND
Sig -> D4(サーボ1)
Sig -> D5(サーボ2)

Arduinoは3.3Vで起動しACアダプタから外部電源を取ります.
そうしなければサーボを動かした瞬間落ちます.

Arduino側プログラム
#include<Servo.h>
#include <Wire.h>

Servo servo_pan;
Servo servo_tilt;
byte recv_data[256];
byte addr = 8;// Slave ID #8
byte deg_pan = 0;
byte deg_tilt = 0;

void setup() {
    servo_pan.attach(4);
    servo_tilt.attach(5);
    Wire.begin(addr);
    Wire.onReceive(receiveEvent);
    Wire.onRequest(requestEvent);
    Serial.begin(115200);
}

void loop() {
    if(deg_pan>=0 && deg_pan<=180){servo_pan.write(deg_pan);}
    if(deg_tilt>=0 && deg_tilt<=180){servo_tilt.write(deg_tilt);}
    delay(1000);
}

void receiveEvent(int a){
  int i=0;
  //delay(100);
  while (Wire.available()) {
    recv_data[i] = Wire.read();
    Serial.print(recv_data[i],DEC);
    Serial.print(" ");
    i++;
  }
  if(i>0){Serial.println(' ');}
  if(i>1){
      if(recv_data[0] == 4){ deg_pan = recv_data[1]; }
      else if(recv_data[0] == 5){ deg_tilt = recv_data[1]; }
  }
}

void requestEvent() {
  Wire.write(addr);
}

一応シリアル通信でデバックできるようにしておきました.
マスタからはレジスタ(4or5),角度(0~180)を送ります.
マスタからの読み出しはi2cdetectコマンドで使用するので
アドレスを返すようにしておきます.

とりあえず動作確認
Rpi3でi2cを使えるようにする.
こちらを参考にライブラリをインストールしました.
以下コマンドで接続デバイスを確認します.
$ sudo i2cdetect -y 1
上記のArduinoプログラムでは0x08がスレーブアドレスです.
コマンドからは
$ sudo i2cset -y 1 0x08 0x04 "角度"
で操作できます.


接続まで確認しました.Arduinoを使用したのはATmega328と
クリスタル等数セットが余っていたので何かに利用できないかと思ったからです.
とりあえずブラウザからアクセスできるカメラマウントの製作を目指します.

Raspberry Pi3 WEBカメラでストリーミングしてみる

お久しぶりです.
今更ながらRaspberry pi3とWEBカメラを購入したので
動作確認をしました.Raspberry pi3のセットアップ等は
わかりやすいサイトが多々あるので割愛します.

WEBカメラは動作実績のある
LOGICOOL ウェブカム HD画質 120万画素 C270
を使用しました.



ちょっと大きいですがマイクもついているので
音声処理ソフトウェアも使えそうです.

ソフトウェアにはmjpg-streamerを使用しました.セットアップ等は
こちらのサイトを参考にさせて頂きました.というかまんまです.

できた動画がこちら


動作確認ができました.
しばらくは画像処理,音声処理等で遊びつつ
何を作るか考える予定です.

ちなみにこのカメラには第二関節?のところにおもりがついています.
サーボモータを取り付けるときは外した方がよさそうですね.




2017年1月28日土曜日

RX621で遊ぶ モータ制御してみる

RX621でMTU2を持ちいてモータ制御してみたメモ.
MTU2を用いてPWM出力と位相係数モードを使うことは難しいことではありません.
今回確認したかったのは,4モータを制御することです.

ちなみにピン選定はPDG(Peripheral Driver Generator)を使うと楽です.
コード生成機能はあまり使用しませんが,モジュールで使用するピンが簡単に
わかりやすく出力されるので,一目でピンを確認できます.

PDGを使用した結果4モータを制御するためには
MTU1,2,7,8を位相係数モード.(7,8はポートB)
MTU6,9をPWMモード2.
その他適当なピンをモータドライバにつなぐのが良いとわかりました.

以下MTU6のPWMモード2とMTU1,2の位相係数モードのイニシャライズメモ
その他もほとんど同じです.

//MTU6
SYSTEM.MSTPCRA.BIT.MSTPA8 = 0; //モジュールストップ状態の解除 MTU6
MTU6.TCR.BIT.TPSC =2; //PCLK/16
MTU6.TCR.BIT.CCLR = 1; //TGRAでカウントクリア
MTU6.TMDR.BIT.MD = 2; //PWMモード1
MTU6.TIORH.BIT.IOA = 1; //出力禁止
MTU6.TIORH.BIT.IOB = 2; //LOW->HIGH出力
MTU6.TIORL.BIT.IOC = 1; //出力禁止
MTU6.TIORL.BIT.IOD = 2; //LOW->HIGH出力
MTU6.TGRA = 3000-1;     //1kHz
MTU6.TGRB = 0;
MTU6.TGRC = 3000-1;     //1kHz
MTU6.TGRD = 0;
MTUB.TSTR.BIT.CST0 = 1; //カウント動作開始

//MTU1,MTU2
SYSTEM.MSTPCRA.BIT.MSTPA9= 0; //MTUストップ解除
MTUA.TSTR.BIT.CST1 = 0; //MTU1カウント停止
MTUA.TSTR.BIT.CST2 = 0; //MTU2カウント停止
PORT2.ICR.BYTE=0xff;   //ポート機能解除
IOPORT.PFCMTU.BIT.TCLKS = 0; //ポート設定

MTU1.TMDR.BIT.MD = 4; //位相係数モード
MTU1.TSR.BIT.TCFD = 1; //TCNTはアップカウント,フラグクリア
MTU1.TCNT = 0; //カウントストップ

MTU2.TMDR.BIT.MD = 4; //位相係数モード
MTU2.TSR.BYTE = 0xC0; //TCNTはアップカウント,フラグクリア
MTU2.TCNT = 0; //カウントクリア

MTUA.TSTR.BIT.CST1 = 1; //76543210
MTUA.TSTR.BIT.CST2 = 1; //MTU2カウント開始


モータドライバはこれ,モータはこれのエンコーダ付き
現在いじっている基盤にそのままモータドライバは乗らなかったので
別に基盤を作りました.





結構ゴチャゴチャしてきました.
とりあえずこれで4モータ動かし,回転数を取得できることは確認しました.
今回で回路の確認は終了したので
前にも書いたとおりマイクロマウスの製作に入りたいと思います.
とりあえずモータ買わないと.

RX621で遊ぶ SPI通信でジャイロセンサを使う

RX621でSPIで使用するメモ

使用したジャイロセンサはこれ

L3G4200D



Amazonで購入しました.秋月にデータシートと詳しい説明書がありました.
http://akizukidenshi.com/catalog/g/gM-06433/

今回はピンの関係からRSPI1のポートBを使用.
配線は以下のとおり

PE5(RSPCKB) -> SCL
PE6(MOSIB)    -> SDA
PE7(MISOB)    -> SDO
PE4(SSL0B)    -> CS

説明書によると,クロックはデフォルトでHIGH奇数エッジでデータ変化
偶数エッジでデータサンプルです.(データシート24ページ目)
16ビットで通信し,上位8ビットでデータレジスタ送信,下位8ビットでデータ受信します.

以下イニシャライズと16ビット送受信のサンプル


//SPI設定
SYSTEM.MSTPCRB.BIT.MSTPB16 = 0; //SPIストップ解除

RSPI1.SPCR.BIT.SPE = 0; //SPI機能停止

RSPI1.SPBR = 23; //100kHz

RSPI1.SPDCR.BIT.SLSEL = 0x01b; //SSL0,SSL1許可
RSPI1.SPDCR.BIT.SPLW = 0; //ワードアクセス

RSPI1.SPCMD0.BIT.CPHA = 1; //奇数エッジでデータ変化偶数でサンプル
RSPI1.SPCMD0.BIT.CPOL = 1; //アイドル時RSPCK=1
RSPI1.SPCMD0.BIT.SSLA = 0; //SSL0でアサート
RSPI1.SPCMD0.BIT.SSLKP = 1; //SSL信号を保持
RSPI1.SPCMD0.BIT.SPB = 15; //データ長16bit

PORTE.ICR.BIT.B7=1; //入力バッファ有効
IOPORT.PFHSPI.BIT.RSPIS = 1; //SPI端子portEに変更
IOPORT.PFHSPI.BIT.RSPCKE = 1; //RSPCKB有効
IOPORT.PFHSPI.BIT.MOSIE = 1; //MOSIB有効
IOPORT.PFHSPI.BIT.MISOE = 1; //MISOB有効
IOPORT.PFHSPI.BIT.SSL0E = 1; //SSL0B有効

RSPI1.SPCR.BIT.MSTR = 1;     //マスタモード

RSPI1.SPSR.BYTE = 0xA0; //ステータスクリア
RSPI1.SPCR.BYTE;     // SPCR空読み


//センサレジスタから1バイト読み出し
unsigned char rspi_read( unsigned char reg,unsigned char x ){
unsigned short  recv;
RSPI1.SPCR.BIT.SPE = 1; // enable
RSPI1.SPDR.WORD.H = reg<<8+x; // 送信
while( 0 == RSPI1.SPSR.BIT.SPRF ); // 受信完了待ち
recv = RSPI1.SPDR.WORD.H; // 受信バッファ読出し
RSPI1.SPCR.BIT.SPE = 0; // disable
recv = recv&0x00ff; //マスク
return(recv);
}


とりあえずWho_am_iレジスタから読み取る.
具体的には0x8fを送り,0xd3(211)が帰ってくればOK.