alanhc 互動技術-week15

alanhc 互動技術-week15

December 19, 2019
 我實在不知道期末作業做什麼比較好,而且我也想做到期末作品人家可以投我的作品,找了很久有沒有一些有趣的應用
我發現有人做一個使用arduino與tensorflow.js的應用
參考文章
但這可能有點進階,在還沒有任何web開發經驗的我來說有點早,因此我找了幾個影片學怎麼寫node跟javascript等等
然後socket的寫法我大部分是跟著這影片學,再加上一些其他文章的參考

發現其實google有個叫做chrome music lab的地方,也很有趣,也讓我確定要做的東西
chrome music lab

實在想做一點機器學習的東西,剛好有個函式庫叫做ml5.js他是基於tensorflow.js的一個簡單容易上手的函示庫
直接看文件就好,因為他也很好上手 [ 文件 ]
等等會有更詳細的解說

p5.js serial的寫法 [ doc ]

簡述

  • index.html > 網頁進入點 沒有特別的,不多加論述
  • p5.serialport.js > 要匯入的library 請參照 [ doc ]
  • main.js > 裡面有setup()跟draw()
  • serial.js > 直接把一些重要函式包再一起放在這
執行前需要先把整個repository clone下來,執行node startserver.js,由於它是由node去做的

serial.js

initSerial() 會放在到時候彙整的setup() 或在此實驗是在main.js呼叫

let serial="/dev/ttyACM0";
let latestData = "waiting for data";

function initSerial() {

  serial = new p5.SerialPort();
  serial.list();

  serial.open("/dev/ttyACM0");
  serial.on('connected', serverConnected);

  serial.on('list', gotList);
  serial.on('data', gotData);
  serial.on('error', gotError);
  serial.on('open', gotOpen);

  serial.on('close', gotClose);
}

function serverConnected() {
  print("Connected to Server");
}
function gotList(thelist) {
  print("List of Serial Ports:");
  for (let i = 0; i < thelist.length; i++) {
    print(i + " " + thelist[i]);
  }
}

function gotOpen() {
  print("Serial Port is Open");
}

function gotClose(){
    print("Serial Port is Closed");
    latestData = "Serial Port is Closed";
}

function gotError(theerror) {
  print(theerror);
}
let ax,ay,az;
function gotData() {
  let currentString = serial.readLine(); 
  trim(currentString);                   
  if (!currentString) return;           
  let splitString = split(currentString, '\t');
  ax=float(splitString[1]);
  ay=float(splitString[2]);
  az=float(splitString[3]);
 
 
  latestData = currentString;
}
function gotRawData(thedata) {
 
}

p5.js的介面函式庫 [ doc ]

由於在期中作業時發現有人使用gui的函式庫,我也找了一個是p5.touchgui,節省一點時間
Image of three different presets for p5.touchgui: Blue, Rose, and Seafoam
 
簡述

  • index.html > 網頁進入點 沒有特別的,不多加論述
  • g_m.js > 做場景切換等環境變數的設定
  • gui.js > 直接在此畫gui

gui.js


let b_go, t_set, s_volume;

let pre_stage;

function init_gui_layout() {
  pre_stage=0;
 
  gui = createGui();
  gui.loadStyle("Blue");
  b_go = createButton("start", cx-50,cy,100,50);
  t_set = createToggle("▽", cx/10, cy/10, 50,50);
  s_volume = createSlider("volume", cx,cy-75);
 
  b_go.onPress = function() {
    if (stage==0) stage++;
  }
  t_set.onPress = function() {
    if (stage!=-1) pre_stage=stage;
    if (t_set.val) stage=-1;
    else stage=pre_stage;
  }

 
 
  t_set.labelOn  = "△";
  t_set.labelOff = "▽";

}


function gui_layout() {
  drawGui();
 
  switch(stage) {
    default:
    break; case -1:
      b_go.visible = false;
    break; case 0:
      b_go.visible = true;
    break; case 1:
      b_go.visible = false;
    break; case 2:
     
  }
  s_volume.visible = t_set.val;
 
  if (s_volume.isChanged) {
    volume = s_volume.val;
  }
  s_volume.val = volume;
 
}

ml5.js [ doc ]

簡述

  • index.html > 網頁進入點 
  • sketch.js > 裡面有setup()跟draw() 做主要控制
  • ml5.js > 把ml5.js分為初始的函式跟loop
  • serial.js
  • p5.serialport.js

index.html




<head>
  <meta charset="UTF-8">
  <title>XY Classifier</title>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.sound.min.js"></script>
  <script src="https://unpkg.com/ml5@0.4.3/dist/ml5.min.js" type="text/javascript"></script>
</head>

<body>
  <h1>Teachable Air Drum</h1>
  <script src="sketch.js"></script>
  <script src="ml5.js"></script>
  <script src="serial.js"></script>
  <script src="p5.serialport.js"></script>
  <p>
    Label: <select id="label">
      <option value="bdrum">bdrum</option>
      <option value="crash">crash</option>
      <option value="hh_c">hh_c</option>
      <option value="tom1">tom1</option>
      <option value="tom2">tom2</option>
      <option value="up">up</option>

    </select>
    <button id="train">train</button>
  </p>
  <p>
    Classification: <span id="classification"></span>
  </p>

  <p>
    Click in canvas to add training data.  <span id="device_data"></span>
  </p>

</body>

</html>

sketch.js


let brain;

function setup() {
  let canvas = createCanvas(400, 400);
 
  canvas.mousePressed(addData);
  init_ml5js();
 
  // Train Model button
  select('#train').mousePressed(trainModel);

  background(0);
  initSerial();
 
}


function draw()
{
 
  textAlign(LEFT);
  select('#device_data').html("acc is "+ax+","+ay+","+az);
 
}

ml5.js


function init_ml5js()
{
 
  // Create ethe model
  const options = {
    inputs: ['x', 'y'], 
    outputs: ['label'],
    layers: [
        ml5.tf.layers.dense({
            units: 50,
            inputShape: [3],
            activation: 'relu',
        }),
        ml5.tf.layers.dense({
            units: 25,
            activation: 'relu',
        }),
       
        ml5.tf.layers.dense({
            units: 6,
            activation: 'sigmoid',
        })
    ],
    debug: true,
    task: 'classification'
  }
  brain = ml5.neuralNetwork(options);
 
}

// Add a data record
function addData() {

  let label = select('#label').value();
  // Add data
  brain.addData({x:ax, y:ay, z:az}, {label});


  stroke(255);
  noFill();
  ellipse(mouseX, mouseY, 32);
  fill(255);
  textSize(16);
  textAlign(CENTER, CENTER);
  text(label, mouseX, mouseY);
}

// Train the model
function trainModel() {
  brain.normalizeData();
 
  brain.train({ epochs: 200 }, finishedTraining);
}

// When the model is trained
function finishedTraining() {
  brain.classify([ax, ay, az], gotResults);
}

// Got a result
function gotResults(error, results) {
  if (error) {
    console.error(error);
    return;
  } // Show classification
  select('#classification').html(results[0].label);
  // Predict again
  brain.classify([ax, ay, az], gotResults);
}
serial.js
請參考前一部分的serial