2015年2月27日 星期五

修改S4A韌體

前一節修改S4A腳位定義,也修改S4A韌體中對應的腳位,但Arduino感測器種類繁多,不是都修改腳位就可使用,部分感測器需加入特定函式庫這些都要在S4A韌體中自行撰寫。

本篇以超音波為例:
超音波感測器(老外好像把它叫作 PING))) sensor)是由超音波發射器、接收器和控制電路所組成。當它被觸發的時候,會發射一連串 40 kHz 的聲波並且從離它最近的物體接收回音。超音波是人類耳朵無法聽見的聲音,因為它的頻率很高。





加入到Arduino的libraries中



// NEW IN VERSION 1.5:
// Changed pin 8 from standard servo to normal digital output

// NEW IN VERSION 1.4:
// Changed Serial.print() for Serial.write() in ScratchBoardSensorReport function to make it compatible with latest Arduino IDE (1.0)

// NEW IN VERSION 1.3:
// Now it works on GNU/Linux. Also tested with MacOS and Windows 7.
// timer2 set to 20ms, fixing a glitch that made this period unstable in previous versions.
// readSerialport() function optimized.
// pulse() modified so that it receives pulse width as a parameter instead using a global variable.
// updateServoMotors changes its name as a global variable had the same name.
// Some minor fixes.

// Thanks to Jorge Gomez for all these new fixes!
#include <Ultrasonic.h>// 超音函式褲
#define TIMER2_PRELOAD 100

#define TRIGGER_PIN  5 //觸發超音波
#define ECHO_PIN     A5 //傳回偵測值
Ultrasonic ultrasonic(TRIGGER_PIN, ECHO_PIN);

char outputs[10];
int states[10];

unsigned long initialPulseTime;
unsigned long lastDataReceivedTime;

volatile boolean updateServoMotors;
volatile boolean newInterruption;

void setup()
{
  Serial.begin(38400);
  Serial.flush();
  configurePins();
  configureServomotors();
  lastDataReceivedTime = millis();
}

void loop()
{
  if (updateServoMotors)
  {
    sendUpdateServomotors();
    sendSensorValues();
    updateServoMotors = false;
  }
  else
  {
    readSerialPort();
  }
}

void configurePins()
{
  for (int index = 0; index < 10; index++)
  {
    states[index] = 0;
    pinMode(index+4, OUTPUT);
    digitalWrite(index+4, LOW); //reset pins
  }

  pinMode(2,INPUT);
  pinMode(3,INPUT);

  outputs[0] = 'c'; //pin 4
  outputs[1] = 'a'; //pin 5
  outputs[2] = 'a'; //pin 6
  outputs[3] = 'c'; //pin 7
  outputs[4] = 's'; //pin 8
  outputs[5] = 'a'; //pin 9
  outputs[6] = 'd'; //pin 10
  outputs[7] = 'd'; //pin 11
  outputs[8] = 'd'; //pin 12
  outputs[9] = 'd'; //pin 13
}

void configureServomotors() //servomotors interruption configuration (interruption each 10 ms on timer2)
{
  newInterruption = false;
  updateServoMotors = false;

  TCCR2A = 0;
  TCCR2B = 1<<CS22 | 1<<CS21 | 1<<CS20;
  TIMSK2 = 1<<TOIE2; //timer2 Overflow Interrupt
  TCNT2 = TIMER2_PRELOAD; //start timer
}

void sendSensorValues()
{
  int sensorValues[6], readings[5], sensorIndex;
  for (sensorIndex = 0; sensorIndex < 5; sensorIndex++)  // 將原來的 6 改為 5
  {
    for (int p = 0; p < 5; p++)
      readings[p] = analogRead(sensorIndex);
    InsertionSort(readings, 5); //sort readings
    sensorValues[sensorIndex] = readings[2]; //select median reading
  }

  //send analog sensor values
  for (sensorIndex = 0; sensorIndex < 5; sensorIndex++)  // 將原來的 6 改為 5
    ScratchBoardSensorReport(sensorIndex, sensorValues[sensorIndex]);

  // 自已定義的程序
  ReadExtra();  // 讀取超音波

  //send digital sensor values
  ScratchBoardSensorReport(6, digitalRead(2)?1023:0);
  ScratchBoardSensorReport(7, digitalRead(3)?1023:0);
}

void ReadExtra()  // 自已定義的程序,讀取超音波
{   
  long microsec = ultrasonic.timing();  // 取得傳回時間
  float cmMsec = ultrasonic.convert(microsec, Ultrasonic::CM); // 計算距離,單位: 公分
  ScratchBoardSensorReport(5, cmMsec);  // 將讀取的類比角位傳回 Arduino
}

void InsertionSort(int* array, int n)
{
  for (int i = 1; i < n; i++)
    for (int j = i; (j > 0) && ( array[j] < array[j-1] ); j--)
      swap( array, j, j-1 );
}

void swap (int* array, int a, int b)
{
  int temp = array[a];
  array[a] = array[b];
  array[b] = temp;
}

void ScratchBoardSensorReport(int sensor, int value) //PicoBoard protocol, 2 bytes per sensor
{
  Serial.write( B10000000
    | ((sensor & B1111)<<3)
    | ((value>>7) & B111));
  Serial.write( value & B1111111);
}

void readSerialPort()
{
  int pin, inByte, sensorHighByte;

  if (Serial.available() > 1)
  {
    lastDataReceivedTime = millis();
    inByte = Serial.read();

    if (inByte >= 128) // Are we receiving the word's header?
    {
      sensorHighByte = inByte;
      pin = ((inByte >> 3) & 0x0F);
      while (!Serial.available()); // Wait for the end of the word with data
      inByte = Serial.read();
      if (inByte <= 127) // This prevents Linux ttyACM driver to fail
      {
        states[pin - 4] = ((sensorHighByte & 0x07) << 7) | (inByte & 0x7F);
        updateActuator(pin - 4);
      }
    }
  }
  else checkScratchDisconnection();
}

void reset() //with xbee module, we need to simulate the setup execution that occurs when a usb connection is opened or closed without this module
{
  for (int pos = 0; pos < 10; pos++)  //stop all actuators
  {
    states[pos] = 0;
    digitalWrite(pos + 2, LOW);
  }

  //reset servomotors
  newInterruption = false;
  updateServoMotors = false;
  TCNT2 = TIMER2_PRELOAD;

  //protocol handshaking
  sendSensorValues();
  lastDataReceivedTime = millis();
}

void updateActuator(int pinNumber)
{
  if (outputs[pinNumber] == 'd')  digitalWrite(pinNumber + 4, states[pinNumber]);
  else if (outputs[pinNumber] == 'a')  analogWrite(pinNumber + 4, states[pinNumber]);
}

void sendUpdateServomotors()
{
  for (int p = 0; p < 10; p++)
  {
    if (outputs[p] == 'c') servomotorC(p + 4, states[p]);
    if (outputs[p] == 's') servomotorS(p + 4, states[p]);
  }
}

void servomotorC (int pinNumber, int dir)
{
  if (dir == 1) pulse(pinNumber, 1300); //clockwise rotation
  else if (dir == 2) pulse(pinNumber, 1700); //anticlockwise rotation
}

void servomotorS (int pinNumber, int angle)
{
  if (angle < 0) pulse(pinNumber, 600);
  else if (angle > 180) pulse(pinNumber, 2400);
  else pulse(pinNumber, (angle * 10) + 600);
}

void pulse (int pinNumber, int pulseWidth)
{
  initialPulseTime = micros();
  digitalWrite(pinNumber, HIGH);

  while (micros() < pulseWidth + initialPulseTime){
  }
  digitalWrite(pinNumber, LOW);
}

void checkScratchDisconnection() //the reset is necessary when using an wireless arduino board (because we need to ensure that arduino isn't waiting the actuators state from Scratch) or when scratch isn't sending information (because is how serial port close is detected)
{
  if (millis() - lastDataReceivedTime > 1000) reset(); //reset state if actuators reception timeout = one second
}

ISR(TIMER2_OVF_vect) //timer1 overflow interrupt vector handler
{ //timer2 => 8 bits counter => 256 clock ticks
  //preeescaler = 1024 => this routine is called 61 (16.000.000/256/1024) times per second approximately => interruption period =  1 / 16.000.000/256/1024 = 16,384 ms
  //as we need a 20 ms interruption period but timer2 doesn't have a suitable preescaler for this, we program the timer with a 10 ms interruption period and we consider an interruption every 2 times this routine is called.
  //to have a 10 ms interruption period, timer2 counter must overflow after 156 clock ticks => interruption period = 1 / 16.000.000/156/1024 = 9,984 ms => counter initial value (TCNT) = 100
  if (newInterruption)
  {
    updateServoMotors = true;
  }
  newInterruption = !newInterruption;
  TCNT2 = TIMER2_PRELOAD;  //reset timer
}

2015年2月7日 星期六

APP控制S4A應用程式

範例:電流急急棒

1.新建立的檔案無法取得虛擬感測器積木,必須先用控制S4A的APP傳送虛擬感測器數值才能產生虛擬感測積木。

各種音效





APP的部分我以Inventor2開發,其中ballX跟ballY要同時傳送所以傳送虛擬感測器給S4A語法要加&連結。
EX:http://IP位址:42001/?sensor-update=ballY=感測值&sensor-update=ballX=感測值

2015年1月26日 星期一

S4A TOUCH

今天看到Arduino Touch感測元件,想起大朋友小朋友都愛看的海賊王裡面的腳色MR.2的變臉,於是做了這個小實驗。

Arduino範例:
http://www.arvydas.co.uk/2012/08/arduino-touch-sensor-ky036/

  • 需要材料:




  • 電路圖:





  • Scratch程式碼:


2015年1月23日 星期五

變更 S4A 的 PIN 腳定義以符合不同的硬體需求

由於今天有在實驗室看到紅外線接收模組想說來玩玩,但上網爬文好像Arduino那邊可以載入library支援,但S4A的限制其中之一是內定腳位,腳位的功能被定住,不像在Arduino程式語言中那麼自由;另一個是不支援library,不能用I2C、SPI或與時脈有關的控制,只能用標準的數位IO及類比IO,特殊的功能,S4A內定的就是支援伺服馬達與連續伺服馬達而已。

接下來就要來更改S4A韌體的部分(感謝范運平老師的文章)

S4A改韌體和更改Arduino驅動範例:8X8矩陣LED
http://beardad1975.blogspot.tw/2014/04/ledMatrixFirmware.html

1.滑鼠移到 [檔案] 上方,按著 shift + 滑鼠左鍵,在跳出選單中選 Exit User Mode



2.接著你會發現程式下方及右邊多了空白區域 (表示已經進到編輯模式了),請在下方空白區域     點一下 滑鼠右鍵,在跳出的選單中點選 open ,再來選 browser



3.跳出 System Browser 視窗後,調整左側拉把來到最底 S4A 選項




4.點選 S4A ArduinoScratchSpriteMorth other acruator ops analogPinNumbers,然後在下方編 輯區    把原來的原來的數位模擬類比的 pwm 腳位(9,6,5)改成(4,5,6,7,8,9,10,11)




PS:要記得按accept存檔會出現框框隨便打,之後就不會出現了

5.連續旋轉伺服馬達(4,7,8)不再需要,可在 continuousServoPinNum 點右鍵移除


6..改完了 digital、analog、 motor 的腳位定義之後其實就算大功告成了,不過還有一個地方要       改,進 到 S4A ArduinoScratchSpriteMorth,將原來 instance 模式切成 class 模式。







7.有新的選項 blockspace,這裡設定的是左方選單的預設值,原來連續旋轉伺服馬達的不需要 了,可以把它整段拿掉,其他的就改預設要顯示的腳位就好了。



8..最後,選取 System Browser 左方的 x ,關閉 System Browser。回到工具列,同樣滑鼠移到 [檔     案] 上 方,按著 shift + 滑鼠左鍵,在跳出選單中選 Save Image in User Mode ,再按 Yes 確       定,程式就 會關閉,下次再開 S4A 就會套用新的設定了。













2015年1月22日 星期四

S4A模擬哆啦A夢放大/縮小燈

今天用了 光敏電阻跟RGB LED來做Scratch控制圖片縮放
模擬哆啦A夢放大/縮小燈XD

光敏電阻與RGB LED一開始不會使用GOOGLE大神先爬文

http://coopermaa2nd.blogspot.tw/2010/12/arduino-lab8-led.html

http://yehnan.blogspot.tw/2013/01/arduinorgb-led.html

  • RGB
    • 綠燈對光敏電阻比較好增加阻值

  • 3腳光敏電阻
 S腳為偵測
       中間腳為GND
-腳為VCC
  • 電路圖:
  • Scratch程式碼:

2015年1月21日 星期三

用keyes_SJoys(搖桿)控制腳色移動


  • 下圖為本次實驗測試搖桿:

  • 需要材料
    1. 搖桿 x 1
    2. 線材
  • 電路圖





  • Scratch程式碼:






2015年1月20日 星期二

S4A控制LED


安裝完S4A就來個小實作


  • 需要材料
    1. 電阻10k x 1
    2. 按鈕 x 1
    3. 線材

  • 電路圖如下:




  • Scratch程式碼:



2015年1月19日 星期一

S4A安裝環境

S4A(Scratch for Arduino )環境安裝

Scratch的簡介

Scratch是 MIT (麻省理工學院) 發展的一套新的程式語言,可以用來創造互動式故事、動畫、遊戲、音 樂和藝術。很適合國小小朋友使,目前1.4版已經有 支援中文介面更方便使用,完全不用背指令,使用積木組合式的程式語言。

關於S4A

S4A是Scratch的修改,允許Arduino開放原始碼和硬體平台的簡單編程。它提供了用於管理連接到Arduino的管理感應器。

安裝Arduino


安裝S4A


安裝上述兩項完後打開Arduino,把代碼複製貼上燒入即可



1.打開Arduino



2.將代碼複製貼上燒錄


3.打開S4A會自動連上Arduino