TI-Nspire & Arduino、超音波距離計 3、超音波モジュールをサーボに載せて左右に振る

An ultrasonic module mounted on a servo horn would act just like a radar or sonar.
By running the following code, Leo will transmit range and angle data to the TI-Nspire in the format of a space-delimited string, "range angle".
Drawing residual images will make the display appear to be a radar.
 
f:id:ti-nspire:20160904151617j:plain:h315
 
.ino

#include <Servo.h>
#define ultraPin 7
#define servoPin 9
int deg = 0;

class Ultrasonic {
  public:
    Ultrasonic(int pin);
    void DistanceMeasure(void);
    float microsecondsToCentimeters(void);
  private:
    int _pin;
    float duration;
};
Ultrasonic::Ultrasonic(int pin) {
  _pin = pin;
}

void Ultrasonic::DistanceMeasure(void) {
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delayMicroseconds(2);
  digitalWrite(_pin, HIGH);
  delayMicroseconds(5);
  digitalWrite(_pin, LOW);
  pinMode(_pin, INPUT);
  duration = (float)pulseIn(_pin, HIGH);
}

float Ultrasonic::microsecondsToCentimeters(void) {
  return duration / 29.0 / 2.0;
}

Ultrasonic ultrasonic(ultraPin);
Servo myservo;

void setup() {
  myservo.attach(servoPin);
  Serial.begin(115200);
}

void loop() {
  while(deg < 160) {
    if(Serial.available() && Serial.read() == 'T') {
      myservo.write(deg);
      ultrasonic.DistanceMeasure();
      Serial.print(ultrasonic.microsecondsToCentimeters());
      Serial.print(" ");
      Serial.println(deg);
      deg = deg + 1;
      delay(0);
    }
  }
  while(deg > 20) {
    if(Serial.available() && Serial.read() == 'T') {
      myservo.write(deg);
      ultrasonic.DistanceMeasure();
      Serial.print(ultrasonic.microsecondsToCentimeters());
      Serial.print(" ");
      Serial.println(deg);
      deg = deg - 1;
      delay(0);
    }
  }
}


.lua

require "asi" require "color"
platform.window:setBackgroundColor(color.black)

function on.resize() 
   W, H = platform.window:width(), platform.window:height()
   X0, Y0 = W/2, H
   UNIT = H/50 -- 1 cm = H/50 pixels 
   fontSize = W/13.25
end
function polar2screen(r, deg, x0, y0, unit)
   local rad = math.rad(deg)
   local x, y = r * math.cos(rad), r * math.sin(rad)
   return x0 + x * unit, y0 - y * unit
end
function constrain(var, min, max)
   return math.max(min, math.min(var, max))
end

local PORT
local DATA = 0
local RANGE = {}
local DEGREE = {}

-----------------------------------
-- シリアルデータの読み取り要求函数
-----------------------------------
function requestData()
      PORT:write('T')
      PORT:read()
end

--------------------------------------------------------------------------------
-- ASI ステートリスナーを定義する(ASI の準備が整ったらポートスキャンを開始する)
--------------------------------------------------------------------------------
function stateListener(state) 
   if state == asi.ON then 
      asi.startScanning(portScanner)
   end
end

----------------------------------------------------------------
-- ポートスキャナーを定義する(見つかったポートに接続要求を出す)
----------------------------------------------------------------
function portScanner(port) 
   port:connect(portConnector) 
end

-----------------------------------------------------------------------------------------------------
-- ポートコネクターを定義する
-----------------------------------------------------------------------------------------------------
function portConnector(port, event)  
   PORT = port
   if event == asi.CONNECTED then
      asi.stopScanning()
      requestData() 
      port:setReadListener(readListener)
   end 
end

----------------------------------------------------------------------------
-- 読み取りリスナーを定義する(データを取得し、またデータ読み取り要求を出す) 
----------------------------------------------------------------------------
function readListener(port)
   DATA = port:getValue() or 0
   RANGE[#RANGE+1], DEGREE[#DEGREE+1] = unpack(string.split(DATA))
   if #RANGE > 255 then
      table.remove(RANGE, 1)
      table.remove(DEGREE, 1)
   end 
   platform.window:invalidate()
   requestData() 
end

---------------------------------
-- ASI ステートリスナーを登録する
---------------------------------
function on.construction() 
   asi.addStateListener(stateListener)
end

-------------------------------------------------------------------------------
function on.paint(gc)
   gc:setFont("sansserif", "r", fontSize)
   gc:setColorRGB(0, 255, 0)
--   gc:drawString((RANGE[#RANGE] or "NO DATA").." cm", 0, 0)
--   gc:drawString((DEGREE[#DEGREE] or "NO DATA").." °", 0, 30)
   gc:setPen("thin")
   for i = 1, #RANGE do
      gc:setColorRGB(i, 0, 0)
      gc:drawLine(X0, Y0, polar2screen(50, DEGREE[i], X0, Y0, UNIT))
      gc:setColorRGB(0, i, 0)
      gc:drawLine(X0, Y0, polar2screen(constrain(RANGE[i], 0, 50), DEGREE[i], X0, Y0, UNIT))
   end
end