Hatena::ブログ(Diary)

urekatのスカンク日記3 このページをアンテナに追加 RSSフィード

2007-06-22

[][]rubyで3D物理シミュレーション

rubyからODEを使えるようになったのでとりあえずうp。

http://ssktkr.com/ode-ruby5.tgz

D


こんなソースで3Dシミュレーションできます!

require "ode"
require "draw_stuff"
require "pp"
require "dl"

$world = Ode::World.new
$world.gravity = [0.0, 0.0, -0.2]                            # 重力設定
$space        = Ode_lib.dHashSpaceCreate(nil);               # 衝突用空間の創造
$contactgroup = Ode_lib.dJointGroupCreate(0);                # ジョイントグループの生成
$ground       = Ode_lib.dCreatePlane($space, 0,0, 1.0, 0.0); # 平面ジオメトリの生成

def rand_within(from, to)
  rand*(to-from)+from
end

$objects = []
100.times{
  $objects << Ode::Material::Ball.new(:m=>rand_within(1,9),
                                      :r=>rand_within(1,5),
                                      :position=>[rand_within(-7,7), rand_within(-7,7), rand_within(5,500)],
                                      :color=>[rand(2).to_f, rand(2).to_f, rand(2).to_f] )
}
$objects << Ode::Material::Box.new(:m=>1000.0,
                                   :x=>10.0, :y=>50.0, :z=>50.0,
                                   :position=> [-30.0, 0.0, 30.0],
                                   :color   => [0.3, 0.0, 0.0] )

ds = DrawStuff.new
ds.world  = $world
ds.width  = 800
ds.height = 600
ds.path_to_textures = "../drawstuff/textures"
def ds.start
  puts "start"
  xyz = [  50.0,   0.0,   1.0] # 視点の位置
  hpr = [-180.0,  20.0,   0.0] # 視線の方向
  DrawStuff::DSLib.dsSetViewpoint(xyz.to_ptr("F"), hpr.to_ptr("F")) # カメラの設定
end

def ds.step(pause)
  @step_count += 1
  if @step_count%5000==0
    puts "=============================================="
    puts "step #{pause} #{@step_count}"
    xyz = [0.0, 0.0, 0.0].to_ptr("F") # 視点の位置
    hpr = [0.0, 0.0, 0.0].to_ptr("F") # 視線の方向
    DrawStuff::DSLib.dsGetViewpoint(xyz, hpr)
    puts "xyz = " + xyz.to_a("F").inspect
    puts "hpr = " + hpr.to_a("F").inspect
  end

  Ode_lib.dSpaceCollide($space, Proc.new{|o1,o2|
#    puts "cb #{o1._ptr} #{o2._ptr} #{$ground._ptr} #{$ground._ptr==o1._ptr} #{$ground._ptr==o2._ptr}"
    # 衝突検出
    #if $ground._ptr==o1._ptr || $ground._ptr==o2._ptr
      contact_geoms = Ode_lib.dCollide(o1, o2, 10000) # 衝突情報の生成
      contact_geoms.each do |cg|
        # pp cg
        contact = Ode_lib::DContact.new
        contact.geom = cg
        contact.surface.mode       = Ode_lib::DContactBounce; # 接触面の反発性を設定
        contact.surface.bounce     = 0.8;            # 反発係数(0.0から1.0)
        contact.surface.bounce_vel = 1.0;            # 反発に必要な最低速度
        # 接触ジョイントの生成
        joint = Ode_lib.dJointCreateContact($world._id, $contactgroup, contact)
        # 接触している2つの剛体を接触ジョイントにより拘束
        Ode_lib.dJointAttach(joint, Ode_lib.dGeomGetBody(cg.g1), Ode_lib.dGeomGetBody(cg.g2))
      end
    #end
  });

  @world.step(0.05)
  Ode_lib.dJointGroupEmpty($contactgroup); # ジョイントグループを空にする
  $objects.each{|o| o.draw }
end

def ds.command(cmd)
  puts "command #{cmd}"
end

def ds.stop
  puts "stop"
end

ds.run

今回学んだ技術:

- SWIG

- Ruby/DL

- Ruby拡張ライブラリの作り方

- Rubyの中身を少々(Ruby Hacking Guideを読んだ)

- ODE この本がすごい!

簡単!実践!ロボットシミュレーション - Open Dynamics Engineによるロボットプログラミング

簡単!実践!ロボットシミュレーション - Open Dynamics Engineによるロボットプログラミング



Wiiリモコンと組み合わせたら絶対たのしい。

[][]WiiリモコンRubyのサンプル

  • RubyCocoa-0.11.1.tgz
  • DarwiinRemote0.5.dmg
  • ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.9.1]
require 'osx/cocoa'
OSX.require_framework "WiiRemote"

class WiiRemoconTest < OSX::NSObject
  def initialize
    @discovery = nil
    @remote = nil
  end

  def init
    @discovery = OSX::WiiRemoteDiscovery.alloc.init
    @discovery.setDelegate(self)
    @discovery.start
    return self
  end

  def WiiRemoteDiscovered(remote)
    puts "WiiRemoteDiscovered remote=#{remote.inspect}"
    @remote = Remote.alloc.init
    @remote.start(remote)
    # @discovery.stop
  end

  def WiiRemoteDiscoveryError(code)
    puts "WiiRemoteDiscoveryError code=%x" % code
  end

  objc_method :WiiRemoteDiscovered,     %w{void id}
  objc_method :WiiRemoteDiscoveryError, %w{void int}
end

class Remote < OSX::NSObject
  def init
    return self
  end

  def start(remote)
    @remote = remote
    @remote.setDelegate(self)
    @remote.setMotionSensorEnabled(true)
    @remote.setIRSensorEnabled(false)
  end

  # /Library/Frameworks/RubyCocoa.framework/Versions/A/Resources/ruby/osx/objc/oc_import.rb
  # /Library/Frameworks/WiiRemote.framework/Headers/WiiRemote.h

  def irPointMovedX_Y_wiiRemote(px, py, wiiRemote)
    #puts "irPointMovedX_Y"
  end

  def buttonChanged_isPressed_wiiRemote(btn_type, is_pressed, wiiRemote)
    puts "buttonChanged_isPressed #{btn_type} #{is_pressed}"
  end

  def accelerationChanged_accX_accY_accZ_wiiRemote(type, ax, ay, az, wiiRemote)
    #p "accelerationChanged_accX_accY_accZ(%d,%d,%d,%d)" % [type,ax,ay,az]
    #p "*" * (ax/2)
    div = 3
    s = (" " * (256/div))+"|"
    s[ax/div] = "x"
    s[ay/div] = "y"
    s[az/div] = "z"
    puts s
  end

  def joyStickChanged_tiltX_tiltY_wiiRemote(type, tilt_x, tilt_y, wiiRemote)
    puts "joyStickChanged_tiltX_tiltY"
  end

  def wiiRemoteDisconnected(device)
    puts "wiiRemoteDisconnected"
  end

#- (void) irPointMovedX:(float)px Y:(float)py wiiRemote:(WiiRemote*)wiiRemote;
#- (void) rawIRData: (IRData[4])irData wiiRemote:(WiiRemote*)wiiRemote;
#- (void) buttonChanged:(WiiButtonType)type isPressed:(BOOL)isPressed wiiRemote:(WiiRemote*)wiiRemote;
#- (void) accelerationChanged:(WiiAccelerationSensorType)type accX:(unsigned char)accX accY:(unsigned char)accY accZ:(unsigned char)accZ wiiRemote:(WiiRemote*)wiiRemote;
#- (void) joyStickChanged:(WiiJoyStickType)type tiltX:(unsigned char)tiltX tiltY:(unsigned char)tiltY wiiRemote:(WiiRemote*)wiiRemote;
#- (void) analogButtonChanged:(WiiButtonType)type amount:(unsigned)press wiiRemote:(WiiRemote*)wiiRemote;
#- (void) wiiRemoteDisconnected:(IOBluetoothDevice*)device;
  objc_method :irPointMovedX_Y_wiiRemote, %w{void float float id}
  objc_method :buttonChanged_isPressed_wiiRemote, %w{void ushort char id}
  objc_method :accelerationChanged_accX_accY_accZ_wiiRemote, %w{void ushort uchar uchar uchar id}
  objc_method :joyStickChanged_tiltX_tiltY_wiiRemote, %w{void ushort uchar uchar id}
  objc_method :wiiRemoteDisconnected, %w{void id}
end

test = WiiRemoconTest.alloc.init
OSX::NSRunLoop.currentRunLoop.run

WiiRemote.frameworkをインストール

xcodeビルド。ボタン押すだけ。

で、

sudo mv WiiRemote.framework /Library/Frameworks/

インターフェイスが変わっていて前に作ったやつがうごかん。

Hello, Ruby Cocoa

どっかから持ってきたサンプルで動作確認。

require 'osx/cocoa'

class HelloApp <  OSX::NSObject
   def quit(notifier)
     exit
   end
end

app = OSX::NSApplication.sharedApplication
app.setDelegate HelloApp.alloc.init
win = OSX::NSWindow.alloc.initWithContentRect_styleMask_backing_defer([200.0, 300.0, 250.0, 60.0], 15, 2, 0)
win.setTitle 'Hello RubyCocoa'
win.setLevel(3)   # floating window
win.orderFrontRegardless
button = OSX::NSButton.alloc.initWithFrame([10.0, 10.0, 210.0, 40.0])
win.contentView.addSubview button
button.setBezelStyle 4
button.setTitle 'Hello, World!'
button.setTarget app.delegate
button.setAction 'quit:'
button.setEnabled true
app.run

おk。

[][]RubyCocoaインストール記録

バイナリパッケージをいれたら/usr/bin/rubyのほうに入ってしまった。

いつもつかってるのはportでいれた/opt/にあるやつなのでソースからインストール


tkrmb:~/Desktop/RubyCocoa-0.11.1% ruby install.rb config
install.rb: entering config phase...
create ext/rubycocoa/extconf.rb
create framework/GeneratedConfig.xcconfig
create framework/src/objc/Version.h
---> framework
create /Users/takeru/Desktop/RubyCocoa-0.11.1/framework/src/objc/osx_ruby.h ...
create /Users/takeru/Desktop/RubyCocoa-0.11.1/framework/src/objc/osx_intern.h ...
BSROOT="/Users/takeru/Desktop/RubyCocoa-0.11.1/framework/bridge-support" CFLAGS="" /opt/local/bin/ruby build.rb
Generating BridgeSupport metadata for: CoreFoundation ...
    Collect metadata (12.983316 seconds)
    Write final metadata (165.017092 seconds)
    Validate XML (0.829204 seconds)
    Generate dylib file (4.263049 seconds)
Done (183.094969 seconds).
Generating BridgeSupport metadata for: CoreData ...
    Collect metadata (5.338192 seconds)
    Write final metadata (0.439494 seconds)
    Validate XML (0.013119 seconds)
Done (5.79575 seconds).
Generating BridgeSupport metadata for: PDFKit ...
    Collect metadata (7.611306 seconds)
    Write final metadata (0.186546 seconds)
    Validate XML (0.013643 seconds)
Done (7.816811 seconds).
Generating BridgeSupport metadata for: Foundation ...
    Collect metadata (12.169901 seconds)
    Write final metadata (46.748283 seconds)
    Validate XML (0.029448 seconds)
    Generate dylib file (0.739722 seconds)
Done (59.69456 seconds).
Generating BridgeSupport metadata for: CoreGraphics ...
    Collect metadata (54.6267 seconds)
    Write final metadata (89.165918 seconds)
    Validate XML (0.279392 seconds)
    Generate dylib file (0.588252 seconds)
Done (144.667176 seconds).
Generating BridgeSupport metadata for: InstantMessage ...
    Collect metadata (5.853906 seconds)
    Write final metadata (0.029686 seconds)
    Validate XML (0.014123 seconds)
Done (5.903086 seconds).
Generating BridgeSupport metadata for: Quartz ...
    Collect metadata (5.883848 seconds)
    Write final metadata (0.006867 seconds)
    Validate XML (0.012119 seconds)
Done (5.908422 seconds).
Generating BridgeSupport metadata for: ImageIO ...
    Collect metadata (5.914733 seconds)
    Write final metadata (0.115417 seconds)
    Validate XML (0.01424 seconds)
Done (6.049777 seconds).
Generating BridgeSupport metadata for: Cocoa ...
    Collect metadata (6.183535 seconds)
    Write final metadata (0.005757 seconds)
    Validate XML (0.011465 seconds)
Done (6.207085 seconds).
Generating BridgeSupport metadata for: OpenGL ...
    Collect metadata (10.013917 seconds)
    Write final metadata (1.828747 seconds)
    Validate XML (0.051416 seconds)
Done (11.901694 seconds).
Generating BridgeSupport metadata for: QuartzComposer ...
    Collect metadata (9.726545 seconds)
    Write final metadata (0.021444 seconds)
    Validate XML (0.014132 seconds)
Done (9.767429 seconds).
Generating BridgeSupport metadata for: ApplicationServices ...
    Collect metadata (4.415054 seconds)
    Write final metadata (0.014068 seconds)
    Validate XML (0.013584 seconds)
Done (4.447495 seconds).
Generating BridgeSupport metadata for: QuartzCore ...
    Collect metadata (24.518391 seconds)
    Write final metadata (4.964294 seconds)
    Validate XML (0.01691 seconds)
Done (29.504879 seconds).
Generating BridgeSupport metadata for: SyncServices ...
    Collect metadata (12.531122 seconds)
    Write final metadata (0.319699 seconds)
    Validate XML (0.014041 seconds)
Done (12.870431 seconds).
Generating BridgeSupport metadata for: AppKit ...
    Collect metadata (53.684602 seconds)
    Write final metadata (83.972944 seconds)
    Validate XML (0.28991 seconds)
    Generate dylib file (1.237285 seconds)
Done (139.192725 seconds).
Generating BridgeSupport metadata for: AddressBook ...
    Collect metadata (18.341418 seconds)
    Write final metadata (0.775136 seconds)
    Validate XML (0.017448 seconds)
Done (19.140541 seconds).
Generating BridgeSupport metadata for: WebKit ...
    Collect metadata (43.266885 seconds)
    Write final metadata (10.299582 seconds)
    Validate XML (0.274515 seconds)
Done (53.847364 seconds).
Generating BridgeSupport metadata for: QTKit ...
    Collect metadata (25.314914 seconds)
    Write final metadata (2.986737 seconds)
    Validate XML (0.01777 seconds)
Done (28.32868 seconds).
<--- framework
---> lib
---> lib/osx
<--- lib/osx
<--- lib
---> ext
---> ext/rubycocoa
/opt/local/bin/ruby "/Users/takeru/Desktop/RubyCocoa-0.11.1/ext/rubycocoa/extconf.rb" 
creating Makefile
execute 'mv -f Makefile Makefile.bak' ...
execute 'mv -f Makefile Makefile.bak' done
execute 'sed -e 's/-no-cpp-precomp//' -e 's/-no-precomp//' Makefile.bak > Makefile' ...
execute 'sed -e 's/-no-cpp-precomp//' -e 's/-no-precomp//' Makefile.bak > Makefile' done
<--- ext/rubycocoa
<--- ext
install.rb: config done.
tkrmb:~/Desktop/RubyCocoa-0.11.1%