2012年10月4日木曜日

マニュピュレータ

# coding: UTF-8
# 2012/9/8 09:13
# アームの作成から 2012/09/09 ニ完成
#アーム2個 第一アーム水平回転 第二アーム固定
# manipulator10.py

import random
import ode
from visual import *

paraList = []
#box_kosuu = 4
box_kosuu = 4
objList  = []

jParaList = []
jointList = []
joint_kosuu = 3
#上のように宣言することにより appendコマンドだけで関数内
#クラス内でグローバル宣言せずにリストに追加できる


#動かすjointの選択

#パラメータ
##c言語のodeの座標からpyodeの座標へ(zとyを入れ替えるだけ)
paraList = [
        {"pos":(0,       1.00, 0 ), "m_density":2,  "v_x":2.0, "v_y":2.00, "v_z":2.0, "v_color":color.red},  #台座
        {"pos":(0,       4.50, 0 ), "m_density":0.01,  "v_x":0.5, "v_y":5.00, "v_z":0.5, "v_color":color.white},#第一アーム
        {"pos":(2.75,    6.75, 0 ), "m_density":0.01,  "v_x":5.0, "v_y":0.50, "v_z":0.5, "v_color":color.blue},
        {"pos":(7.75,    6.75, 0 ), "m_density":0.01,  "v_x":5.0, "v_y":0.50, "v_z":0.5, "v_color":color.cyan}
        ]
#objListにデータがはいってからjParaListのリストを作成する
#でないとえらーが出る
#jParaList0は元データ それから 利用するでーたjParaListを作成

#def putJParaList():
#    for i in jParaList0[joint_kosuu-1]:
#        jParaList.append(jParaList0[i])

#次ここから jParaListのデータから判断してじどうで ジョイントを作成
def    metaSetJoint(field):
    print "metaSetJoint"
    print jParaList
    for list in jParaList:
        print "list", list
        if list["name"]=="fixed":
            name = list["name"]
            obj1 = list["obj1"]
            obj2 = list["obj2"]
            jointList.append(SetFixedJoint(field, name, obj1, obj2))
            print "metaSetJoint....fixed"
        if list["name"]=="hinge":
            name = list["name"]
            obj1 = list["obj1"]
            obj2 = list["obj2"]
            anchor0 = list["anchor"]
            j_axis0 = list["j_axis"]
            hani_kakudo = list["hani_kakudo"] 
            jointList.append(SetHingeJoint(field, name, obj1, obj2, anchor0, j_axis0, hani_kakudo))
            print "metaSetJoint....hinge"

class Field:
    scene = display(autoscale=1 ,forward=norm((-2.0,-1.0,-1.0)))
   
    #物理世界を作成
    world=ode.World()
    world.setGravity((0, -9.81, 0))
    #自由落下させたいなら worldのコメントアウトのほうを生かし
    # 最後の方の ball.body.addForce((0,-1000,0)) を殺す
    #world.setGravity((0, 0, 0))
    #地平面を作成?
    space=ode.Space()

    #衝突関係
    jointgroup=ode.JointGroup()
    ode_floor=ode.GeomPlane(space,(0,1,0),0)
    #()なかの引数 上の例ではy軸方向に重力が発生
    #多分 spaceの最後の引数が y軸の座標を示す
    ode_floor.setCategoryBits(5)
    ode_floor.setCollideBits(5)
    ode_floor.viz=box(
        pos=(0,-0.03,0),
        width=20,length=20,height=0.06,color=(0.5,0.5,1.0))

    vball_x=sphere( pos=(5, 0, 0), radius=0.2, color=color.red)  #x軸
    vball_y=sphere( pos=(0, 5, 0), radius=0.2, color=color.white)#y軸
    vball_z=sphere( pos=(0, 0, 5), radius=0.2, color=color.yellow) #z軸

    target_fps=30
    #target_fps=30だから1秒間に30回の処理をする
    dt=1.0/target_fps

    def near_callback(self,args,geom1,geom2):
        #isBall = ((ground == o1) || (ground == o2));
        #if (isGround)//地面だけと衝突判定
        for c in ode.collide(geom1,geom2):
            c.setBounce(0.0)
            c.setMu(50)#摩擦
            c.setMu2(50)
            #random.seed(1)
            j=ode.ContactJoint(self.world,self.jointgroup,c)
            j.attach(geom1.getBody(),geom2.getBody())

    def tick(self):
        print "tick"
        for i in  range(box_kosuu):
            objList[i].update()
        time.sleep(0.1)
        #self.space.collide((),self.near_callback)
        self.world.step(self.dt)
        self.jointgroup.empty()
        return True

class Box:
    def __init__(
            self, field, flg=1,
            m_density=0.01,
            m_x=1, m_y=5, m_z=1,
            g_x=1, g_y=5, g_z=1,
            v_x=1, v_y=5, v_z=1,
            b_pos=vector(0,2.5,0),
            b_sp =vector(0,0,0),
            v_color=color.cyan
            ):
        if flg==1:
            #デフォルトで...(vpthonのパラメータだけですます)
            self.m_x = v_x
            self.m_y = v_y
            self.m_z = v_z
            self.g_x = v_x
            self.g_y = v_y
            self.g_z = v_z
        if flg==0:
            self.m_x = m_x
            self.m_y = m_y
            self.m_z = m_z
            self.g_x = g_x
            self.g_y = g_y
            self.g_z = g_z

       
        self.body=ode.Body(field.world)
        M=ode.Mass()
        M.setBox(m_density, self.m_z, self.m_y, self.m_x)#密度,z,y,x w,h,l
        self.body.setMass(M)
        self.body.setPosition(b_pos)
        self.geom = ode.GeomBox(
                space=field.space, lengths=(self.g_z, self.g_y, self.g_x)#w,h,l
                )
        self.geom.setCategoryBits(1)
        self.geom.setCollideBits(4)
        #ボール同士の衝突を避ける
        self.geom.setBody(self.body)
        self.f = frame()
        self.f.pos = b_pos
        self.vbox = box(frame=self.f,
                length=v_x, height=v_y, width=v_z, color=v_color)
        mat=self.geom.getRotation()
        self.f.axis=(mat[0],mat[3],mat[6])
        #self.f.axis=(1, 1, 1)
        #self.vbox.up=mat[1],mat[4],mat[7]
        #setRotationとmatの表示が微妙にずれるのでうえのコードで
        #vpytonのオブジェクトをmatで表示してからまたvpythonの
        #回転こまんどで微調整をしよう
   
        #self.geom.setRotation([0.866,0,0.5, 0,1,0, -0.5,0,0.866])
        # opacity :透明度
        #BoxのMassの大きさ,geomの大きさ,
        #   vboxの大きさを同じにする
        #print m_x,m_y,m_z

    def update(self):
        print 'box_update'
        pos = self.geom.getPosition()
        #boxのジオメトリの位置を得る
        #self.vbox.pos = pos
        self.f.pos = pos
        mat=self.geom.getRotation()
        self.f.axis=(mat[0],mat[3],mat[6])
        #self.vbox.up=mat[1],mat[4],mat[7]
        #self.geom.setRotation(1,0,0, 0,3,0, 0,0,1)
        #print mat[0],mat[3],mat[6]
        #print mat[1],mat[4],mat[7]
        #print

def metaBox(field):
    for i in range(box_kosuu):
        pos0     = paraList[i]["pos"]
        density0 = paraList[i]["m_density"]
        v_x0     = paraList[i]["v_x"]
        v_y0     = paraList[i]["v_y"]
        v_z0     = paraList[i]["v_z"]
        v_color0 = paraList[i]["v_color"]
        objList.append(Box(field, flg=1, b_pos=pos0,
            m_density=density0, v_x=v_x0, v_y=v_y0, v_z=v_z0, v_color=v_color0))


class SetFixedJoint:
    def __init__(self, field, name, obj1, obj2):
        #FixedJointで固定 
        self.name = "fixed"
        self.joint = ode.FixedJoint(field.world)
        if obj2=="env":
            self.joint.attach(obj1.body, ode.environment)
        else:
            self.joint.attach(obj1.body, obj2.body)
        self.joint.setFixed()

class SetHingeJoint:
    def __init__(self, field, name,obj1, obj2, anchor, j_axis, hani_kakudo):
        #theta  関節の目標とする角度 関節をどの方向へ曲げるか決める
        self.name = name
        self.joint = ode.HingeJoint(field.world)
        self.joint.attach(obj1.body, obj2.body)
        self.joint.setAnchor(anchor)
        self.joint.setAxis(j_axis)
        self.tmp1   = 0
        self.theta1 = 0
        self.z1     = 0
        self.PI = 3.141592
        self.hani_kakudo = hani_kakudo
        self.flg1 = 1
        self.flg2 = 1
        #現在の角度
        print "SetHingeJoint", self.theta1, self.tmp1

    def kaitenn_joint(self):
        vel = self.joint.getParam(ode.ParamVel)
        k = 10.0
        self.tmp1 = self.joint.getAngle()
        self.z1 = self.theta1 - self.tmp1

        print "kaitenn_joint",
        print round(self.theta1,4), round(self.tmp1,4), round(self.z1,4), round(vel,4),
        print self.flg1, self.flg2

        v = k*self.z1
        self.joint.setParam(ode.ParamVel, v)
        #目標とする角速度 単位はたぶんラジアン 角速度マイナスなら逆向きに回転
        self.joint.setParam(ode.ParamFMax, 10)
        #目標の角度と現在のジョイントの角度との差を求めている
        ##dParamVel      目標とする速度または角速度            
        ##dParamFMax     dParamVelを達成するために発生する最大の力またはトルク。
        ##直接 関節を目標の角度にするAPIがないので 上のように角度の差を求め
        ##て ...とする

    def    set_kaiten_kakudo(self, field):
        #-180と+180以上になるとキー入力をセーブしている。(範囲角以上になると)
        print " set_kaiten_kakudo   "
        if self.theta1>-self.hani_kakudo:
            self.flg1 = 1
        if self.theta1< self.hani_kakudo:
            self.flg2 = 1

        if field.scene.kb.keys:
            s = field.scene.kb.getkey()
            if s=='j' and self.flg1==1:
                print "jjjjjjjjjjjjjjjjjjjjjj"
                self.theta1 -= self.PI/20
                if self.theta1<-self.hani_kakudo:
                    self.theta1 = -self.hani_kakudo
                    self.flg1 = 0

            elif s=='k' and self.flg2==1:
                print "kkkkkkkkkkkkkkkkkkkkkk"
                self.theta1 += self.PI/20
                if self.theta1> self.hani_kakudo:
                    self.theta1 = self.hani_kakudo
                    self.flg2 = 0
            print self.theta1

if __name__=='__main__':
    index = 1
    field = Field()
    metaBox(field)
    #objListにオブジェクトが入った後jParaListに要素を入れる
    jParaList = [
            {"name":"fixed", "obj1":objList[0], "obj2":"env"},
            {"name":"hinge", "obj1":objList[0], "obj2":objList[1], "anchor":(0,       2, 0), "j_axis":(0, 1, 0), "hani_kakudo":3.1415},#台座と第一アームの関節
            {"name":"hinge", "obj1":objList[1], "obj2":objList[2], "anchor":(0.25, 6.75, 0), "j_axis":(0, 0, 1), "hani_kakudo":1.0}, #第一と第二アームの関節
            {"name":"hinge", "obj1":objList[2], "obj2":objList[3], "anchor":(5.25, 6.75, 0), "j_axis":(0, 0, 1), "hani_kakudo":1.0}
            ]

    metaSetJoint(field)

    #PI = 3.141592
    while True:
        print "index", index
        #jointList[1].kaitenn_joint()
        #jointList[2].set_kaiten_kakudo(field)
        #すべてのHingeJointで下のコマンドを実行しないと重力でダラーンとなる
        jointList[index].set_kaiten_kakudo(field)
        for list in jointList:
            if list.name=="hinge":
                #print "list.name",list.name
                list.kaitenn_joint()
        if field.scene.kb.keys:
            print "index", index
            jn = field.scene.kb.getkey()
            print "jnjnjnjnjnjnjn"
            print "jn", jn
            #動かすジョイントの選択
            #いささか反応が遅い
            if jn=="1" or jn=="2" or jn=="3":
                index = int(jn)
                lb = label(pos=(0,0,10), text=jn)
                #今どんなコマンドがはいっているか表示(キー入力の反応が遅いのをカバー)
        field.tick()

0 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ページ

Featured Posts