Processing × スクーミー ⑩~お化け屋敷~【Python】

~距離センサーの値の変化でお化けが現れる~

距離センサーに手を近づけると、画面上にお化けたちが現れ、音が鳴ります!

画像や音楽ファイルのダウンロード

画像や音楽ファイルのダウンロード

このボタンをクリックすると、Processingを動かすために必要な画像や音楽ファイルがまとまったzipファイルをダウンロードできます。

画像をコピーする

ダウンロードしたzipファイルを展開し、中にある3つのデータファイルをprocessingフォルダにコピーします。

SchooMy_workspace\processing

画像と音を変更したい場合は、同じファイル名で置き換えてください。

使用するセンサーと取付位置

左上:距離センサー

距離センサーを使用するため、スクーミーIDEのプログラムの9行目でsensorTypeを9にしてください。

Pythonモードの追加

ProcessingでPythonを使うためには、Pythonモードがインストールされている必要があります。

Pythonモードが追加されていない場合、「ツール」→「ツールを追加」→「Modes」から「Python Mode for Processing 3」をインストールしてください。

Soundライブラリの追加

音を鳴らすには、Soundライブラリを追加する必要があります。

「ツール」→「ツールを追加」→「Libraries」から「Sound」をインストールしてください。

センサーの値の受け取りと条件分岐について

距離センサーの値が10以下になるとポップアップ画像(popup.png)が表示され、音が再生されます。
距離センサーの値が10を超えるとポップアップ画像が表示されなくなり、音が止まります。

※ 距離センサーの値10はプログラムの10行目で指定しているtriggerValueの値 

playModeについて

ProcessingIDEのプログラムの15行目のplayModeを変更することで、ポップアップ画像の表示と音の再生のタイミングが変わります。

playModeが1の場合:
距離センサーの値が10以下になると、ポップアップ画像が表示され、音が再生されます。
距離センサーの値が10を超えるとポップアップ画像が表示されなくなり、音が止まります。


playModeが2の場合:
距離センサーの値が10以下になると、音が最後まで再生され、ポップアップ画像も表示されます。
音が再生されている間は、距離センサーの値が10を超えてもポップアップ画像は表示されます。

スクーミーIDEのコード

#include <SchooMyUtilities.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>

SchooMyUtilities scmUtils = SchooMyUtilities();

/************ sensorTypeの種類 ************/
int sensorType = 9;
// 1: タッチセンサー
// 2: 明るさセンサー
// 3: 磁気センサー
// 4: 通過センサー(プッシュスイッチも可)
// 5: 音センサー
// 6: 土壌水分センサー
// 7: 温度センサー
// 8: 加速度センサー
// 9: 距離センサー

/************ 特定のセンサーで必要な関数 ************/
float _sbeGetLux(int pinNumber, int res, float vol) {
  pinMode(pinNumber, INPUT);
  float cds_ad = analogRead(pinNumber);
  float cds_v = cds_ad * vol / res;
  float v_res = vol - cds_v;
  if (v_res < 0.01) {
    v_res = 0.01;
  }
  return 10000 * cds_v / v_res / 1000;
}

unsigned long distanceTimeOut = 100000;
float _sbeGetDistanceUsingDistanceSensor(int trigPin, int echoPin) {
  long distance = 0;
  long duration = 0;

  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH, distanceTimeOut);
  if (duration > 0) {
    distance = duration / 2 * 340 * 100 / 1000000;
  }
  return distance;
}

float _sbeGetValOfMoisture(int pinNumber) {
  pinMode(pinNumber, INPUT);
  float moisture_ad = analogRead(pinNumber);
  return moisture_ad;
}

#define SENSOR_BIT 9
OneWire oneWire_19(19);
DallasTemperature sensors_19(&oneWire_19);
float _sbeGetTemperature_19() {  
  sensors_19.requestTemperatures();  
  return sensors_19.getTempCByIndex(0);
}

int MPU6050_ADDR = 0x68;
#define MPU6050_SMPLRT_DIV   0x19
#define MPU6050_CONFIG       0x1a
#define MPU6050_GYRO_CONFIG  0x1b
#define MPU6050_ACCEL_CONFIG 0x1c
#define MPU6050_PWR_MGMT_1   0x6b
int16_t raw_acc_x, raw_acc_y, raw_acc_z, raw_t, raw_gyro_x, raw_gyro_y, raw_gyro_z ;
float acc_x, acc_y, acc_z, acc_angle_x, acc_angle_y;
float absAccelerometer;
double gyro_angle_x = 0, gyro_angle_y = 0, gyro_angle_z = 0;
float interval, preInterval;
double offsetX = 0, offsetY = 0, offsetZ = 0;
float angleX, angleY, angleZ;
float dpsX, dpsY, dpsZ;
double init_angleX = 0, init_angleY = 0, init_angleZ = 0;
volatile float rel_angleX, rel_angleY, rel_angleZ;
void AcceleroMeterWireRead() {
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU6050_ADDR, 14, true);
  raw_acc_x = Wire.read() << 8 | Wire.read();
  raw_acc_y = Wire.read() << 8 | Wire.read();
  raw_acc_z = Wire.read() << 8 | Wire.read();
  raw_t = Wire.read() << 8 | Wire.read();
  raw_gyro_x = Wire.read() << 8 | Wire.read();
  raw_gyro_y = Wire.read() << 8 | Wire.read();
  raw_gyro_z = Wire.read() << 8 | Wire.read();
}
void AcceleroMeterAddressSetup() {
  byte error, address;
  int nDevices = 0;
  for(address = 1; address < 127; address++ ) {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    if (error == 0) {
      if (address<16)MPU6050_ADDR = address;
      nDevices++;
    }
  }
}
void writeMPU6050(byte reg, byte data) {
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(reg);
  Wire.write(data);
  Wire.endTransmission();
}
void AcceleroMeterAngleSetup() {
  AcceleroMeterAddressSetup();
  AcceleroMeterWireRead();
  writeMPU6050(MPU6050_SMPLRT_DIV, 0x00);
  writeMPU6050(MPU6050_CONFIG, 0x00);
  writeMPU6050(MPU6050_GYRO_CONFIG, 0x08);
  writeMPU6050(MPU6050_ACCEL_CONFIG, 0x00);
  writeMPU6050(MPU6050_PWR_MGMT_1, 0x01);
  Serial.print("Calculate Calibration");
  for (int i = 0; i < 3000; i++) {
    AcceleroMeterWireRead();
    dpsX = ((float)raw_gyro_x) / 65.5;
    dpsY = ((float)raw_gyro_y) / 65.5;
    dpsZ = ((float)raw_gyro_z) / 65.5;
    offsetX += dpsX;
    offsetY += dpsY;
    offsetZ += dpsZ;
    if (i % 1000 == 0) {
      Serial.print(".");
    }
  }
  Serial.println();
  offsetX /= 3000;
  offsetY /= 3000;
  offsetZ /= 3000;
  Serial.print("Calculate Rotation");
  for (int i = 0; i < 1000; i++) {
    calcRotation();
    if (i % 1000 == 0) {
      Serial.print(".");
    }
  }
  Serial.println();
  init_angleX = angleX;
  init_angleY = angleY;
  init_angleZ = angleZ;
}
void calcRotation() {
  acc_x = ((float)raw_acc_x) / 16384.0;
  acc_y = ((float)raw_acc_y) / 16384.0;
  acc_z = ((float)raw_acc_z) / 16384.0;
  acc_angle_y = atan2(acc_x, acc_z + abs(acc_y)) * 360 / -2.0 / PI;
  acc_angle_x = atan2(acc_y, acc_z + abs(acc_x)) * 360 / 2.0 / PI;
  dpsX = ((float)raw_gyro_x) / 65.5;
  dpsY = ((float)raw_gyro_y) / 65.5;
  dpsZ = ((float)raw_gyro_z) / 65.5;
  interval = millis() - preInterval;
  preInterval = millis();
  gyro_angle_x += (dpsX - offsetX) * (interval * 0.001);
  gyro_angle_y += (dpsY - offsetY) * (interval * 0.001);
  gyro_angle_z += (dpsZ - offsetZ) * (interval * 0.001);
  angleX = (0.996 * gyro_angle_x) + (0.004 * acc_angle_x);
  angleY = (0.996 * gyro_angle_y) + (0.004 * acc_angle_y);
  angleZ = gyro_angle_z;
  gyro_angle_x = angleX;
  gyro_angle_y = angleY;
  gyro_angle_z = angleZ;
  rel_angleX = init_angleX - angleX;
  rel_angleY = init_angleY - angleY;
  rel_angleZ = init_angleZ - angleZ;
}
float relativeAngleX() {
  AcceleroMeterWireRead();
  calcRotation();
  return rel_angleX;
}

/***************************************************************/

/************ 各センサーの関数 ************/
void touchSensor() {
  Serial.write(digitalRead(19));
}

void brightnessSensor() {
  Serial.write(int(_sbeGetLux(A5, 1023, 5)));
}

void magneticSensor() {
  Serial.write(analogRead(A5));
}

void passingSensor() {
  Serial.write(!digitalRead(19));
}

void soundSensor() {
  scmUtils.soundSensorBegin(A5);
  Serial.write(scmUtils.soundSensorPlotterAnalogRead(A5));
}

void soilMoistureSensor() {
  Serial.write(int(_sbeGetValOfMoisture(A5)));
}

void temperatureSensor() {
  sensors_19.setResolution(SENSOR_BIT);
  Serial.write(int(_sbeGetTemperature_19()));
}

void accelerationSensor() {
  Serial.write(int(relativeAngleX()));
}

void distanceSensor() {
  Serial.write((byte)_sbeGetDistanceUsingDistanceSensor(18 , 19));
}

/***************************************************************/

void changeSensorType(int type) {
    switch(type) {
        case 1:
            touchSensor();
            break;
        case 2:
            brightnessSensor();
            break;
        case 3:
            magneticSensor();
            break;
        case 4:
            passingSensor();
            break;
        case 5:
            soundSensor();
            break;
        case 6:
            soilMoistureSensor();
            break;
        case 7:
            temperatureSensor();
            break;
        case 8:
            accelerationSensor();
            break;
        case 9:
            distanceSensor();
            break;
    }
}

void setup() {
  Serial.begin(9600);
  pinMode(19, INPUT);
  if(sensorType==8){
    Wire.begin();
    AcceleroMeterAngleSetup();
  }
}

void loop() {
    changeSensorType(sensorType);
}

ProcessingIDEのコード

add_library('serial')
add_library('sound')

myPort = None
available_serialport = 2
arduinoPort = Serial.list()[available_serialport]
popupWidth = 0
popupHeight = 0
sensingValue = 0
triggerValue = 10

popup_img = "haunted_house_popup.png"
background_img = "haunted_house_background.png"
sound_file = "haunted_house_sound.mp3"

playMode = 1
# 1: Interrupt sound playback
# 2: Play sound until the end

def stopSound():
    global popupWidth, popupHeight
    if playMode == 1:
        popupWidth = 0
        popupHeight = 0
        if sound.isPlaying():
            sound.stop()
    elif playMode == 2:
        if not sound.isPlaying():
            popupWidth = 0
            popupHeight = 0

def setup():
    global myPort, popup_img, background_img, sound
    popup_img = loadImage(popup_img)
    background_img = loadImage(background_img)
    this.surface.setSize(background_img.width, background_img.height)
    myPort = Serial(this, arduinoPort, 9600)
    imageMode(CENTER)
    sound = SoundFile(this, sound_file)

def draw():
    background(background_img)
    image(popup_img, width/2, height/2, popupWidth, popupHeight)

def serialEvent(myPort):
    global sensingValue, popupWidth, popupHeight
    if myPort.available() > 0:
        sensingValue = int(myPort.read())
        println(sensingValue)
        if sensingValue <= triggerValue:
            popupWidth = popup_img.width
            popupHeight = popup_img.height
            if not sound.isPlaying():
                sound.play()
        else:
            stopSound()
キャロット
キャロット

このページのHelloNoは、050011 です!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です