2013年1月20日日曜日
car グラフ
# coding: UTF-8
# http://python.matrix.jp/projects/pyogre/ode_test.html
# カーシム
# 別ウィンドウのものに数値を表示できないか
# グラフを書いてみる 2013/01/19
import sys
import os
import time
import ode
import visual
import visual.controls
import visual.graph
import math
import threading
from numpy import *
class Field:
world = ode.World()
space = ode.Space()
jointgroup = ode.JointGroup()
world.setGravity( (0,-9.81,0) )
visual.rate(30)
scene = visual.display(
title='field', width=640, height=520, autoscale=0,
forward=visual.norm((0.5,-0.5,-1)),
range=(5,5,5))
# range 座標軸それぞれに沿った中心:center から対象領域への広がりを意味
#autoscale = 0 のとき自動的にスケールを設定しません
# http://www.nasuinfo.or.jp/FreeSpace/kenji/sf/visualj/display.html
floor = ode.GeomPlane(space, (0,1,0), 0)
# loor = ode.GeomPlane(space, (0,0,1), 0)は(0,0,1)が法線ベクトルとなる、
#つまりx、y軸に平行な地面のジオメトリを高さ0の位置に生成しています。
# GeomPlane 地面? 無限に広がった地面のジオメトリを作成?
# http://rbintelligence.hide-yoshi.net/pyODE3.html
floor.setCategoryBits(1)
floor.setCollideBits(3)
# http://www.matzmtok.com/blog/2008/05/box2d%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB-maskbits%E3%81%AB%E3%82%88%E3%82%8B%E8%A1%9D%E7%AA%81%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%AA%E3%83%B3%E3%82%B0/
#衝突判定の設定をしているのだが ?
#geom.setCategoryBits(0x80000000)
#geom.setCollideBits(0xffffffff)
#といったように32bitの各ビットでカテゴライズと、衝突検出する対象を
# 設定できます。??????
# [http://python.matrix.jp/projects/pyogre/ode_test.html]
#hirosa = 30
hirosa = 200
floor.viz = visual.box(
axis=(1,0,0), pos=(0,-0.05, 0),
width=hirosa, length=hirosa, height=0.1, color=(0.5,0.5,1.0))
#地面のvpythonを作成
#座標を描く
for x in range(-hirosa/2, hirosa/2):
trail = visual.curve(pos=[(x, 0, -hirosa/2), (x, 0, hirosa/2)], color=visual.color.white)
for z in range(-hirosa/2, hirosa/2):
trail = visual.curve(pos=[(-hirosa/2, 0, z), (hirosa/2, 0, z)], color=visual.color.white)
for x in range(-hirosa/2, hirosa/2, 10):
trail = visual.curve(pos=[(x, 0, -hirosa/2), (x, 0, hirosa/2)], range=0.05, color=visual.color.black)
for z in range(-hirosa/2, hirosa/2, 10):
trail = visual.curve(pos=[(-hirosa/2, 0, z), (hirosa/2, 0, z)], radius=0.05,color=visual.color.black)
trail = visual.curve(pos=[(0, 0, -hirosa/2), (0, 0, hirosa/2)], color=visual.color.blue)
trail = visual.curve(pos=[(-hirosa/2, 0, 0), (hirosa/2, 0, 0)], color=visual.color.red)
target_fps = 30
dt = 1.0/target_fps
# target_fpsは1秒間のシュミレーションのコマの数だったと思う
collision_check_num = 2
check_time = dt/collision_check_num
lasttime=time.time()
def __init__(self):
self.objects = []
#わざわざこれだけを__init__にする理由がわからない
#車体、タイヤのオブジェクトの配列
self.objects2 = []
self.joint = ""
def near_callback(self, args, geom1, geom2):
syoutotu_flg = 1
for o1 in self.objects2:
for o2 in self.objects2:
if (o1.geom==geom1 or o2.geom==geom2):
syoutotu_flg = 0
print "00000000000000"
if syoutotu_flg!=0:
for c in ode.collide(geom1, geom2):
# 2つのジオメトリオブジェクトが衝突してるかどうか検知する
# 戻り値は Contactオブジェクトのリストになるみたい
# contacts = ode.collide(geom1, geom2)でgeom1とgeom2の衝突点数を取得します。
# c.setBounce(0.2)は反発係数、c.setMu(5000)は摩擦です。
# http://rbintelligence.hide-yoshi.net/pyODE3.html
c.setBounce(0.5)
c.setMu(50)
c.setMu2(50)
j = ode.ContactJoint(self.world, self.jointgroup, c)
j.attach(geom1.getBody(), geom2.getBody())
# 衝突点にジョイントを作っています。ODEでは接触をジョイントの拘束として計算しています。
# http://rbintelligence.hide-yoshi.net/pyODE3.html
# http://rbintelligence.hide-yoshi.net/pyODE3.html
# 接触ジョイントは衝突検出で使用され、その有効期間はシミュレーションの1ステップだけです
# http://www.crystal-creation.com/robot/technical-information/physics-engine/ode/joint/contact.htm
def tick(self):
time.sleep(0.1)
for obj in self.objects2:
#objectsにはボディ 車輪4個 車そのもの が入る
obj.update()
for obj in self.objects:
#objectsにはボディ 車輪4個 車そのもの が入る
obj.update()
t = self.dt - (time.time() - self.lasttime)
if (t > 0):
#このtickの関数が長くかかると(t<0)sleepせずに
#シーンがスムーズになるようにしているの静的メンバ関数か
#あんまり意味がないように思う
time.sleep(t)
for i in range(self.collision_check_num):
#このコードrangの引数が2だから for文がなくてもいい
#オブジェクトの数だけ以下のコードもforしないとだめ
#でもいままでどうもなかったのに
self.space.collide((), self.near_callback)
self.world.step(self.check_time)
#self.world.step(100)
self.jointgroup.empty()
self.lasttime = time.time()
return True
class Cylinder2:
def __init__(self, field, r, h, c):
#res = Cylinder(field, radius=0.3, length=0.7)
#このコードにはCylinderのインスタンスコードは上のものしかないので
#**keysには radius lengthが格納される
self.body = ode.Body(field.world)
M = ode.Mass()
M.setCylinder( 1, 3, r, h)
# setCylinder (密度、方向、半径 長さ)方向:3だからgeomはz方向に長い
# http://www10.atwiki.jp/bambooflow/pages/226.html#id_8fb8a607
self.body.setMass(M)
self.geom = ode.GeomCCylinder(
space=field.space, radius=r, length=h
)
#CCylinder GeomCapsuleの別名
self.geom.setBody(self.body)
self.frame = visual.frame()
self.visual = visual.cylinder(
frame=self.frame, radius=r, length=h, color=c
)
self.visual.rotate(angle=visual.pi/2.0, axis=(0,1,0))
#vpythonとpyodeの座標を一致させる
self.visual.z += self.visual.length/2.0
#self.visual = visual.cylinder(
# axis=(0,0,h), pos=(0,0,-h/2),
# frame=self.frame, radius=r, color=c
# )
##geomとvpytonのposをあわせる
field.objects2.append(self)
def update(self):
pos = self.body.getPosition()
mat = self.body.getRotation()
#確か 姿勢を得ていると思ったが
self.frame.pos = pos
self.frame.axis = mat[0], mat[3], mat[6]
self.frame.up = mat[1], mat[4], mat[7]
#これも姿勢に関するもの あとで詳しく調べよう
def meta_cylinder2(field, pos, r, h, c):
syougai = Cylinder2(field, r, h, c)
syougai.body.setPosition(pos)
field.joint = ode.FixedJoint(field.world)
field.joint.attach(syougai.body, ode.environment)
field.joint.setFixed()
#車輪のクラス
#引数r とhで シリンダーのvpython pyodeのオブジェクトの作成
#posはまだ未定
class Cylinder:
def __init__(self, field, r, h, c):
#res = Cylinder(field, radius=0.3, length=0.7)
#このコードにはCylinderのインスタンスコードは上のものしかないので
#**keysには radius lengthが格納される
self.body = ode.Body(field.world)
M = ode.Mass()
M.setCylinder( 10, 3, r, h)
# setCylinder (密度、方向、半径 長さ)方向:3だからgeomはz方向に長い
# http://www10.atwiki.jp/bambooflow/pages/226.html#id_8fb8a607
self.body.setMass(M)
self.geom = ode.GeomCCylinder(
space=field.space, radius=r, length=h
)
#CCylinder GeomCapsuleの別名
self.geom.setBody(self.body)
self.frame = visual.frame()
self.visual = visual.cylinder(
frame=self.frame, radius=r, length=h, color=c
)
self.visual.rotate(angle=visual.pi/2.0, axis=(0,1,0))
#vpythonとpyodeの座標を一致させる
self.visual.z += self.visual.length/2.0
#self.visual = visual.cylinder(
# axis=(0,0,h), pos=(0,0,-h/2),
# frame=self.frame, radius=r, color=c
# )
##geomとvpytonのposをあわせる
field.objects.append(self)
def update(self):
pos = self.body.getPosition()
mat = self.body.getRotation()
#確か 姿勢を得ていると思ったが
self.frame.pos = pos
self.frame.axis = mat[0], mat[3], mat[6]
self.frame.up = mat[1], mat[4], mat[7]
#これも姿勢に関するもの あとで詳しく調べよう
#ボディクラス
# x軸がw y軸がl 高さがhのボディを作成
# posはまだ未定
# cylinderだけど 便宜上Boxにしている
class Box:
#多分pyodeとvpythonの座標系は一緒だったな
# → 違う
def __init__(self, field, r, h):
self.old_pos = []
self.body = ode.Body(field.world)
M = ode.Mass()
M.setCylinder(1, 2, r, h)#密度,方向1はx軸の向き,半径,長さ
#方向のパラメータは役にたっていない
self.body.setMass(M)
#とりあえずbodyのシリンダーの位置はboxのように物体の重心にあるものとして設定
#vpythonとpyodeのposが合うか?
self.geom = ode.GeomCylinder(space=field.space, radius=r, length=h)#vpythonの座標でx,y,z
self.geom.setBody(self.body)
self.frame = visual.frame()
self.visual = visual.cylinder(
frame=self.frame, radius=r, length=h
)
self.visual.rotate(angle=visual.pi/2.0, axis=(0,1,0))
#vpythonとpyodeの座標を一致させる
self.visual.z += self.visual.length/2.0
field.objects.append(self)
def update(self):
pos = self.body.getPosition()
#if self.old_pos-pos>5 or self.old_pos-pos<-5:
# print "car_position",pos
#self.old_pos = pos
mat = self.body.getRotation()
self.frame.pos = pos
self.frame.axis = mat[0], mat[3], mat[6]
self.frame.up = mat[1], mat[4], mat[7]
#車体の方向検地のため車体の前方に青い目印のボールをつける
class Ball:
def __init__( self,field,m_density,m_radius,g_radius):
self.body=ode.Body(field.world)
M=ode.Mass()
M.setSphere(m_density, m_radius)
#(密度,半径)
self.body.setMass(M)
self.geom=ode.GeomSphere(
space=field.space,
radius=g_radius
)
#このradiusが実際のバウンドを決める
#多分 sphereの座標が0で radiusが0.3だから
#posが0.3ぐらいのバウンド点になる
self.geom.setCategoryBits(1)
self.geom.setCollideBits(4)
#上は Boxのジオメトリを作成
self.geom.setBody(self.body)
# 剛体にジオメトリをセット
self.vball=visual.sphere(
radius=m_radius,
color=visual.color.blue,
)
field.objects.append(self)
def update(self):
pos=self.geom.getPosition()
#boxのジオメトリの位置を得る
self.vball.pos=pos
#class Rader:
# def __init__(self):
#
# def makeRader():
# sensor_ball = Ball(field, 0.1, 0.1, 0.1)
#車輪クラスとボディクラスから車全体を作成
class Car:
def __init__(self, field, j, pos=(0,0.8,0)):
#pos : ボディの位置
self.handle =0.0 #タイヤの「ハンドル」の角速度を決めるなんか
self.acceleration = 0.0 #タイヤの「回転」の トルク量を決めてるみたい
self.body = Box(field, 1.5, 0.5)
#ボディの作成 引数 w r h
self.body.body.setPosition((pos[0], pos[1], pos[2]))
self.body.body.setRotation((1,0,0, 0,0,1, 0,-1,0))
self.body.geom.setCategoryBits(1)
self.body.geom.setCollideBits(4)
self.ball = Ball(field, 0.1, 0.1, 0.1)
self.ball.body.setPosition((0, 2.3, -1))
#なぜこの数値にするといいのか分からん カット&トライ
self.ball.body.setRotation((1,0,0, 0,0,1, 0,-1,0))
#j = ode.FixedJoint(field.world)
j.attach(self.ball.body, self.body.body)
j.setFixed()
#車輪の作成..タイヤ一個分
def make_tire(pos, offset, c):
#posは def __init__ でpos=(0,2,0)となっている
#車体のposからoffsetを加減してjointの位置をだしている
res = Cylinder(field, 0.3, 0.2, c)
#車輪の実体を作成する関数
res.body.setPosition(pos)
#body ode世界のbody
res.body.setRotation((0,0,-1,0,1,0,1,0,0))
#「body」をy軸右ねじ回転で90°回転している(その回転行列を与えている)
#つまり車の進行方向に対してタイヤの向きが90°になるようにしているのか
#ややこしい。本来cylinderクラスで設定しておくべき
#以下ファイル参考
# C:\howm\2012\06\2012-06-28-202754.txt
res.geom.setCategoryBits(2)
res.geom.setCollideBits(6)
res.joint = ode.Hinge2Joint(field.world)
#ヒンジ2
#http://www.crystal-creation.com/robot/technical-information/physics-engine/ode/joint/
res.joint.attach(self.body.body, res.body)
# 引数の中身(ボディの剛体, 車輪の剛体)
res.joint.setAnchor((pos[0]+offset[0], pos[1]+offset[1], pos[2]+offset[2]))
joint_point = visual.sphere(
pos=(pos[0]+offset[0], pos[1]+offset[1], pos[2]+offset[2]),
radius=0.05, color=visual.color.black
)
#posはボディの位置だから、offsetをたして車輪の軸の位置をきめている
#offsetで車体と車輪のあいだに軸がくるようにしている
res.joint.setAxis1((0,1,0))
res.joint.setAxis2((1,0,0))
#limit = [40.0/180.0*visual.pi, -40.0/180.0*visual.pi]
limit = [170.0/180.0*visual.pi, -170.0/180.0*visual.pi]
res.joint.setParam(ode.ParamHiStop, limit[0])
res.joint.setParam(ode.ParamLoStop, limit[1])
#ジョイントの可動域を設定する
#http://demura.net/9ode/338.html
res.joint.setParam(ode.ParamStopCFM, 1.0E-6)
res.joint.setParam(ode.ParamSuspensionCFM, 0.015)#サス硬さ(0で剛体)
res.joint.setParam(ode.ParamSuspensionERP, 0.4)
res.joint.setParam(ode.ParamFudgeFactor, 1.0)#粘性係数
res.joint.setParam(ode.ParamVel, 0.0)#目標角速度
res.joint.setParam(ode.ParamFMax, ode.Infinity)#目標角速度達成のための最大トルク
#res.joint.setFeedback(True)
#フィードバックバッファを作成します。フラグがTrueの場合、バッファが割り当てられ、
#ジョイントによって加えられる力/トルクがgetFeedback()メソッドを使用して読み取る
#ことができます
return res
#このreturn res 何気なくクラスのなかで関数を使ってreturnをしているけれど
#すごい技
#上の関数を利用して、実際に4個の車輪を作成している
#以下のyのposの設定だと0.25だけ車体にタイヤがめりこんでいるが?
self.tirefl = make_tire((-1, pos[1]-0.5, -1.2), ( 0.1,0,0), visual.color.blue)
self.tirefr = make_tire(( 1, pos[1]-0.5, -1.2), (-0.1,0,0), visual.color.blue)
self.tirerl = make_tire((-1, pos[1]-0.5, 1.2), ( 0.1,0,0), visual.color.red)
self.tirerr = make_tire(( 1, pos[1]-0.5, 1.2), (-0.1,0,0), visual.color.red)
#cylinderはboxと違って片方の端をposとして設定されるからなんかこの上の設定では
#変な気がする。
field.objects.append(self)
def update(self):
#ハンドル..........
#handle :角速度
handle = 40.0/180.0*visual.pi*self.handle
#右前輪と左前輪のハンドルの目標角速度をなんかけいさんしている
target_vel = max(-10.0,min(10.0, handle - self.tirefl.joint.getAngle1()))*3.0
#handle:スライダーから得る目標角速度 それから実際の角度をひいたのが10より小-10より大なら
#その値が target_velの値に(*3)
#handle:スライダーから得る目標角速度 それから実際の角度をひいたのが10より小-10より小なら
#target_velの値は -10(*3)
#handle:スライダーから得る目標角速度 それから実際の角度をひいたのが10より大なら
#target_velの値は 10(*3)
#target_vel = handle - self.tirefl.joint.getAngle1()
#通常は上のように目標角と現在角の差が0になれば、目標角速度を0になるようにしただけの式で
#すんでいるのに なぜか複雑なコードにしている
self.tirefl.joint.setParam(ode.ParamVel, target_vel)
target_vel = max(-10.0,min(10.0, handle - self.tirefr.joint.getAngle1()))*3.0
self.tirefr.joint.setParam(ode.ParamVel, target_vel)
target_vel = max(-10.0,min(10.0, -handle - self.tirerl.joint.getAngle1()))*3.0
self.tirerl.joint.setParam(ode.ParamVel, target_vel)
target_vel = max(-10.0,min(10.0, -handle - self.tirerr.joint.getAngle1()))*3.0
self.tirerr.joint.setParam(ode.ParamVel, target_vel)
#joint2.setParam(ode.ParamVel, 10)は目標角速度の設定
#<http://rbintelligence.hide-yoshi.net/pyODE4.html>
#アクセル
self.tirefl.joint.addTorques(0,self.acceleration/2)
self.tirefr.joint.addTorques(0,self.acceleration/2)
#self.tirerl.joint.addTorques(0,self.acceleration/2)
#self.tirerr.joint.addTorques(0,self.acceleration/2)
# このaccelerationが実際なんのやくにたっているのかわからないが上2行コメントアウトして
#エラーがすくなくなる。 「乱暴な運転」をしてもエラーがでない
#addTorques(torque1、torque2)軸1は1torque1を適用し、軸2はtorque2。
#パラメータ: torque1 - トルク1の大きさ (type=float) torque2 -トルク2大きさ (type=float)
#<http://translate.google.com/translate?hl=ja&sl=auto&tl=ja&u=http%3A%2F%2Fpyode.sourceforge.net%2Fapi-1.2.0%2Fpublic%2Fode.Hinge2Joint-class.html%23addTorques>
class Unnten:
def __init__(self):
self.c = visual.controls.controls()
#コントロールウィンドウを作成
self.slot = visual.controls.slider(
pos=(-50,-20), min=0.0, max=2.0, length=100, axis=(0,1,0))
#コントロールウィンドウの中に、スライダーを作成
self.slot.value=1.0
#value slotスライダーの出力の値を1.0に
self.handle = visual.controls.slider(
pos=(-20,0), min=0.0, max=2.0, length=100, axis=(1,0,0))
self.handle.value=1.0
#handleスライダーを作成 初期出力を1.0に
# slider.py
# ファイル名上でgfを押せ
self.old_acceleration = 0
self.old_pos = visual.vector(0, 2, 0)
#carの初期位置
self.old_time = time.time()
self.old_sp = 0
self.mokuhyou_sp = 0
self.old_moku_sp = 0
pos = (0, 0, 0)
self.lb_slot = visual.label(pos=pos, text='slot')
self.t = 0
self.zissai_sp = 0
def iti_sp(self, car):
p = car.body.body.getPosition()
p_l = car.ball.body.getPosition()
self.t = time.time()
#pos = visual.vector( p[0],p[1],p[2] )
#pos_l = visual.vector( p_l[0],p_l[1],p_l[2] )
pos = visual.vector( round(p[0],2),round(p[1],2),round(p[2],2) )
pos_l = visual.vector( round(p_l[0],2),round(p_l[1],2),round(p_l[2],2) )
#carとspの向きをいろいろ計算
#car_muki= pos - pos_l
car_muki= pos_l - pos
#print 'car_muki', car_muki
if car_muki[0]==0:
if car_muki[2] > 0:
car_kakudo = math.pi/2
else:
car_kakudo = -math.pi/2
else:
car_kakudo = math.atan( car_muki[2]/car_muki[0] )
kyori = pos - self.old_pos
if kyori[0]==0:
if kyori[2] > 0:
sp_kakudo = math.pi/2
else:
sp_kakudo = -math.pi/2
else:
sp_kakudo = math.atan( kyori[2]/kyori[0] )
d_kakudo = sp_kakudo - car_kakudo
#print 'p', p, 'p_l',p_l, 'kyori', kyori
print 'pos', pos, 'pos_l', pos_l, 'self.old_pos', self.old_pos
print 'car_muki[2]', car_muki[2], 'kyori[2]', kyori[2]
print 'car_kakudo',car_kakudo, 'sp_kakudo', sp_kakudo
print 'd_kakudo', d_kakudo
if d_kakudo<math.pi/2 and d_kakudo>-math.pi/2:
sp_zougen = 1
else:
sp_zougen = -1
keika = self.t - self.old_time
if keika<0.046:
keika = 0.046
#なぜか初期値かなりちいさな値となりspが大になるので...
self.zissai_sp = sp_zougen * visual.mag(kyori) / keika #mag ベクトルの絶対値
mokuhyou_acc = self.mokuhyou_sp * 100/30#100/30:spをaccにするための係数
d_sp = self.mokuhyou_sp - self.zissai_sp
#car.acceleration = mokuhyou_acc + d_sp * 100/30
car.acceleration = mokuhyou_acc + d_sp*10
car.acceleration = mokuhyou_acc + d_sp*d_sp*d_sp
print 'mokuhyou_sp',self.mokuhyou_sp
print 'zissai_sp', round(self.zissai_sp, 2)
print 'sp_zougen', sp_zougen
print 'car.acceleration',car.acceleration
k = self.zissai_sp - self.old_sp
kasokudo= round(k, 2) #少数2桁まで
self.old_pos = pos
self.old_time = self.t
self.old_sp = self.zissai_sp
#print 'kasokudo' ,kasokudo
return kasokudo
def update(self, car):
self.iti_sp(car)
self.c.interact()
#マウスイベントをチェックしている?
car.handle = self.handle.value-1.0
self.mokuhyou_sp = 30.0*(self.slot.value-1.0)
self.lb_slot.pos = car.body.body.getPosition()
sp = str(round(self.mokuhyou_sp, 2))
self.lb_slot.text = sp
class Graph:
def __init__(self):
self.graph = visual.graph.gdisplay(title='cyan=zissai_sp green=mokuhyou_sp')
self.funct1 = visual.graph.gcurve(color=visual.graph.color.cyan)
self.funct2 = visual.graph.gcurve(color=visual.graph.color.green)
self.time_start = time.time()
def update(self, mokuhyou_sp, zissai_sp):
time_now = time.time()
t = time_now - self.time_start
self.funct1.plot( pos=(t, zissai_sp) )
self.funct2.plot( pos=(t, mokuhyou_sp) )
def matu(self):
pass
def graphTimer(self, mokuhyou_sp, zissai_sp):
timer = threading.Timer(1, self.matu)
timer.start()
self.update(mokuhyou_sp, zissai_sp)
#以下のようにしたいところだけれど、updateに引数をつけると警告がでる
def graphTimer2(self, zissai_sp):
timer = threading.Timer(1, self.update(zissai_sp))
timer.start()
if __name__=='__main__':
field = Field()
j = ode.FixedJoint(field.world)
car = Car(field, j)
car.body.body.setAngularVel((0,0,0))
#上のコード全体で車のボディのodeのオブジェクトをsetAngularVelしている
#setAngularVel? 角速度を設定
#<http://translate.google.com/translate?hl=ja&sl=auto&tl=ja&u=http%3A%2F%2Fpyode.sourceforge.net%2Fapi-1.2.0%2Fpublic%2Fode.Body-class.html%23setAngularVel>
#よく分からん 停止させているみたいだが、ボディは回転していないし?
unnten = Unnten()
g = Graph()
while True:
field.tick()
field.scene.center = car.body.body.getPosition()
#center 中心:center とは、カメラの視点が周囲を回っても、常に同じ
#位置を保つ場所です
#<http://www.nasuinfo.or.jp/FreeSpace/kenji/sf/visualj/display.html>
unnten.update(car)
g.graphTimer(unnten.mokuhyou_sp, unnten.zissai_sp)
#g.graphTimer()
#g.update(unnten.zissai_sp)
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿