M5StickCのJoystick HATをためす

現時点の情報です。最新情報はM5StickC非公式日本語リファレンスを確認してみてください。

概要

日本未発売のJoystick HATを一ヶ月前に購入していましたが、放置していたので触ってみました。

外観

箱はいつものプラケース入りです。付属品はHAT固定用の両面テープのみ。

大きさはこれぐらいです。結構大きいかな?

ジョイスティックは金属むき出しで、頭の部分がありません。

裏側にはI2Cの情報がかかれています。I2C接続のSTM32F030F4経由でジョイスティック入力を受け取っているみたいです。

スケッチ

#include <M5StickC.h>
#include "Wire.h"
#define JOY_ADDR 0x38
// initial position of the cursor
int xPos = 40;
int yPos = 0;
int prevxPos = 40;
int prevyPos = 0;
char data[100];
int pressstate=0;
float upvelocity=0;
int platwidth=20;
// We store platform x and ys here (so there are 5 platforms here)
int plats[14]={0,0,25,0,50,0,75,0,100,0,125,0,150,0};
bool dead = true;
int deadstate=0;
int speedy=0;
int step=0;
int8_t x_data,y_data,button_data;
void setup() {
  // initialize the display
  M5.begin();
  Wire.begin(0, 26, 100000);
  // clear the background
  M5.Lcd.setRotation(2);
  M5.Lcd.fillRect(0, 0, 80, 160, BLACK);
  for(int i=0; i<14; i+=2)
  {
      plats[i+1]=(random(159)) % 159;
    
  }
}
 
void loop() {
  Wire.beginTransmission(JOY_ADDR);
  Wire.write(0x02); 
  Wire.endTransmission();
  Wire.requestFrom(JOY_ADDR, 3);
  if (Wire.available()) {
    x_data = Wire.read();
    y_data = Wire.read();
    button_data = Wire.read();
  }
  if(!dead)
  {
  for(int i=0; i<14; i+=2)
  {
//    EsploraTFT.stroke(0, 255, 0);
    M5.Lcd.drawLine(plats[i+1],plats[i],plats[i+1]+platwidth,plats[i],GREEN);
//    EsploraTFT.stroke(150, 89, 43);
    M5.Lcd.drawLine(plats[i+1],plats[i]-1,plats[i+1]+platwidth,plats[i]-1, BLACK);
    plats[i]=plats[i]+1;
    if(plats[i] > 160) 
    {
      //sets the platform to the top of screen
      plats[i]=0; 
      //sets random x position
      plats[i+1]= (random(59)) % 59;
    }
  }
  step++;
  int tilt = x_data;
  // the values are 100 when tilted to the left
  // and  -100 when tilted to the right
  // map these values to the start and end points
  speedy = map(tilt, -110, 110, 3, -3);
  xPos+=speedy;
  // don't let the point go past the screen edges
  if (xPos > 59) {
    (xPos = 0);
  }
  if (xPos < 0) {
    (xPos = 59);
  }
  if (yPos > 160) {
    (dead=true);
  }
  if (yPos < 0) {
    (yPos = 0);
  }
   // Erase previous position of player
//  EsploraTFT.stroke(150, 89, 43);
  M5.Lcd.drawPixel(prevxPos, prevyPos, BLACK);
  M5.Lcd.drawPixel(prevxPos+1, prevyPos, BLACK);
  M5.Lcd.drawPixel(prevxPos+1, prevyPos+1, BLACK);
  M5.Lcd.drawPixel(prevxPos, prevyPos+1, BLACK);
  M5.Lcd.drawPixel(prevxPos+1, prevyPos+2, BLACK);
  M5.Lcd.drawPixel(prevxPos, prevyPos+2, BLACK);
  // Create new position of player
//  EsploraTFT.stroke(0, 0, 255);
  M5.Lcd.drawPixel(xPos, yPos, 0xc48c40);
  M5.Lcd.drawPixel(xPos+1, yPos, 0xc48c40);
  M5.Lcd.drawPixel(xPos+1, yPos+1, 0xc48c40);
  M5.Lcd.drawPixel(xPos, yPos+1, 0xc48c40);
  M5.Lcd.drawPixel(xPos+1, yPos+2, 0xc48c40);
  M5.Lcd.drawPixel(xPos, yPos+2, 0xc48c40);
  prevxPos=xPos;
  prevyPos=yPos;
  upvelocity-=0.3f;
  yPos-=upvelocity;
  // Check for collisions with platforms
  for(int i=0; i<20; i+=2)
  {
    if(yPos >= plats[i]-3 && prevyPos < plats[i] && xPos < plats[i+1]+platwidth && xPos > plats[i+1])
    {
      yPos=plats[i]-3;
      upvelocity=4.5f;
    }
  }
  }
  // If dead
  else{
    deadstate++;
    if(deadstate==1) {
      M5.Lcd.fillRect(0, 0, 80, 160, BLACK);
      xPos = 40 / 2;
      yPos = 0;
      M5.Lcd.setCursor(10, 60);
      M5.Lcd.printf("Score: %d", step);
      M5.Lcd.println();
      M5.Lcd.print("Press Joystick to start");
    }
    // Press button to restart
    if(button_data == 0){
            M5.Lcd.fillRect(0, 0, 80, 160, BLACK);
            pressstate=0;
            upvelocity=0;
            step=0;
            dead=false;
            deadstate=0;
    }     
  }
  delay(33);
}

ライブラリにはスケッチ例はなく、UNITのを使いまわそうと思ったら動きませんでした。さらに探したところ、別のところにありました。

新製品が販売されると、ここに追加されてその後に各ライブラリとかに反映されるのですが、最近販売されたものはライブラリまで反映されていないようです、、、

どこかでHATとかの情報を棚卸しして、足りないスケッチをコピーしてPRする必要がありそうです。

このスケッチはゲームになっていて、ジャンプして登っていくようになっているので、デモにはいいですが、サンプルとしてはちょっと冗長な気がします。

シンプルなスケッチ例

#include <M5StickC.h>
#include "Wire.h"
#define JOY_ADDR 0x38
void setup() {
  M5.begin();
  Wire.begin(0,26);
  M5.Lcd.setRotation(3);
}
int8_t x_data;
int8_t y_data;
int8_t button_data;
char data[100];
void loop() {
  // put your main code here, to run repeatedly:
  Wire.beginTransmission(JOY_ADDR);
  Wire.write(0x02); 
  Wire.endTransmission();
  Wire.requestFrom(JOY_ADDR, 3);
  if (Wire.available()) {
    x_data = Wire.read();
    y_data = Wire.read();
    button_data = Wire.read();
    sprintf(data, "x:%d y:%d button:%d\n", x_data, y_data, button_data);
    Serial.print(data);
    M5.Lcd.setCursor(1, 30, 2);
    M5.Lcd.printf("x:%4d y:%4d button:%d\n", x_data, y_data, button_data);
  }
  delay(200);
}

こちらはUNIT版のをベースに作りました。UNIT版とはI2Cのアドレスが違うのと、呼び出す前に0x02を書き込む必要があるみたいです。

縦と横は中心が0でプラス・マイナス120ちょっとが限界値みたいです。たまに-128という無効値を取得しますので、その値は無視したほうが良さそうです。

また、ボタンがあり、通常が1で、ボタンを押し込むと0になります。

まとめ

大きさ的にはかなりぴったりで、便利に使えそうなHATですが金属を直接触るのはちょっと痛いです。

似たようなジョイスティックからキャップを取り外してつけることができそうですが、できれば最初からつけてほしいですね。ただケースに入れたことで、すくまがなくなって動かない可能性もあります。

ちなみに下の写真が中身です。

コメント