2013年6月13日木曜日

ruby gem 'aruduino_firmata'のsysexを用いたI2C通信(温度センサと気圧センサ)でのlinda-arduino-sensor的なもの

2013/06/14-18:11JST u2sで負の値の求め方の間違いを修正(緑色)

気圧の値も妥当なものになった(と思う).
2013/06/14-13:30JST 返り値のバイト数が要求バイト数と合っていないことがあるのでその場合スキップするように修正(赤色)
これまでの記事(APT7410MPL115A2)でのコードを利用したlinda-arduino-sensor的なもの
#!/usr/bin/env ruby 
require 'rubygems'
require 'sinatra/rocketio/linda/client'
require 'arduino_firmata'
$stdout.sync = true

url   = ENV["LINDA_BASE"]  || ARGV.shift || "http://localhost:5000"
space = ENV["LINDA_SPACE"] || "test"
linda = Sinatra::RocketIO::Linda::Client.new url
ts = linda.tuplespace[space]

linda.io.on :connect do  ## RocketIO's "connect" event
  puts "connect!! <#{linda.io.session}> (#{linda.io.type})"
end

linda.io.on :disconnect do
  puts "RocketIO disconnected.."
end

STRING_DATA= 0x71
I2C_REQUEST= 0x76
I2C_REPLY= 0x77
I2C_CONFIG= 0x78

_WRITE= 0x00
_READ= 0x08

ADDRESS_ADT7410= 0x48
ADDRESS_MPL115A2= 0x60

#MPL115A2 coefficients
a0= b1= b2= c12= 0.0

def readByte(data, pos)
  return data[pos]+data[pos+1]*(1<<7)
end

def readData(msb, lsb)
  return (msb<<8)+lsb
end

def u2s(v)
  return (v<(1<<15)) ? v : v-(1<<15)*2
end

def bytes2str(bytes)
  ret= ''
  bytes.each do |o|
    ret+= o.chr
  end
  return ret;
end

def decodeData(data)
  ret= {}
  ret[:address]= readByte(data, 0) if (data.length>1)
  ret[:register]= readByte(data, 2) if (data.length>3)
  ary= [];
  i= 4
  while i+1<data.length
    ary.push( readByte(data, i))
    i+= 2
  end
  ret[:data]= ary
  return ret;
end

arduino = ArduinoFirmata.connect ENV["ARDUINO"], :nonblock_io => true

arduino.on :sysex do |command, data|
  #puts "command : #{command}"
  #puts "data    : #{data.inspect}"
  data= (command == STRING_DATA) ? bytes2str(data) : decodeData(data)
  if command == STRING_DATA
    p data
  elsif command == I2C_REPLY
    if data[:address] == ADDRESS_ADT7410
      if data[:data].length == 2
        tout= u2s(readData(data[:data][0], data[:data][1])) / (1<<7).to_f
        ts.write ["sensor", "temperature", tout]
      end
    elsif data[:address] == ADDRESS_MPL115A2
      if data[:register] == 0x04
        if data[:data].length == 8
          a0 = u2s(readData(data[:data][0], data[:data][1]))/(1<< 3).to_f
          b1 = u2s(readData(data[:data][2], data[:data][3]))/(1<<13).to_f
          b2 = u2s(readData(data[:data][4], data[:data][5]))/(1<<14).to_f
          c12= u2s(readData(data[:data][6], data[:data][7]))/(1<<24).to_f
        end
      elsif data[:register] == 0x00
        if data[:data].length == 4
          padc= readData(data[:data][0], data[:data][1])>>6
          tadc= readData(data[:data][2], data[:data][3])>>6
          pcomp= a0 + ( b1 + c12 * tadc ) * padc + b2 * tadc
          pout= pcomp * 650.0/1023.0 + 500.0
          ts.write ["sensor", "pressure", pout] if padc>0
        end
      end
    end
  end
end

#i2c enable
arduino.sysex I2C_CONFIG, [0x00, 0x00]

#APT7410 16bit mode
arduino.sysex I2C_REQUEST, [ADDRESS_ADT7410, _WRITE, 0x03, 0x00, 0x00, 0x01]

#MPL115A2 coefficients
arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _READ, 0x04, 0x00, 0x08, 0x00]

loop do
  arduino.sysex I2C_REQUEST, [ADDRESS_ADT7410, _READ, 0x00, 0x00, 0x02, 0x00]

  arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _WRITE, 0x12, 0x00, 0x01, 0x00]
  sleep 0.02
  arduino.sysex I2C_REQUEST, [ADDRESS_MPL115A2, _READ, 0x00, 0x00, 0x04, 0x00]

  sleep 1
end

0 件のコメント: