目次
インフラ構築と自動化が得意。TerraformとAnsibleでインフラを自動構築するお仕事が多め
工作HardwareHubからのお知らせ
Open Dynamics Engine (ODE) を用いた動力学シミュレーションを行います。ここでは ode-python を利用して Python から実行します。
インストール
以下は Linux 環境の例です。
ODE ビルド
ODE に付属する DrawStuff をビルドするためには OpenGL と GLUT が必要です。
sudo apt install -y libgl1-mesa-dev libglu1-mesa-dev
cmake を利用してビルドします。
sudo apt install -y cmake
ソースコードをこちらからダウンロードします。動的ライブラリとしてビルドします。
mv ode-0.16.1.tar.gz ode-0.16.1.tar
tar xvf ode-0.16.1.tar
mkdir -p mybuild && cd mybuild
cmake ../ode-0.16.1 -DBUILD_SHARED_LIBS=ON -DODE_WITH_DEMOS=ON
make
DrawStuff は make install でインストールできないため手動でコピーしてインストールします。
sudo cp libdrawstuff.so /usr/local/lib/
sudo cp -d libode.so.0.16.1 libode.so /usr/local/lib/
DrawStuff 利用時に必要になるためテクスチャファイルも適当な場所に保存しておきます。
sudo cp -r ode-0.16.1/drawstuff/textures /usr/local/share/ode-0.16.1-drawstuff-textures
sudo chmod -R a+x /usr/local/share/ode-0.16.1-drawstuff-textures
ode-python のインストール
python -m pip install ode-python
ボールの自由落下
ode-python では ctypes によるバインディングが行われています。ポインタ渡しでは byref を利用します。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import odepy
import drawstuffpy as ds
import ctypes
import random
def Main():
# ODE では動力学計算用の world と
# 衝突計算用の space を利用します。
world, space, ground, contactgroup = CreateWorld()
geoms = [AddBall(world, space)['geom']]
geomColors = [[random.random(), random.random(), random.random()]]
tDelta = 0.01
# 衝突が予想されるタイミングで呼び出される関数です。
def __NearCallback(data, o1, o2):
o1IsGround = ctypes.addressof(ground.contents) == ctypes.addressof(o1.contents)
o2IsGround = ctypes.addressof(ground.contents) == ctypes.addressof(o2.contents)
if not (o1IsGround or o2IsGround):
return
N = 10
contacts = (odepy.dContact * N)()
n = odepy.dCollide(o1, o2, N, ctypes.byref(contacts[0].geom), ctypes.sizeof(odepy.dContact))
for i in range(n):
contact = contacts[i]
contact.surface.mu = float('inf')
contact.surface.mode = odepy.dContactBounce
contact.surface.bounce = 0.95
contact.surface.bounce_vel = 0.0
c = odepy.dJointCreateContact(world, contactgroup, ctypes.byref(contact))
odepy.dJointAttach(c, odepy.dGeomGetBody(contact.geom.g1), odepy.dGeomGetBody(contact.geom.g2))
# tDelta で world の時間が進む毎に呼び出される関数です。
def __StepCallback(pause):
if pause != 1:
odepy.dSpaceCollide(space, 0, odepy.dNearCallback(__NearCallback))
odepy.dWorldStep(world, tDelta)
odepy.dJointGroupEmpty(contactgroup)
for geom, color in zip(geoms, geomColors):
body = odepy.dGeomGetBody(geom)
ds.dsSetColor(*color)
if odepy.dGeomGetClass(geom) == odepy.dSphereClass:
r = odepy.dGeomSphereGetRadius(geom)
pos = odepy.dBodyGetPosition(body)
rot = odepy.dBodyGetRotation(body)
ds.dsDrawSphereD(pos, rot, r)
elif odepy.dGeomGetClass(geom) == odepy.dCapsuleClass:
r = odepy.dReal()
l = odepy.dReal()
odepy.dGeomCapsuleGetParams(geom, ctypes.byref(r), ctypes.byref(l))
pos = odepy.dBodyGetPosition(body)
rot = odepy.dBodyGetRotation(body)
ds.dsDrawCapsuleD(pos, rot, l.value, r.value)
else:
raise Exception('Not supported geom class: {}'.format(odepy.dGeomGetClass(geom)))
# シミュレーションを開始します。
RunDrawStuff(__StepCallback)
# ODE を終了するための手続きを行います。
DestroyWorld(world, space)
def AddBall(world, space, m=1.0, r=0.1, pos=[0, 0, 2.0]):
mass = odepy.dMass()
odepy.dMassSetZero(ctypes.byref(mass))
odepy.dMassSetSphereTotal(ctypes.byref(mass), m, r)
body = odepy.dBodyCreate(world)
odepy.dBodySetMass(body, ctypes.byref(mass))
geom = odepy.dCreateSphere(space, r)
odepy.dGeomSetBody(geom, body)
# body は world に属します。geom は space に属します。
ball = {'body': body, 'geom': geom}
odepy.dBodySetPosition(ball['body'], *pos)
return ball
def RunDrawStuff(stepCallback, pathToTextures='/usr/local/share/ode-0.16.1-drawstuff-textures', w=400, h=225, cameraXyz=[3.0, 0.0, 1.0], cameraHpr=[-180.0, 0.0, 0.0]):
def __StartCallback():
xyz = (ctypes.c_float * 3)()
hpr = (ctypes.c_float * 3)()
for i, v in enumerate(cameraXyz):
xyz[i] = v
for i, v in enumerate(cameraHpr):
hpr[i] = v
ds.dsSetViewpoint(xyz, hpr)
fn = ds.dsFunctions()
fn.version = ds.DS_VERSION
fn.start = ds.dsStartCallback(__StartCallback)
fn.step = ds.dsStepCallback(stepCallback)
fn.path_to_textures = ctypes.create_string_buffer(pathToTextures.encode('utf-8'))
ds.dsSimulationLoop(0, ctypes.byref(ctypes.POINTER(ctypes.c_char)()), w, h, fn)
def CreateWorld():
odepy.dInitODE()
world = odepy.dWorldCreate()
odepy.dWorldSetGravity(world, 0, 0, -9.8)
space = odepy.dHashSpaceCreate(0)
ground = odepy.dCreatePlane(space, 0, 0, 1, 0)
contactgroup = odepy.dJointGroupCreate(0)
return world, space, ground, contactgroup
def DestroyWorld(world, space):
odepy.dSpaceDestroy(space)
odepy.dWorldDestroy(world)
odepy.dCloseODE()
if __name__ == '__main__':
Main()
0
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。
関連記事
- Python コードスニペット (条件分岐)if-elif-else sample.py #!/usr/bin/python # -*- coding: utf-8 -*- # コメント内であっても、ASCII外の文字が含まれる場合はエンコーディング情報が必須 x = 1 # 一行スタイル if x==0: print 'a' # 参考: and,or,notが使用可能 (&&,||はエラー) elif x==1: p...
- Python コードスニペット (リスト、タプル、ディクショナリ)リスト range 「0から10まで」といった範囲をリスト形式で生成します。 sample.py print range(10) # for(int i=0; i<10; ++i) ← C言語などのfor文と比較 print range(5,10) # for(int i=5; i<10; ++i) print range(5,10,2) # for(int i=5; i<10;...
- ZeroMQ (zmq) の Python サンプルコードZeroMQ を Python から利用する場合のサンプルコードを記載します。 Fixing the World To fix the world, we needed to do two things. One, to solve the general problem of "how to connect any code to any code, anywhere". Two, to wra...
- Matplotlib/SciPy/pandas/NumPy サンプルコードPython で数学的なことを試すときに利用される Matplotlib/SciPy/pandas/NumPy についてサンプルコードを記載します。 Matplotlib SciPy pandas [NumPy](https://www.numpy
- pytest の基本的な使い方pytest の基本的な使い方を記載します。 適宜参照するための公式ドキュメントページ Full pytest documentation API Reference インストール 適当なパッケージ