- (EusLisp 9.29) 通商産業省 工業技術院 電子技術総合研究所 知能システム部 松井 俊浩, 原 功, 中垣 博文(九州電力) matsui@etl.go.jp, hara@etl.go.jp, nakagaki@etl.go.jp〒305 茨城県つくば市梅園1-1-4 .. toctree::
jintro :maxdepth: 2 :caption: EusLisp 基本
jgenerals
jcontrols
jobjects
jarith
jsymbols
jsequences
jio
jevaluation
システム関数¶
メモリ管理¶
メモリ管理の設計は、オブジェクト指向言語の柔軟性と効率性にたいへん 影響を及ぼす。 Euslispは、フィボナッチバディ法を基本に統一した方法で オブジェクトをメモリに割り当てる。 この方法は、chunkと呼ばれる大きなメモリのプールを小さなセルに分割する。 それぞれのセルは、サイズが等しくなく、フィボナッチ数がそれぞれ割り当てられる。 chunkメモリは、symbol, cons, string, float-vectorなどのような 様々な型のオブジェクトのための同次なデータ容器である。 それらのサイズはchunkと一致する長さである。 chunkは、固定、動的、再配置可能、交替可能などのような どんな特別な属性も持っていない。 EusLispのヒープメモリは、chunkの集合である。そして、 ヒープはUNIXより新しいchunkを得ることにより動的に拡張することができる。 拡張は、動作中に自動的に発生するかあるいはユーザーがsystem:alloc関数を 呼び出すことにより発生する。 自動的に処理されるとき、使用可能なメモリサイズは合計のヒープサイズの 約25%に保つ。この比率は、sys:*gc-margin*パラメータに0.1から0.9までの値を設定 することにより変更することができる。
すべてのヒープメモリを使いきったとき、mark-and-sweep型のガーベージコレクション(GC) を始める。 ルート(パッケージ,クラスやスタック)からアクセス可能なセルは, 同じアドレスのままである。 他のアクセス不可能なセルは、矯正されfree-listsにリンクされる。 GCの間にコピーやコンパクト化は発生しない。 ガーベージされるセルが矯正されるとき、その隣接セルがfreeかどうかチェックされる。 そして、できるだけ大きなセルを構成するようにマージされる。 しかしながら、このマージは、ときどき意味の無いものになる。 なぜなら、もっとも頻繁に呼び出されるメモリアロケータであるconsが、 そのマージされたセルを最も小さなセルに分割することを要求するからである。 したがって、Euslispはconsの高速化のためにマージされないある特定の量の ヒープを残すことを許可している。 この比率は、sys:*gc-merge*パラメータによって決定される。その値のデフォルトは 0.3である。 sys:*gc-merge*に大きな値を設定することにより、マージされないヒープを多く残す。 これは、consが要求されるとき、buddy-cellの分割が滅多に起こらないので、consの性能を改善する。 これは、また3次元ベクトルのような相対的に小さなセルのアロケーションについて すべて成り立つ。
sys:gcは、明示的にガーベージコレクターを呼び出す。 そして、ヒープに配置された空いているワード数と全体のワード数(バイト数ではない)を示す2つの整数の リストを返す。
もし、実行中に“fatal error: stack overflow”が報告され、 そのエラーが無限ループあるいは再帰処理によるものでないと確信するならば、 sys:newstackでLispのスタックの大きさを拡張すれば回避できる。 sys:newstackを設定する前には、resetを実行しなければならない。 なぜなら、 スペシャルバインドとunwind-protectの整理用の書式が 現在のスタックの中からすべて捨てられるためである。
新しいスタックが配置された後、オープニングメッセージを表示するところから 実行を始める。 デフォルトのスタックサイズは、16Kwordである。 Lispのスタックは、システムのスタックと別物である。 前者は、ヒープ上に配置され、後者は、オペレーティングシステムによって スタックセグメント内に配置される。 もし、“segmentation fault”エラーが発生したならば、システムのスタックが小さいことに より発生したことが考えられる。 cshのコマンドlimitで、システムのスタックサイズを増加することにより、 解決できる可能性がある。
sys:reclaimとsys:reclaim-tree関数は、オブジェクトにより占有されているセルを メモリマネージャーに戻す。そのため、ガーベージコレクションを呼び出すことなしに その後も再使用をすることができる。 しかし、それらのセルが他のセルから参照されていないことが確実でなければならない。
memory-reportとroom関数は、メモリの使用に関する統計を セルのサイズやクラスによりソートして表示する。
addressは、オブジェクトのバイト換算したアドレスを返す。 このアドレスはプロセスに独自のものであるから、 この関数はハッシュテーブルが使用するハッシュ関数に有用である。
peekとpokeは、メモリから直接データを読み書きできる関数である。 アクセスする型は、:char, :byte, :short, :long, :integer, :float, :double のどれかにすべきである。 例えば、(SYS:PEEK (+ 2 (SYS:ADDRESS ’(a b))) :short)は、 consセルのクラスID(ふつう1である)を返す。
’list-all-’を名前の前に付けている幾つかの関数がある。 これらの関数は、システムのリソースあるいは環境のリストを返し、 動的なデバッグに有用である。
sys:gc **
ガーベージコレクションを実行する。割り当てられている中で空いているワード数および全体のワード数 のリストを返す。
sys:*gc-hook* **
ガーベージコレクションを実行する時に呼ばれる関数を定義する。
sys:gctime **
3つの整数のリストを返す。1つは、GCを呼び出した回数。 2つは、セルをマーキングするために使用した時間(1ユニットに1/60秒)。 3つが、矯正(マーキングを外し、マージする)のために使用した時間。
sys:alloc size
ヒープに少なくともsizeワードのメモリを配置し、 実際に配置されたワード数を返す。
sys:newstack size
現在のスタックを廃棄し、sizeワードの新しいスタックを配置する。
sys:*gc-merge* **
メモリ管理用のパラメータ。 gc-merge*は、GCによりマージされずに残すヒープメモリの比率を示す。 このマージされない領域は、すぐにconsのような小さなセルに満たされる。 デフォルトの値は、0.3である。 この値を0.4のように大きくすると、マージされない空きヒープが40%であることを 示し、consのためには役立つが、実数ベクトルやエッジや面などのような大きなセル の確保には、害を及ぼす。
sys:*gc-margin* **
メモリ管理用のパラメータ。 gc-margin*は、全体のヒープに対する空きヒープの比率を決定する。 メモリは、UNIXから獲得したものであるため、空き空間はこの比率より 小さくならない。 デフォルトは、0.25であり、GCの際に25%以上の 空き空間が維持されることを意味する。
sys:reclaim object
ごみとしてobjectを廃棄する。 そのオブジェクトは、他のどのオブジェクトからも絶対に参照されないことが 保証されなければならない。
sys:reclaim-tree object
から通過できるsymbolを除いてすべてのオブジェクトを矯正する。
sys::bktrace num
Lispのスタックのnum番目の深さの情報をトレースして表示する。
sys:memory-report &optional strm
セルのサイズでソートしたメモリ使用のテーブルをstrmストリームに出力する。
sys:room output-stream
クラスで整列したメモリ配置の情報を出力する。
sys:address object
プロセスのメモリ空間内にあるobjectのアドレスを返す。
sys:peek [vector] address type
で指定されたメモリ位置のデータを読みだし、 それを整数として返す。 typeは、:char, :byte, :short, :long, :float, :doubleの内の1つである。 もし、vectorが与えられなかったなら、 そのアドレスは、UNIXの処理空間として扱われる。 例えば、Sunにおいてa.outのヘッダーは#x2000に置かれるため、 (sys:peek #x2000 :short)はmagic number(ふつうは#o403)を返す。 Solaris2は、ELFヘッダーを#10000に置くため、 (sys:peek #x10000 :long)が“ELF”を表現する文字列である #xff454c46を返す。 もし、vectorが与えられたならば、それはforeign-stringであり、 アドレスはvectorの起点からのオフセットとして認識される。 (sys:peek “123456” 2 :short)は、“34”を表現する short wordを返す。(#x3334(13108)である)
アドレス位置については十分注意すること。 short, integer, long. float, double wordを奇数アドレスから読み出すと、 “bus error”になる。
sys:poke value [vector] address value-type
をaddressで指定された位置に書き込む。 プロセスのメモリ空間内のどこでも書き込むことができるため、 特に注意をしなければならない。 プロセスの空間の外へ書き込んだなら、 確実に“segmentation fault”が発生する。 short, integer, long. float, double wordを奇数アドレスに書き込んだ 場合、“bus error”が発生する。
sys:list-all-chunks **
配置されたすべてのヒープのchunkをリストアップする。 他に有用な実行関数はない。
sys:object-size obj
からアクセス可能なセルとワードの数を計算する。 objから参照可能なすべてのオブジェクトが探索される。 そして、3つの数のリストが返される。 1つ目は、セルの数。2つ目は、これらのオブジェクトに論理的に配置されたワード数( すなわち、ユーザーからアクセスできるワード数)。 3つ目は、物理的に配置されたワード数。 これは、ヘッダーとメモリ管理のための特別なスロットを含む。 探索は、symbolで停止する。すなわち、property-listあるいはprint-name stringのような symbolから参照されるオブジェクトは、カウントされない。
UNIXシステムコール¶
EusLispは、UNIXオペレーティングシステムのシステムコールとライブラリ関数とに 直接関連する関数を取りそろえている。 これらの関数の詳細については、UNIX system interface (2)を調べること。 unix-package*に定義されているこれらの低レベル関数の使用は、 ときどき危険をはらむ。 できるだけ他のパッケージに定義されている高レベル関数を使用すること。 例えば、unix:socket, unix:bind, unix:connectなどの代わりに[IPC]節に 記述されているIPC機能を使用すること。
時間¶
unix:ptimes **
経過時間、システム時間、ユーザー時間、サブプロセスのシステム時間とサブプロセスのユーザー時間 の5つの要素を持つリストを返す。 この関数は旧いので、unix:getrusageの使用を推奨する。
unix:runtime **
プロセスのシステムとユーザー時間の合計を返す。 単位は、1/60秒である。
unix:localtime **
現在の時間と月日を整数ベクトルで返す。 要素は、秒、分、時、日、月(0から始まることに注意)、年(1900からの経過年数)、曜日(0が日曜日、6が土曜日)、年内の通し日数(0から始まる)、夏時間がセットされているか、サポートされている時間帯である。
ex.) unix:localtime => #(10 27 12 8 10 116 2 312 nil (“JST” “JST”))
unix:asctime tm_intvector
整数ベクトルで表現されるローカル時間を文字列表現に変換する。 (unix:asctime (unix:localtime))は、現在の実際の時間の文字列 表現を返す。
プロセス¶
unix:getpid **
このプロセスのプロセスID(16ビット整数)を返す。
unix:getppid **
親プロセスのプロセスIDを返す。
unix:getpgrp **
このプロセスのグループIDを返す。
unix:setpgrp **
新しいプロセスのグループIDを設定する。
unix:getuid **
このプロセスのユーザーIDを返す。
unix:geteuid **
このプロセスの使用可能なユーザーIDを返す。
unix:getgid **
このプロセスのユーザーグループIDを返す。
unix:getegid **
このプロセスの使用可能なユーザーグループIDを返す。
unix:setuid integer
このプロセスの使用可能なユーザーIDを設定する。
unix:setgid integer
このプロセスの使用可能なユーザーグループIDを設定する。
unix:fork **
他のEuslispを作成する。サブプロセスに0が返され、 親プロセスにforkされたプロセスのpidが返される。 パイプで接続されたプロセスを作成するためには、[UnixProcess]節に書かれている system:piped-forkを使用すること。
unix:vfork **
他のEuslispをforkし、その新しいEuslispのプロセスが終了するまで親プロセスの実行を 一時停止する。
unix:exec path
Euslispから他のプログラムへ実行を移す。
unix:wait **
サブプロセスの中の1つのプロセスの終了を待つ。
unix::exit code
実行を終了し、codeを終了状態として返す。 ゼロは通常の終了を意味する。
sys:*exit-hook* **
プロセスが終了する直前に呼ばれる関数を定義する。
unix:getpriority which who
このプロセスが持つ最大の優先順位を返す。 whichは、0(プロセス)、1(プロセスグループ)、2(ユーザー)のうちの 1つである。
unix:setpriority which who priority
とwhoで決定されるリソースの優先順位をpriorityに設定する。 whichは、0,1,2の内の1つである。 whoは、whichから相対的に解釈される (\(which=0\)ならプロセスを示し、\(which=1\)ならプロセスグループを示し、 \(which=2\)ならユーザーのIDを示す)。 whoがゼロのとき、現在のプロセス、プロセスグループ、ユーザーを示す。 Euslispプロセスに低い優先順位を指定することは、大きい値を設定することであり、 これはプロセスを不利にする。 (unix:setpriority 0 0 10)は、優先順位を10に設定する。
unix:getrusage who
プロセスについてのシステムリソースの使用情報のリストを返す。 要素は、以下のような順番になっている。 もっと多くの情報が、lisp:rusageより得られる。
float ru_utime (sec.) /* user time used */
float ru_stime (sec.) /* system time used */
int ru_maxrss; /* maximum resident set size */
int ru_ixrss; /* currently 0 */
int ru_idrss; /* integral resident set size */
int ru_isrss; /* currently 0 */
int ru_minflt; /* page faults without physical I/O */
int ru_majflt; /* page faults with physical I/O */
int ru_nswap; /* number of swaps */
int ru_inblock; /* block input operations */
int ru_oublock; /* block output operations */
int ru_msgsnd; /* messages sent */
int ru_msgrcv; /* messages received */
int ru_nsignals; /* signals received */
int ru_nvcsw; /* voluntary context switches */
int ru_nivcsw; /* involuntary context switches */
unix:system &optional command
サブシェルでcommandを実行する。 commandは、Bourn-shellで認識されるものでなければならない。
unix:getenv env-var
の環境変数の値を返す。
unix:putenv env
プロセスの環境変数リストにenvを追加する。 envは、“VARIABLE=value”のように変数と値の等価を表す文字列である。
unix:sleep time
秒間このプロセスの実行を一時停止する。
unix:usleep time
マイクロ秒間このプロセスを一時停止する。 (uは、マイクロを表現する。) usleepは、Solaris2あるいは他のSystem5系のシステムには実現されていない。
ファイルシステムと入出力¶
unix:uread stream &optional buffer size
からsizeバイト読み込む。 streamは、ストリームオブジェクトあるいはファイルディスクリプタ(fd)を 表現する整数である。 もし、bufferが与えられるとき、入力はそこに蓄積される。 そうでないならば、入力はstreamのバッファに蓄積される。 したがって、もしstreamがfdなら、bufferは与えられなければならない。 unix:ureadは、新しい文字列バッファを配置しない。 unix:ureadは、実際に読み込まれたバイト数を返す。
unix:write stream string &optional size
にstringのsizeバイトを書き込む。 もし、sizeが省略されたならば、stringの全部の長さが出力される。
unix:fcntl stream command argument
unix:ioctl stream command buffer
unix:ioctl_ stream command1 command2
unix:ioctl_R stream command1 command2 buffer &optional size
unix:ioctl_W stream command1 command2 buffer &optional size
unix:ioctl_WR stream command1 command2 buffer &optional size
unix:uclose fd
で指定されるファイルをクローズする。
unix:dup fd
で指定されるファイルディスクリプタを2重化して返す。
unix:pipe **
パイプを作成する。このパイプの入出力ストリームを返す。
unix:lseek stream position &optional (whence 0)
のファイルポインタをwhenceからpositionの 位置に設定する。
unix:link path1 path2
hardリンクを作る。
unix:unlink path
で指定されたファイルのhardリンクを取り去る。 もし、ファイルに参照が残っていないなら、削除される。
unix:mknod path mode
ファイルシステムにinodeを作る。 pathは、pathnameオブジェクトでなく文字列でなければならない。
unix:mkdir path mode
ファイルシステムにディレクトリを作る。 pathは、pathnameオブジェクトでなく文字列でなければならない。
unix:access path mode
へのアクセス権利をチェックする。
unix:stat path
のinode情報を得て、以下に示す整数のリストを返す。
st_ctime ; file last status change time
st_mtime ; file last modify time
st_atime ; file last access time
st_size ; total size of file, in bytes
st_gid ; group ID of owne
st_uid ; user ID of owner
st_nlink ; number of hard links to the file
st_rdev ; the device identifier (special files only)
st_dev ; device file resides on
st_ino ; the file serial number
st_mode ; file mode
unix:chdir path
現在のディレクトリをpathに変更する。
unix:getwd **
現在のディレクトリを返す。
unix:chmod path integer
のアクセスモード(permission)を変更する。
unix:chown path integer
ファイルのオーナーを変更する。
unix:isatty stream-or-fd
もし、stream-or-fdがTTY型のデバイス(シリアルポートあるいは仮想TTY)に接続されているなら Tを返す。
unix:msgget key mode
によってアドレスされるメッセージキューを作成し、配置する。
unix:msgsnd qid buf &optional msize mtype flag
unix:msgrcv qid buf &optional mtype flag
unix:socket domain type &optional proto
に定義されている名前を持ちtypeを抽象型とするソケットを作成する。 typeは、1 (SOCK_STREAM), 2 (SOCK_DGRAM), 3 (SOCK_RAW), 4 (SOCK_RDM), 5 (SOCK_SEQPACKET)の内の1つである。
unix:bind socket name
とsocketを関連付ける。 もし、ソケットがUNIX領域内で定義されているならば、nameは、UNIXのパス名でなければならない。
unix:connect socket addr
とaddrで指定される他のソケットを接続する。
unix:listen socket &optional backlog
から接続要求を受け始める。 backlogは、接続の確定を待つためのキューの長さを指定する。
unix:accept socket
から接続要求を受け、両方向にメッセージを交換できるファイルディスクリプタ を返す。
unix:recvfrom socket &optional mesg from flag
からデータを書いたメッセージを受ける。 そのソケットは、unix:bindにより名前を割り当てられなければならない。 mesgは、入ってきたメッセージが蓄積されるための文字列である。 もし、mesgが与えられたならば、unix:recvfromは受け取ったバイト数を返す。 もし省略されたなら、メッセージを蓄積するための新しい文字列を作成し、 その文字列を返す。
unix:sendto socket addr mesg &optional len flag
によって指定される他のソケットへデータの書かれたメッセージを送る。 socketは、名前が割り当てられてないデータ書き込み型のソケットでなければならない。 mesgは、送るための文字列であり、lenは文字列の最初から 数えたメッセージの長さである。 もし、省略されたなら、すべての文字列を送る。
unix:getservbyname servicename
あるいはNISデータベースに記録されているservicename のサービス番号を返す。
unix:gethostbyname hostname
のipアドレスとアドレス型のリストを返す。 (一般にいつも AF_INET==2).
unix:syserrlist errno
のエラーコードに対するエラー情報が記述された文字列を返す。
シグナル¶
unix:signal signal func &optional option
に対してシグナルハンドラーfuncをインストールする。 BSD4.2システムにおいて、システムコール処理の間に捕まえたシグナルは、 システムコールのリトライに起因する。 これは、もしその処理がシステムコールの呼び出しを発行するならば、 シグナルを無視することを意味する。 もし、option=2が指定されたならば、シグナルはsystem-5の手法で 処理される。そのシグナルは、システムコールの失敗に起因する。
unix:kill pid signal
で名前付けされるプロセスにsignalを送る。
unix:pause **
シグナルが到着するまでこのプロセスの実行を一時停止する。
unix:alarm time
秒後にアラーム時計シグナル(SIGALRM 14)を送る。 time=0でunix:alarmを呼び出すと、アラーム時計をリセットする。
unix:ualarm time
がマイクロ秒単位であることを除いてunix:alarmと同じである。 ualarmは、Solaris2あるいはSystem5系のシステムに実現されていない。
unix:getitimer timer
は、0 (ITIMER_REAL), 1 (ITIMER_VIRTUAL), 2(ITIMER_PROF)の内の1つである。 秒単位の時間(timer)と間隔(interval)の2つの要素を持つリストを返す。
unix:setitimer timer value interval
にvalueとintervalを設定する。 timerは、0 (ITIMER_REAL), 1 (ITIMER_VIRTUAL), 2(ITIMER_PROF)の内の1つである。 ITIMER_REALは、valueが終了したとき、SIGALRMを発行する。 ITIMER_VIRTUALは、SIGVTALRMを発行し、 ITIMER_PROFは、SIGPROFを発行する。
unix:select inlist outlist exceptlist timeout
とexceptlistは、ファイルディスクリプタ を示すビットベクトルである。そのファイルディスクリプタの入出力イベント は、テストされなければならない。 例えば、もしinlist=#b0110でoutlist=#b100で exceptlist=NILであるなら、 fd=1あるいはfd=2で読み込み可能かあるいはfd=2で書き込み可能であるかどうかをテストする。 timeoutは、unix:selectが待つために許される秒数を指定する。 inlistで指定されているポートの1つに入力データが現れるかあるいは outlistに指定されるポートの1つに書き込み可能となるかあるいは exceptlistで指定されるポートの1つに例外条件が起こるとすぐに unix:selectは、inlist, outlist, exceptlistのそれぞれにおいて アクセス可能なポートとして設定されたポートの中で、入力処理可能なポート番号を返す。
unix:select-read-fd read-fdset timeout
入出力の選択は、ふつう入力処理のときのみ意味がある。 unix:select-read-fdは、 select fdset nil nil timeoutの速記法である。 read-fdsetは、ビットベクトルでなく、設定された読み込みfdを指定する整数である。
マルチスレッド¶
スレッド内でシグナルを生成することはできない。 したがって、1つのシグナルスタックと1つのタイマーがEuslispのプロセスの 中で実現されている。 Solaris2の上では、メインの最上位レベルが分割されたスレッド内で実行する。
unix:thr-self **
現在実行されているスレッドのID(整数)を返す。
unix:thr-getprio id
で指定されたスレッドの実行優先順位を返す。
unix:thr-setprio id newprio
で指定されたスレッドの実行優先順位にnewprioを設定する。 newprioが小さい数値の場合、優先順位が高いことを意味する。 言い替えれば、 newprioよりも大きな数値を持つスレッドは、CPUにアクセスされることが 少なくなる。 ユーザーは、実行優先順位をプロセスの値(普通はゼロ)よりも高く することはできない。
unix:thr-getconcurrency **
並列に実行できるスレッドの数で表現される 並列度(整数)を返す。
unix:thr-setconcurrency concurrency
の値は、プロセス内のLWPの数である。 もし、concurrensyがデフォルトの1ならば、 生成されたたくさんのスレッドがすべて実行可能であったとしても 順番に1つのLWPに割り当てられる。 もし、プログラムがマルチプロセッサマシン上で実行され、 同時に複数のCPUを利用したいならば、 concurrencyに1より大きい値を設定しなければならない。 concurrencyに大きな値を設定すると、オペレーティングシステムの リソースをたくさん消費する。普通、concurrencyはプロセッサの数 と同じかあるいは小さくすべきである。
unix:thr-create func arg-list &optional (size 64*1024)
ワードのlispスタックを持ち、sizeバイトのCスタック持つ 新しいスレッドを作成し、そのスレッド内でarg-listにfuncを適用する。 スレッドは、どんな結果も呼びだし側に返すことができない。 この関数の使用は避けること。
低レベルメモリ管理¶
unix:malloc integer
Euslispのメモリ空間の外にメモリを配置する。
unix:free integer
で配置されたメモリブロックを開放する。
unix:valloc integer
unix:mmap address length protection share stream offset
unix:munmap address length
unix:vadvise integer
IOCTL¶
Unixはターミナルデバイスをioctlの2番目の引数に命令を設定することにより 制御することができるが、Euslispはインクルードファイルの参照や命令コードとしての 引数の論理和を省略するために、関数で備えている。 詳しい内容は、Unixのtermioのマニュアルを参照すること。
ターミナルの入出力制御には、TIOC*とTC*という2つの命令系がある。 自分のオペレーティングシステムにこれらの関数が実現されているがどうか について気を付けなさい。 基本的に、BSD系はTIOC*の入出力をサポートし、System5系がTC*を サポートしている。
SunOS 4.1 TIOC*とTC*の両方サポート
Solaris2 TC*のみサポート
mips, ultrix? TIOC*のみサポート
unix:tiocgetp stream &optional sgttybuf
パラメータを得る。
unix:tiocsetp stream sgttybuf
パラメータを設定する。
unix:tiocsetn stream &optional sgttybuf
unix:tiocgetd stream &optional sgttybuf
unix:tiocflush stream
バッファをすべて出力する。
unix:tiocgpgrp stream integer
プロセスのグループIDを得る。
unix:tiocspgrp stream integer
プロセスのグループIDを設定する。
unix:tiocoutq stream integer
unix:fionread stream integer
unix:tiocsetc stream buf
unix:tioclbis stream buf
unix:tioclbic stream buf
unix:tioclset stream buf
unix:tioclget stream buf
unix:tcseta stream buffer
ターミナルパラメータをすぐに設定する。
unix:tcsets stream buffer
ターミナルパラメータを設定する。
unix:tcsetsw stream buffer
出力として列をなす全ての文字を転送した後、ターミナルパラメータを設定する。
unix:tcsetsf stream buffer
出力として列をなす全ての文字を転送し、 入力として列をなす全ての文字列を廃棄した 後、ターミナルパラメータを設定する。
unix:tiocsetc stream buffer
unix:tcsetaf stream buffer
unix:tcsetaw stream buffer
unix:tcgeta stream buffer
unix:tcgets stream buffer
unix:tcgetattr stream buffer
unix:tcsetattr stream buffer
キーインデックスファイル¶
近年UNIXは、キーインデックスファイルの管理のためにdbmあるいはndbm ライブラリを提供する。このライブラリを使用することにより、 キーとデータの組みで構成されるデータベースを構築することができる。 以下に示す関数は、clib/ndbm.cに定義されている。 Sunにおいて、そのファイルは、cc -c -Dsun4 -Bstaticでコンパイルし、 (load “clib/ndbm” :ld-option “-lc”)でEuslispにロードすること。
dbm-open dbname mode flag
は、データベースファイルを作るときと、そのデータベースに読み込み/書き込み をするとき、最初に呼び出されなければならない。 dbnameは、データベースの名前である。 実際に、ndbm managerは“.pag”と“.dir”の拡張子を持つ 2つのファイルを作成する。 modeは、ファイルのオープンモードを指定する。0は読み込み専用、1は書き込み専用、 2は読み書き用を示す。また、最初にファイルを作成するときは、#x200を論理和すべきである。 flagは、chmodで変更されるアクセス許可を与える。 #o666あるいは#o664が、flagに適している。 dbm-openは、そのデータベースを確認するための整数を返す。 この値は、他のdbm関数によってデータベースを確認するために使用される。 言い換えれば、同時に幾つかのデータベースをオープンすることができる。
dbm-store db key datum mode
とdatumの組み合わせをdbに蓄積する。 dbは、データベースを確認するための整数である。 keyとdatumは文字列である。 modeは0(挿入)あるいは1(置き換え)のどちらかである。
dbm-fetch db key
の中のkeyに関連付けられているデータを呼び出す。
UNIXプロセス¶
EuslispからUNIX命令を実行ためにunix:system関数を使用すること。 piped-forkは、標準出力を標準入力がパイプを通してEuslispの双方向ストリームに 接続されるサブプロセスを作成する。 piped-forkはストリームを返す。 以下に示す関数は、“wc”を使用することにより、ファイルに含まれる行の数を 数えるものである。
(defun count-lines (file) (read (piped-fork "wc" file)))
次の例は、他のワークステーション“etlic0”の上にeusプロセスを作成し、 分散計算をするためのポートを提供する。
(setq ic0eus (piped-fork "rsh" "etlic0" "eus"))
(format ic0eus "(list 1 2 3)~%")
(read ic0eus) --> (1 2 3)
ソースコードを修正するために、Euslispからezを呼び出すことができる。 スクリーンエディターezは、メッセージキューを通してEuslispと接続する。 もし、既にezプロセスをEuslispと並列に実行しているならば、 ezはezプロセスを再スタートし、ターミナル制御を得る。 ezの中でesc-Pあるいはesc-M命令を発行することにより、 テキストは戻され、Euslispで評価される。 ファイルに少しの変更を加えたとき、全部のファイルをロードする必要がないので、 デバッグするのにこれは便利である。 emacsの上でもM-X run-lisp命令でおなじことが可能である。
cd &optional (dir (unix:getenv “HOME”))
現在のディレクトリを変更する。
ez &optional key
ezエディターの画面に入る。それからLisp書式を読み込み、 評価する。
piped-fork &optional (exec) &rest args
プロセスをforkし、両方向ストリームをEuslispとサブプロセスの間に作る。
rusage **
このプロセスのリソースの使用状況を表示する。
Cで書かれたLisp関数の追加¶
ファイルに含まれるCを重く参照したり、行列にしばしばアクセスするような プログラムにおいては、Euslispで記述するよりはむしろCあるいは他の言語で 記述した方が効率が良く、記述もわかり易い。 EusLispは、Cで書かれたプログラムをリンクする方法を備えている。
もしCで書かれたEuslispの関数を定義したいならば、 Euslispで呼び出しできるCの関数はそれぞれ、3つの引き数を受けるように書かれなければ ならない。環境へのポインタと受け取る引き数の数とlispの引数領域を示す ポインタの3つである。 これらの引数は、c/eus.hの中のマクロによって参照されるため、 ctx, n, argvと名付けられねばならない。 Cのプログラムは、eusdir*/c/eus.hをincludeしなければならない。 プログラマーは、そこに書かれた型やマクロに精通していなければならない。 エントリ関数名には、ソースファイルのbasenameを付けなければならない。
任意の数の実数の算術平均を計算するCの関数AVERAGEのサンプルコードは、 以下に示す通りである。 この例において、引数から実数値を得る方法、実数のポインタを作る方法、 特殊変数AVERAGEにポインタを設定する方法やエントリ関数aveに 関数やsymbolを定義する方法を知ることができる。 ’cc -c -Dsun4 -DSolaris2 -K pic’でこのプログラムをコンパイルする。 c/eus.h内の正しい定義を選択するために、-Dsun4や-DSolaris2 が必要である。 -K picは、ロード可能な共有オブジェクトのために、位置に依存するコードを Cコンパイラで生成させるために必要である。 その後、コンパイルの結果である’.o’ファイルがEuslispにロードすることができる。 もっと完全な例はeusdir*/clib/*.cに置かれている。 これらの例は、ここで書かれた方法で定義され、ロードされる。
/* ave.c */
/* (average &rest numbers) */
#include "/usr/local/eus/c/eus.h"
static pointer AVESYM;
pointer AVERAGE(ctx,n,argv)
context *ctx;
int n;
pointer argv[];
{ register int i;
float sum=0.0, a, av;
pointer result;
numunion nu;
for (i=0; i<n; i++) {
a=ckfltval(argv[i]);
sum += a;} /*get floating value from args*/
av=sum/n;
result=makeflt(av);
AVESYM->c.sym.speval=result; /*kindly set the result in symbol*/
return(result);}
ave(ctx,n,argv)
context *ctx;
int n;
pointer argv[];
{ char *p;
p="AVERAGE";
defun(ctx,p,argv[0],AVERAGE);
AVESYM=intern(ctx,p,strlen(p),userpkg); /* make a new symbol*/
}
他言語インターフェース¶
Euslispとのリンクを考慮していないCの関数もEuslispにロードすることができる。 これらの関数は、他言語関数と呼ばれる。 そのようなプログラムはload-foreignマクロによりロードされる。 そのマクロは、foreign-moduleのインスタンスを返す。 オブジェクトファイルの中の外部symbol定義は、モジュールオブジェクトの中に 登録されている。 defforeignは、Euslispから呼び出すための C関数に対するエントリーを作るために使用される。 defun-c-callableは、Cから呼び出し可能なlisp関数を定義する。 呼び出し可能なCの関数は、パラメータを変換し関連するEuslispの関数へ制御を移すために pod-codeと呼ばれる特別なコードを持つ。 pod-addressは、この特別なコードのアドレスを返す。 そのアドレスはCの関数に通知されるべきである。
これは、CのプログラムのサンプルとEuslispへの関数インターフェースである。
/* C program named cfunc.c*/
static int (*g)(); /* variable to store Lisp function entry */
double sync(x)
double x;
{ extern double sin();
return(sin(x)/x);}
char *upperstring(s)
char *s;
{ char *ss=s;
while (*s) { if (islower(*s)) *s=toupper(*s); s++;}
return(ss);}
int setlfunc(f) /* remember the argument in g just to see */
int (*f)(); /* how Lisp function can be called from C */
{ g=f;}
int callfunc(x) /* apply the Lisp function saved in g to the arg.*/
int x;
{ return((*g)(x));}
;;;; Example program for EusLisp's foreign language interface
;;;; make foreign-module
(setq m (load-foreign "cfunc.o"))
;; define foreign functions so that they can be callable from lisp
(defforeign sync m "sync" (:float) :float)
(defforeign toupper m "upperstring" (:string) :string)
(defforeign setlfunc m "setlfunc" (:integer) :integer)
(defforeign callfunc m "callfunc" (:integer) :integer)
;; call them
(sync 1.0) --> 0.841471
(print (toupper "abc123")) --> "ABC123"
;; define a test function which is callable from C.
(defun-c-callable TEST ((a :integer)) :integer
(format t "TEST is called, arg=~s~%" a)
(* a a)) ;; return the square of the arg
;; call it from C
;;setlfunc remembers the entry address of Lisp TEST function.
(setlfunc (pod-address (intern "TEST")))
(callfunc 12) --> TEST is called, arg=12 144
Euslispのデータ表現は、以下に示す方法でCのデータ表現に変換される。 EusLispの30ビット整数(文字列を含む)は、符号拡張され、スタックを通してCの関数に渡される。 30ビット実数は、倍精度実数(double)に拡張され、スタックを通して渡される。 文字列と整数ベクトルと実数ベクトルについては、その最初の要素のアドレスのみが スタックに渡され、行列自体はコピーされない。 Euslispには、2次元以上の配列を渡す方法がない。 2次元以上の配列はすべての要素を線形に保持する1次元ベクトルを持つ。 このベクトルは、array-entityマクロにより得られる。 もし、2次元行列をFORTRANのサブルーチンに送る場合、FORTRANにおいて列と行が反対となっているため その行列を転置しなければならないことに注意すること。
実数のEuslisp表現は、いつも単精度であるので、倍精度の実数のベクトルに渡すとき変換を要する。 変換関数、double2floatとfloat2doubleは、この目的でclib/double.cの中に定義されている。 例えば、もし3x3の実数行列があり、CFのいう名のCの関数にそれを倍精度実数の行列として渡したいなら、 以下のように使用すればよい。
(setq mat (make-matrix 3 3))
(CF (float2double (array-entity mat)))
Cの構造体は、defstructマクロにより定義することができる。 defstructは、次のようなフィールド定義書式によりstruct-nameを受け取る。
(defcstruct <struct-name>
{(<field> <type> [*] [size])}*)
たとえば、以下に示す構造体の定義は、つぎのdefstructによって表現される。
/* C definition */
struct example {
char a[2];
short b;
long *c;
float *d[2];};
/* equivalent EusLisp definition */
(defcstruct example
(a :char 2)
(b :short)
(c :long *)
(d :float * 2))
load-foreign objfile &key symbol-input symbol-output (symbol-file objfile) ld-option)
Euslisp以外の言語で書かれたオブジェクトモジュールをロードする。 Solaris2において、load-foreignは:entryパラメータにnull文字列を 与えたloadを呼び出す。 コンパイルされたコードのオブジェクトが返される。 この結果は、後にdefforeignを呼び出すことによって モジュールの中の関数のエントリーを作ることが 必要である。 ライブラリーはld-optionに指定することができる。 しかしながら、ライブラリの中に定義されたsymbolはデフォルトのsymbol-outputファイルで 獲得することができない。 ライブラリで定義された関数の呼び出しをEuslispに許可するために、 symbol-outputとsymbol-fileが明示的に与えられなければならない。 (もし、objfileからのみそれらを参照するならば、これらの引き数は必要ない。) load-foreignは、指定されたライブラリとグローバル変数と一緒にobjfileをEuslispのコアにリンクし、 リンクされたオブジェクトをsymbol-outputに書き込む。 それから、symbol-fileの中のsymbolは、検索され、他言語モジュールの中にリストアップされる。 symbol-fileのデフォルトがobjfileであるので、もしsymbol-fileが与えられないなら、 objfileに定義されているsymbolのみ認識される。 objfileとライブラリの両方のグローバルエントリーをすべて見るために、 load-foreignの最初のプロセスリンクの結果であるリンクされた(マージされた)symbolテーブル は確かめられなければならない。このような理由で、symbol-outputとsymbol-fileの両方に 同一のファイル名を与えなければならない。
以下に示されるように、中間のsymbolファイルはunix:unlinkによって 削除することができる。 しかしながら、もし同じライブラリを参照する2つ以上の他言語モジュールをロードするとき、 ライブラリの2重化を避けたいなら、symbol-output引き数を使用しなければならない。 上記の例として、“linpack.a”のすべての関数をロードしており、 次に“linpack.a”の関数を呼び出している他のファイル“linapp.o”を呼びだそうとしていると仮定する。 次のload-foreign呼び出しは、“euslinpack”をunlinkする前に発行しなければならない (load-foreign “linapp.o” :symbol-input “euslinpack”)。 load-foreignとdefforeignのもっと完全な例は、eusdir*/llib/linpack.lで 見ることができる。
(setq linpack-module (load-foreign "/usr/local/eus/clib/linpackref.o" :ld-option "-L/usr/local/lib -llinpack -lF77 -lm -lc" :symbol-output "euslinpack" :symbol-file "euslinpack" )) (unix:unlink "euslinpack")
defforeign funcname module cname paramspec resulttype
他言語モジュールの中の関数エントリーを作る。 funcnameは、Euslispに作られるsymbolである。 moduleは、load-foreignによって返されるコンパイルされたコードのオブジェクトである。 cnameは、他言語プログラムの中で定義されているCの関数の名前である。 その名前は“_myfunc”のような文字列である。 paramspecは、パラメータの型指定のリストである。 それは、EuslispからCの関数に引き数を渡すときに、データの型変換と強制(coercion)を行うために使用される。 データ変換がなかったり、あるいは型チェックが必要ないとき、paramspecはNILで構わない。 :integer, :float, :string, (:string n)の内の1つがresulttypeに与えられなければならない。 :integerは、Cの関数がchar,short,int(long)のいずれかを返すことを意味する。 :floatは、返す値がfloatあるいはdoubleのときに指定する。 :stringは、C関数がstringへのポインターを返すことを意味し、 EuslispはEuslispの文字列に変更するためにstringにlong-wordのヘッダーを追加する。 文字列の長さはstrlenによって見つけられる。 stringの直前に書き込まれるヘッダーは、悲惨な結果を引き起こすことがあることに注意。 もう一方で、(:string n)は、安全だが遅い。なぜなら、 nの長さを持つEuslispの文字列が新しく作成され、Cの文字列の内容が そこにコピーされるからである。 (:string 4)は、整数へのポインターを返すCの関数に使用できる。 FORTRANユーザーは、FORTRANの関数あるいはサブルーチンのあらゆる引き数は、 call-by-refferenceによって渡されることに注意すべきである。 したがって、1つの整数あるいは実数型の引き数でさえFORTRANへ 渡される前に整数ベクトルあるいは実数ベクトルに 置かれなければならない。
defun-c-callable funcname paramspec resulttype &rest body
他言語のコードから呼び出すことができるEuslispの関数を定義する。 funcnameは、Euslispの関数として定義されているsymbolである。 paramspecは、defforeignの中の型指定のリストである。 defforeignのparamspecと違い、defun-c-callableのparamspecは、 関数が引き数を全く受け取らない場合以外、省略することができない。 :integerは、int,char,shortのすべての型に使用すべきである。 :floatは、floatとdoubleに使用する。 resulttypeは、Lisp関数の型である。 resulttypeは、型のチェックあるいは整数から実数に型の強制を 必要とする場合を除いて、省略することができる。 bodyは、この関数がCから呼び出されるとき、実行されるlisp表現である。 defun-c-callableで定義されている関数は、Lisp表現からでも 呼び出すことができる。 defun-c-callableはfuncnameを返す。 その返り値は、symbolのようであるが、そうではなく、symbolのサブクラスである foreign-podのインスタンスである。
pod-address funcname
で定義されたCで呼び出し可能なLisp関数funcnameにおける 他言語とEuslispとのインターフェースコードのアドレスを返す。 これは、他言語プログラムにLisp関数の位置を知らせるために使用される。
array-entity array-of-more-than-one-dimension
多次元配列の要素を保持する1次元ベクトルを返す。 これは、多次元あるいは一般の配列を他言語に渡すために必要である。 しかし、1次元のベクトルは直接渡すことができる。
float2double float-vector &optional doublevector
を倍精度実数の表現に変換する。 その結果は、float-vectorであるが、最初の引き数の長さの2倍になっている。
double2float doublevector &optional float-vector
倍精度実数表現が単精度のfloat-vectorに変換される。
VxWorks¶
ホストとVxWorksとの通信機能が“vxworks/vxweus.l”ファイルで提供されている。 VxWorks上にvxwservサーバを常駐させることにより、 ホスト上のEusLispからvxwservに コネクションを張り、vxwsプロトコルに従った コマンドを送ることにより、VxWorksの関数を起動し、引数を送り、 結果を受け取ることができる。
VxWorksのソフトはSunのcコンパイラによって開発することができる上、 データ表現がsun3, sun4, VME147の間で共通であることを利用して、 vxwsプロトコルは、バイナリモードで動作することができる。
VxWorks側の起動¶
VxWorksにログインし、“*eusdir*/vxworks/vxwserv.o”をロードする。 その後、vxwservタスクをspawnする。 vxwservはVxWorks上の2200番ポートをlistenする。 2200が塞がっている場合、2201, 2202, ...を試す。 正しくbindされたポート番号が表示される。
% rlogin asvx0 (あるいはetlic2上であれば、% tip asvx[01] も可能)
-> cd "atom:/usr/share/src/eus/vxworks"
-> ld <vxwserv.o
-> sp vxwserv
port 2200 is bound.
VxWorksのiコマンドで、vxwservタスクが常駐したことを確かめる。 同じ要領で、eusから呼び出したいVxWorksのプログラムをVxWorks上にロードする。 その後、EuslispとVxWorksとの コネクションが張られると、vxwservを走らせたTTYに、次のようなメッセージが 出力される。
CLIENT accepted: sock=9 port = 1129: family = 2: addr = c01fcc10:
VxWserv started with 16394 byte buffer
ホスト側の起動¶
任意のマシンの上でeusを起動し、“vxworks/vxweus”をロードする。 connect-vxw関数を用いてvxwservに接続する。 接続後、ソケットストリームがvxw-stream*にバインドされる。 以下に、コネクトの例を示す。この例では、VxWorks上のsin, vadd関数を euslispの関数VSIN,VADとして定義している。
(load "vxworks/vxweus")
(setq s (connect-vxw :host "asvx0" :port 2200 :buffer-size 1024))
(defvxw VSIN "_sin" (theta) :float)
(defvxw VAD "_vadd" (v1 v2) (float-vector 3))
VxWorks上に作成される関数が、vxwsを通じて呼び出されるためには、 次の条件を満たさなければならない。
- 引数は、32個以内であること、引数に受け取るベクタの容量の合計が connect-vxwの:buffer-sizeで指定した値を越えないこと
- structを引数にしないこと、必ずstructへのポインタを引数にすること
- 結果は、int, float, doubleまたは、それらの配列のアドレスであること
- 配列のアドレスを結果とする場合、その配列の実体は、 関数の外部に取られていること
:hostに対してvxwsプロトコルによる通信のためのソケットストリームを作成し、そのストリームを返す。 :hostには、ネットワークにおけるVxWorksのアクセス番号あるいはアクセス名を指定する。 :portには、VxWorks上のvxwservがバインドしたポートを捜すための最初のポート番号を指定する。 このポート番号から、増加方向に接続を試行する。 :optionのコードについては、VxWorksの、spawn関数を参照のこと。 コネクションは、同時に複数張ってよい。
vxw vxw-stream entry result-type args
は、vxw-streamに接続されているVxWorksの関数entryを呼び出し、 その関数に引き数argsを与えてresult-typeで指定された結果を得る。 vxw-streamには、connect-vxwで作成したソケットストリームを与える。 entryには、VxWorksの関数名をストリングで指定するか、あるいは関数の アドレスを整数で指定する。 関数のアドレスを知るには、VxWorksのfindsymbolを呼び出す。 知りたいシンボルは、通常、“_”で始まることに注意。 entryがストリングの場合、VxWorks上でシンボルテーブルの逐次探索が行われる。 result-typeには、結果のデータ型(:integerまたは:float)、 あるいはデータを受け取るベクタ型を指定する。 ベクタは、float-vector, integer-vector, stringのインスタンスである。 general vector(lispの任意のオブジェクトを要素とするベクタ)は指定できない。 結果型は、必ず、実際のVxWorks関数の結果型と一致しなければならない。 argsには、entryに与える引き数を指定する。 引数に許されるEusLispデータは、integer, float, string, integer-vector, float-vector, integer-matrix, float-matrixである。 ポインタを含んだ一般のオブジェクト、一般のベクトルは送れない。 また、送られたベクトルデータは、一旦vxwservが獲得したバッファの中に蓄積される。 例えば、VxWorksに定義された関数“sin”を呼び出すためには、次のように実行すればよい。 (vxw *vxw-stream* “sin” :float 1.0)
defvxw eus-func-name entry args &optional (result-type :integer)
は、findsymbolを用いてvxwを呼び出して、VxWorksの関数の高速な呼び出しを 実現するためのマクロである。 VxWorksの関数entryを呼び出すためのEuslispの関数eus-func-nameを定義する。 このマクロを実行後は、eus-func-nameを呼び出すことにより、VxWorksの関数を呼び出すことができる。 このとき、呼び出しに使用されるソケットストリームはvxw-stream*に固定されている。 ただし、VxWorks側で、関数をコンパイルし直して再ロードした場合、 新しい関数定義が呼ばれるようにするためには、eus側で、defvxwをもう一度 実行し直して、最新のエントリアドレスが指定されるようにする必要がある。
マルチスレッド¶
マルチスレッドは、Solarisオペレーティングシステム上の 並列プログラミングや非同期プログラミングの機能である。 非同期プログラミングは、プログラムの状態と無関係に発生する 様々なセンサを経由した外部イベントに応答するためのプログラムに要求される。 並列プログラミングは、画像処理や経路計画の干渉チェックのような プロセス向きの計算の効率を改善する場合に効果的である。
マルチスレッドEuslispの設計¶
Solaris 2 オペレーティングシステムのマルチスレッド
マルチスレッドEuslisp(MT-Eus)は、複数のプロセッサを持ったSolaris 2 オペレーティングシステム上で動作する。 Solarisのスレッドは、 共有メモリと異なった環境を持つような従来の UNIXプロセスをCPUに配置するためのユニットである。Solaris OSによって提供されるスレッドのライブラリは、 それぞれのスレッドを単一のLWP(light weight process)に配置する。 このプロセスがカーネルのリソースである。 UNIXのカーネルは、それぞれのスレッドに割り当てられたスレッドの優先権に 基づいて複数の物理CPUにLWPの配置を計画する。 図[threadmodel]は、スレッドとLWPとCPUの関係を表わしたものである。 Euslispの環境およびメモリ管理の設計について、 マルチスレッドの能力を引き出すために2つの大きな変更がされた。
Context Separation¶
MT-Eusは、それぞれのスレッドに対し個別にスタックと環境を配置する。 そのため、他のスレッドと独立に実行することができる。 symbolやconsのようなオブジェクトは、これまでのEuslispのように 共有ヒープメモリ上に配置される。 したがって、block labelやcatch tagやローカル変数のような スレッドの個別データは、他のスレッドから保護される。 ところが、グローバル変数によって示される値(オブジェクト)は、 情報の変更が許可されているすべてのスレッドから見ることができる。
環境はC-stackとbinding-stackおよびlambda, block, catch, let, flet などのローカルブロックに繋がるフレームポインタにより構成されており、 新しいスレッドが作成されたときに設置される。 複数の環境が本当のマルチプロセッサマシンの上で同時に 動作できるので、グローバル変数の中の現在の環境に対して単一なポインタ を持つことができない。 むしろ、環境のポインタを最上位の評価から低レベルのメモリ管理に変換するために、 すべての内部関数にもう一つ引き数を付け加えなければならない。
メモリ管理¶
EusLispは、すべての型のオブジェクトに対して単一のヒープの中で フィボナッチバディを用いたメモリ管理方法を採用している。 異なったメモリ要求を持つプログラムを実行した後、 フィボナッチバディが様々な大きさのオブジェクトを等しく高速に配置することができ、コピーなしに素早くガーベージコレクトができ、 かつ、高いメモリ利用率(内部損失が10〜15%で外部損失は無視できる) を示すことを確信した。 マルチスレッドのためには、2つ目のポイントすなわちコピーなしの ガーベージコレクトが重要である。 もし、オブジェクトのアドレスがガーベージコレクトのコピーにより 変化したならば、すべてのスレッド環境のスタックおよびCPUのレジスタ 内のポインタを新しいアドレスに書き換えなければならない。 しかし、この書き換えは不可能かあるいは大変困難である。
すべてのメモリ配置要求は、低レベルのalloc関数によって処理される。 allocは、mutex-lockingをする。なぜなら、大きさを持たないリストの グローバルデータベースを扱うからである。 ガーベージコレクトの始まる時期およびどのスレッドによってガーベージコレクトが 生じるのかを予言できないので、 すべてのスレッドは突発的に起こるガーベージコレクトのために 準備をしておかなければならない。 生きているオブジェクトへのすべてのポインタは、ゴミとして掃除されない ように保護するためいつでもガーベージコレクトからアクセスできるよう 調整されなければならない。 これは、スタックの上に保存されていることを信用する代わりに、 それぞれの環境の固定されたスロットの中に極最近に配置されたオブジェクトに 対するポインタを蓄積することによって達成される。
図 [parathreads]は、スレッドのメモリ要求とforkされたガーベージコレクト 内部でのmarkingおよびsweepingを並列に行っている流れ図を示したものである。 メモリ要求およびポインタの処理を行わないスレッドはガーベージコレクトと並列に 実行することができ、信号処理や画像獲得のような低レベルのタスクの 実時間応答を改善することに注意すること。
非同期プログラミングと並列プログラミングの構築¶
スレッド作成とスレッドプール¶
Solarisにおいて複数のプロセッサ上で並列にプログラムを実行するためには、 そのプログラムは関数の集まりとして書かれる必要がある。 その関数はそれぞれプロセスの中で動的に作成されるスレッドによって 実行される。 スレッドを作成するために要求される時間は、プロセスを作成するよりも 速くなければならないが、スタックを配置しスタックのオーバーフローを 発見するためのページ属性を設定した後にスレッドが動き始めるまでに Euslispにおいて数ミリ秒かかる。 この遅れは関数実施と比較して我慢できないため、 評価時間におけるシステムコールに対する所要時間を排除する目的で、 あらかじめmake-thread関数により十分な数のスレッドが作られ、 システムのスレッドプールに置かれる。 スレッドプールの中のそれぞれのスレッドは、図[threadobj]で示されるように スレッドIDと同期のためのセマフォと引き数や評価結果を転送するためのスロット から構成されるスレッドオブジェクトにより表現される。
スレッドの並列実行¶
スレッドによる並列実行の配置のために、スレッド関数が使用される。 スレッドは、スレッドプールから1つの空きスレッドを取り、 共有メモリを経由して引き数を渡し、図[threadobj]に示されるような セマフォ信号によりスレッドを立ち上げ、 停止することなしに呼出側へスレッドオブジェクトを返す。 立ち上げられたスレッドは、呼び出したスレッドと並列に実行され、 引き数を評価し始める。 呼出側は、forkされたスレッドから評価結果を受けとるためにwait-threadを 使用する。 plistマクロは、引き数の並列評価を記述するために大変便利な書式である。 plistは、それぞれの引き数を評価するためにスレッドを割り当て、 すべてのスレッドが評価し終わるのを待って結果をリストアップする。
同期の手法¶
MT-Eusは、mutex lock, condition variable, セマフォと呼ばれる 3種類の同期手法を持っている。 mutex lockは、スレッド間の共有変数の連続アクセスのために使用される。 condition variableは、ロックの仮開放あるいは再獲得によってmutex-lockされた 部分の条件がtrueになることを待つことをスレッドに許可する。 セマフォは、イベントの発生を通知するためあるいはリソースの分割を制御するために 使用される。 Solarisのカーネルが時間分割スケージューリングを基本として何気なしにタスク 切り替えを発生するのと異なり、 これらの同期手法は、任意の環境切り替えを引き起こす。
同期障壁¶
barrier-synchは、複数のスレッドを同時に同期させるための機構である (図 [synchports])。 この目的において、barrierクラスのインスタンスが作成され、 同期に関係するスレッドがオブジェクトに登録される。 その後、それぞれのスレッドはbarrierオブジェクトに:waitメッセージを 送り、そのスレッドは停止する。 オブジェクトに登録された最後のスレッドが:waitメッセージを送ったとき、 待ちが解除され、すべての待ちスレッドがTの返り値を得る。 barrier-syncは、マルチロボットシミュレーションのグローバルタイムという 重要な役割を演じている。
同期メモリポート¶
同期メモリポート(synch-memory-port)は、 スレッド間でデータを交換するための1種のストリーム である(図 [synchports])。 プロセス内のすべてのスレッドはヒープメモリを共有しているので、 もし1つのスレッドがグローバル変数にオブジェクトを割り当てた場合、 直ちに他のスレッドから見れるようになる。 しかしながら、共有メモリはグローバルデータが更新されたという イベントを送るための能力が不足している。 同期メモリポートは、共有オブジェクトをアクセスするための この同期機能を保証する。 同期メモリポートオブジェクトは、1つのバッファスロットと同期読み書きの ために使用される2つのセマフォによって構成されている。
タイマー¶
実時間プログラムは、予定された時間に実行される関数や、 特定の間隔で繰り返される関数をしばしば要求する。 これまでのEusLispは、Unixのインターバルタイマーによって 定期的に生成される信号によって発生するユーザー関数を 実行することができた。 MT-Eusにおいて、この実行はデッドロックを引き起こす。 なぜなら、割り込みがmutex-lockされたブロック内から発生する可能性がある。 したがって、制御はevalの最初のように安全な場所で渡されなければ ならない。 上記の同期によって引き起こされる遅れを避けるために、 MT-Eusはセマフォを経由して信号通知(signal-notification)も 提供する。 言い換えれば、信号関数は呼び出されるかあるいは信号の到着を知らせる 関数あるいはセマフォのどちらかをとる。 セマフォは、低レベルで告示されるので、 同期により隠れているところは最小である。
以下に示すものは、マルチスレッド機能を用いた画像処理のプログラム例である。 画像入力スレッドとフィルタースレッドが生成される。 samp-imageは、33msec毎に通知されるsamp-semを待つことにより、 定期的に画像データをとる。 2つのスレッドはthread-portの読み書きを通じて同期する。 filter-imageは、フィルターの並列計算のために複数のスレッドを使用している。
(make-threads 8) (defun samp-image (p) (let ((samp-sem (make-semaphore))) (periodic-sema-post 0.03 samp-sem) (loop (sema-wait samp-sem) (send p :write (read-image)))) (defun filter-image (p) (let (img) (loop (setf img (send p :read)) (plist (filter-up-half img) (filter-low-half img))))) (setf port (make-thread-port)) (setf sampler (thread #'samp-image port)) (setf filter (thread #'filter-image port))
並列度の計測¶
表 [paragain]は、32CPUで構成されるCray Superserverの上で測定 した並列実行効率を示したものである。 コンパイルされたフィボナッチ関数において線形な並列度が得られた。 なぜなら、共有メモリへのアクセスがなく、それぞれのプロセッサのキャッシュ メモリに十分ロードできるほどちいさなプログラムであったためである。 それに反して、同じプログラムをインタープリターで実行したとき、 キャッシュメモリを使い果たしたため、 線形な高効率を達成することができなかった。 さらにまた、頻繁に共有メモリを参照するようなプログラムや メモリ配置を要求するようなプログラムは1個のプロセッサで実行した ときよりも良い性能を得ることができなかった。 これは、頻繁なキャッシュメモリの入れ替えが原因と考えられる。
processors | 1 | 2 | 4 | 8 | GC (ratio) |
---|---|---|---|---|---|
|
1.0 | 2.0 | 4.0 | 7.8 | 0 |
|
1.0 | 1.7 | 2.7 | 4.4 | 0 |
|
1.0 | 1.3 | 0.76 | 0.71 | 0.15 |
|
1.0 | 0.91 | 0.40 | 0.39 | 0.15 |
|
1.0 | 0.88 | 0.55 | 0.34 | 0.21 |
Table: マルチプロセッサ上で実行されたプログラムの並列度
スレッド生成¶
スレッドは、計算を割り当てる単位であり、普通lisp書式を評価する ための単位である。 Euslispのスレッドは、threadクラスのインスタンスによって 表現される。 このオブジェクトは、内容を表現するスレッド全体というよりはむしろ、 実際に引き数と結果を渡すためのスレッドの 制御ポートであり、評価を始めるものである。
sys:make-thread num &optional (lsize 32*1024) (csize lsize)
ワードのlispスタックとcsizeワードのC-スタックを持つ スレッドをnum個だけ生成し、システムのスレッドプールに 置く。 スレッドプール内のすべてのスレッドは、sys:*threads*に束ねてあり、 make-threadが呼び出されたときに拡張される。 thread関数によって、計算はスレッドプールの中で空いたスレッドの 1つに割り当てられる。 したがって、指定された計算がどのスレッドに割り当てられるか 制御できないため、スレッドのスタックサイズを変更する方法が無い。
sys:*threads* **
によって作成されたすべてのスレッドのリストを持つ。
sys::free-threads **
スレッドプール内の空いたスレッドのリストを返す。 もし、結果がNILならば、スレッドへのタスクの新しい付託は現在実行されている スレッドのどれかの評価が終了するかあるいは make-threadによってスレッドプールに新しいスレッドを生成するまで 停止される。
sys:thread func &rest args
スレッドプールから空いたスレッドを1つ取り出し、 (func . args)の評価のためにそれを割り当てる。 sys:threadは、argsを展開したリストにfuncを適用 するが、関数の適用結果を受け取らないため、 非同期のfuncallとみなすことができる。 むしろ、sys:threadはfuncallに割り当てられたスレッド オブジェクトを返すので、実際の結果はsys:wait-threadによって 後から得ることができる。
(defun compute-pi (digits) ...) (setq trd (sys:thread \#'compute-pi 1000)) ;assign compute-pi to a thread ... ;; other computation (sys:wait-thread trd) ;get the result of (compute-pi 1000)
sys:thread-no-wait func &rest args
空いたスレッドの1つに計算を割り当てる。 スレッドは、wait-threadされることなしに、 評価が終了したとき、スレッドプールに戻される。
sys:wait-thread thread
にsys:thread関数によって与えられたfuncallの評価が 終了するのを待ち、その結果を受け取り、返す。 もし、スレッドにsys:threadによって評価が割り当てられたならば、 sys:wait-threadは、必須である。 なぜなら、スレッドは結果を転送し終わるまでスレッドプールに戻らない ためである。
sys:plist &rest forms
異なったスレッドにより並列にformsを評価し、 すべての評価が終了するのを待ち、 結果のリストを返す。 sys:plistは、リスト化されたそれぞれのformが関数呼び出しされる ことを除いて、parallel-listとしてみなされるだろう。
同期¶
Solarisオペレーティングシステム内には、マルチスレッドプログラムのために 4つの同期手法がある。 Euslispは、mutex-lockとcondition variableとセマフォを提供している。 reader-writer lockは実現されてない。 これらの手法に基づいて、同期メモリポートや同期障壁のような 高レベルの同期機構が実現されている。
sys:make-mutex-lock **
mutex-lockを作り、返す。 mutex-lockは、6つの要素を持つ整数ベクトルで表現されている。
sys:mutex-lock mlock
mutex-lockのmlockをロックする。 もし、mlockが既に他のスレッドからロックされているなら、 mutex-lockはロックが外されるまで待つ。
sys:mutex-unlock mlock
を解除し、このロックを待っている他のスレッドの内の1つが再び実行され始める。
sys:mutex mlock &rest forms
mutex-lockとmutex-unlockは、組みで使用されなければならない。 mutexは、重要な部分をひとまとまりにしたマクロである。 mlockは、評価するformsが評価される前にロックされる。 そして、評価が終了したときに、ロックが解除される。 このマクロは、以下のprogn formに展開される。 unwind-protectは、formsの評価中にエラーが発生したとき でさえ、ロックの解除を保証するために使用されることに注意すること。
(progn (sys:mutex-lock mlock) (unwind-protect (progn . forms) (sys:mutex-unlock mlock)))
sys:make-cond **
4つの要素を持つ整数ベクトルであるcondition variableオブジェクトを 作る。condition variableの返り値としては、ロックされてない状態でである。
sys:cond-wait condvar mlock
に信号が出されるまで待つ。 もし、condvarが他のスレッドによってすでに獲得されていたならば、 mlockを解除し、condvarに信号が出されるまで待つ。
sys:cond-signal condvar
で示されるcondition variableに信号を出す。
sys:make-semaphore **
20の要素を持つ整数ベクトルによって表現されるセマフォオブジェクトを作る。
sys:sema-post sem
に信号を出す。
sys:sema-wait sem
に信号が来るまで待つ。
sys:barrier-synch
同期障壁のための構造を表現する。 同期を待っているスレッドは、thread-lockによって 相互に排除されるthreadに置かれる。 barrier-synchオブジェクトが生成されたとき、 countは、ゼロに初期化される。 同期しているスレッドは、:addメッセージを送ることによって、 threadsリストに置かれる。 このbarrier-synchオブジェクトに:waitを送ることは、 countを増加させることの原因となり、 送られたスレッドは待ち状態になる。 threadsの中のすべてのスレッドに:waitメッセージが送られたとき、 待ちが解除され、すべてのスレッドの実行が再び始まる。 同期は、count-lockのmutex-lockとbarrier-condのcondition-variable の組み合わせによって実行される。
:init **
このbarrier-synchオブジェクトを初期化する。 2つのmutex-lockと1つのcondition-variableが生成される。
:add thr
リストの中にthrスレッドが追加される。
:remove thr
リストの中からthrスレッドを削除する。
:wait **
リストの中のすべてのスレッドに:waitが配布されるのを待つ。
sys:synch-memory-port
1方向の同期されたメモリポートを実現する。 このオブジェクトを通じてデータを転送するために、2つのスレッドを同期させる。 転送制御は、セマフォを用いて実現されている。
:read **
このsynch-memory-portにバッファされているデータを読む。 もし、まだ書かれていなかったならば、:readは停止する。
:write datum
バッファにdatumを書き込む。 1ワードのバッファのみ存在するので、 もし他のデータが既に書かれておりまだ読まれていなかったならば、 :writeは:readによってそのデータが読み込まれるまで待つ。
:init **
このsync-memory-portを初期化する。 これには2つのセマフォが生成され、:write動作が可能な状態になっている。
幾何学関数¶
実数ベクトル(float-vector)¶
float-vectorは、要素が実数である1次元ベクトルである。 float-vectorは、どんなサイズでも良い。 resultが引き数リストで指定されているとき、 そのresultはfloat-vectorであるべきである。
float-vector &rest numbers
を要素とするfloat-vectorを新しく作る。 (float-vector 1 2 3)と#F(1 2 3)の違いに注意すること。 前者は、呼ばれたときはいつでもベクトルが生成されるが、 後者は読み込まれたときのみ生成される。
float-vector-p obj
がfloat-vectorであるならば、Tを返す。
v+ fltvec1 fltvec2 &optional result
2つのfloat-vectorを加える。
v- fltvec1 &optional fltvec2 result
2つのfloat-vectorを差し引く。もし、fltvec2が省略されているならば、 fltvec1の符号が反転される。
v. fltvec1 fltvec2
2つのfloat-vectorの内積を計算する。
v* fltvec1 fltvec2 &optional result
2つのfloat-vectorの外積を計算する。
v.* fltvec1 fltvec2 fltvec3
スカラー3重積を計算する。(v.* A B C)=(V. A (V* B C))=(V. (V* A B) C)
v:math:`=` fltvec1 fltvec2
もし、fltvec1の要素がfltvec2の対応する要素とすべて等しいとき、 Tを返す。
v:math:`<` fltvec1 fltvec2
もし、fltvec1の要素がfltvec2の対応する要素よりすべて小さいとき、 Tを返す。
v:math:`>` fltvec1 fltvec2
もし、fltvec1の要素がfltvec2の対応する要素よりすべて大きいとき、 Tを返す。
vmin &rest fltvec
の中のそれぞれの次元における最小値を捜し、 その値でfloat-vectorを新しく作る。vminとvmaxは、 頂点の座標から最小のminimal-boxを見つけるために使用される。
vmax &rest fltvec
の中のそれぞれの次元における最大値を捜し、 その値でfloat-vectorを新しく作る。
minimal-box v-list minvec maxvec &optional err
与えられたv-listに対してminimal bounding boxを計算し、 その結果をminvecとmaxvecに蓄積する。 もし、実数errが指定されているならば、minimal boxはその比率によって 成長する。すなわち、もしerrが0.01のとき、minvecのそれぞれの 要素はminvecとmaxvecとの距離の1%減少する。 そして、maxvecのそれぞれの要素は1%増加する。 minimal-boxは、minvecとmaxvecとの距離を返す。
scale number fltvec &optional result
のすべての要素をスカラーnumber倍する。
norm fltvec
のノルムを求める。\(\Vert fltvec\Vert\)
norm2 fltvec
のノルムの2乗を求める。 \(\Vert fltvec\Vert^2\)=(v. fltvec fltvec)
normalize-vector fltvec &optional result
のノルムが1.0となるように正規化する。
distance fltvec1 fltvec2
2つのfloat-vectorの距離を返す。\(|fltvec-fltvec2|\)
distance2 fltvec1 fltvec2
2つのfloat-vectorの距離の2乗を返す。\(|fltvec-fltvec2|^2\)
homo2normal homovec &optional normalvec
同次ベクトルhomovecを正規表現に変換する。
homogenize normalvec &optional homovec
正規ベクトルnormalvecを同次表現に変換する。
midpoint p p1 p2 &optional result
は実数で、p1,p2は同次元のfloat-vectorである。 p1:math:`-`p2を\(p:(1-p)\)の比率で等分した点\((1-p)\cdot p1 + p\cdot p2\) を返す。
rotate-vector fltvec theta axis &optional result
2次元あるいは3次元のfltvecをaxis回りにthetaラジアン 回転する。 axisは、:x, :y, :z, 0, 1, 2, または NILの内の一つである。 axisがNILのとき、fltvecは2次元として扱われる。 3次元空間の任意の軸の回りにベクトルを回転するためには、 rotation-matrixで回転行列を作り、そのベクトルにかければよい。
行列と変換¶
行列は、要素がすべて実数の2次元の配列である。 ほとんどの関数において行列はどんなサイズでもよいが、 v*, v.*, euler-angle, rpy-angle関数では3次元の行列のみ 扱うことができる。 transform, m*とtransposeは、行列を正方行列に限定せず、 一般のn*m行列に対して処理を行う。
resultパラメータを受けた関数は、計算結果をそこに置く。 そのため、ヒープは使用しない。 すべての行列関数は、正規座標系における変換を考慮しており、 同次座標系は考慮していない。
rpy-angle関数は、回転行列をワールド座標系におけるz,y,x軸回りの 3つの回転角に分解する。 euler-angle関数はrpy-angleと同様に分解するが、 回転軸がローカル座標系のz,y,z軸となっている。 角度が反対方向にも得られるため、これらの関数は2つの解を返す。
; Mat is a 3X3 rotation matrix.
(setq rots (rpy-angle mat))
(setq r (unit-matrix 3))
(rotate-matrix r (car rots) :x t r)
(rotate-matrix r (cadr rots) :y t r)
(rotate-matrix r (caddr rots) :z t r)
;--> resulted r is equivalent to mat
3次元空間の位置と方向の組みを保つために、[Coordinates]節に記載されている coordinatesとcascaded-coordsクラスを使用すること。
matrix &rest elements
から行列を新しく作る。 Row x Col = (elementsの数) x (最初のelementの長さ) elementsは、どの型の列((list 1 2 3)や(vector 1 2 3)や (float-vector 1 2 3))でもよい。 それぞれの列は行列の行ベクトルとしてならべられる。
make-matrix rowsize columnsize &optional init
\(rowsize \times columnsize\)の大きさの行列を作る。
matrixp obj
もし、objが行列のとき、すなわち、objが2次元の配列で その要素が実数であるとき、Tを返す。
matrix-row mat row-index
行列matからrow-indexで示される行ベクトルを抽出する。 matrix-rowは、setfを使用することにより 行列の特定の行にベクトルを設定することにも使用される。
matrix-column mat column-index
行列matからcoloumn-indexで示される列ベクトルを抽出する。 matrix-columnは、setfを使用することにより 行列の特定の列にベクトルを設定することにも使用される。
m* matrix1 matrix2 &optional result
とmatrix2の積を返す。
transpose matrix &optional result
の転置行列を返す。すなわち、matrixの列と行を入れ替える。
unit-matrix dim
\(\times\) dimの単位行列を作る。
replace-matrix dest src
行列destのすべての要素を同一な行列srcで置き換える。
scale-matrix scalar mat
のすべての要素にscalerを掛ける。
copy-matrix matrix
のコピーを作る。
transform matrix fltvector &optional result
行列matrixをベクトルfltvectorの左から掛ける。
transform fltvector matrix &optional result
行列matrixをベクトルfltvectorの右から掛ける。
rotate-matrix matrix theta axis &optional world-p result
で行列matrixを回転させるとき、 回転軸(:x, :y, :zまたは0,1,2)はワールド座標系あるいは ローカル座標系のどちらかを与えられる。 もし、world-pにNILが指定されているとき、 ローカル座標系の軸に沿った回転を意味し、回転行列を左から掛ける。 もし、world-pがnon-NILのとき、 ワールド座標系に対する回転行列を作り、回転行列を右から掛ける。 もし、axisにNILが与えられたとき、行列matrixは2次元と仮定され、 world-pの如何にかかわらず2次元空間の回転が与えられる。
rotation-matrix theta axis &optional result
軸回りの2次元あるいは3次元の回転行列を作る。 軸は:x,:y,:z,0,1,2,3次元ベクトルあるいはNILのどれかである。 2次元回転行列を作るとき、axisはNILでなければならない。
rotation-angle rotation-matrix
から等価な回転軸と角度を抽出し、 実数とfloat-vectorのリストを返す。 rotation-matrixが単位行列のとき、NILが返される。 また、回転角が小さいとき、結果がエラーとなる。 rotation-matrixが2次元のとき、1つの角度値が返される。
rpy-matrix ang-z ang-y ang-x
ロール、ピッチ、ヨー角で定義される回転行列を作る。 最初に、単位行列をx軸回りにang-xラジアン回転させる。 次に、y軸回りにang-yラジアン、最後にz軸回りにang-z ラジアン回転させる。 すべての回転軸はワールド座標系で与えられる。
rpy-angle matrix
の2組のロール、ピッチ、ヨー角を抽出する。
Euler-matrix ang-z ang-y ang2-z
3つのオイラー角で定義される回転行列を作る。 最初に単位行列をz軸回りにang-z回転させ、次にy軸回りにang-y 回転させ、最後にz軸回りにang2-z回転させる。 すべての回転軸はローカル座標系で与えられる。
Euler-angle matrix
から2組のオイラー角を抽出する。
LU分解¶
lu-decomposeとlu-solveは、線形の連立方程式を 解くために用意されている。 最初に、lu-decomposeは行列を下三角行列を上三角行列に分解する。 もし、行列が特異値なら、lu-decomposeはNILを返す。 そうでなければ、lu-solveに与えるべき順列ベクトルを返す。 lu-solveは、与えられた定数ベクトルの解をLU行列で計算する。 この手法は、同じ係数行列と異なった定数ベクトルのたくさんの組に対して 解を求めたいときに効果的である。 simultaneous-equationは、1つの解だけを求めたいときにもっとも 手軽な関数である。 lu-determinantは、LU分解された行列の行列式を計算する。 inverse-matrix関数は、lu-decomposeを1回とlu-solveをn回 使って逆行列を求める。 3*3行列での計算時間は約4msである。
lu-decompose matrix &optional result
にLU分解を実行する。
lu-solve lu-mat perm-vector bvector &optional result
LU分解された1次連立方程式を解く。 perm-vectorは、lu-decomposeで返された結果でなければならない。
lu-determinant lu-mat perm-vector
LU分解された行列の行列式を求める。
simultaneous-equation mat vec
係数がmatで、定数がvecで記述される1次連立方程式を解く。
inverse-matrix mat
正方行列matの逆行列を求める。
pseudo-inverse mat
特異値分解を用いて擬似逆行列を求める。
座標系¶
座標系と座標変換は、coordinatesクラスで表現される。 4*4の同次行列表現の代わりに、 Euslisp内で座標系は、高速性と一般性のために 3*3の回転行列と3次元位置ベクトルの組で表現される。
coordinates
位置ベクトルと3x3の回転行列の組みで座標系を定義する。
coordinates-p obj
がcoordinatesクラスかまたはそのサブクラスのインスタンス のとき、Tを返す。
:rot **
この座標系の3x3回転行列を返す。
:pos **
この座標系の3次元位置ベクトルを返す。
:newcoords newrot &optional newpos
とnewposでこの座標系を更新する。 newposが省略された時はnewrotにはcoordinatesのインスタンスを 与える。 この座標系の状態が変化するときはいつでも、このメソッドを用いて新しい 回転行列と位置ベクトルに更新するべきである。 このメッセージはイベントを伝えて他の:updateメソッドを呼び出す。
:replace-coords newrot &optional newpos
メソッドを呼び出さずにrotとposスロットを変更する。 newposが省略された時はnewrotにはcoordinatesのインスタンスを与える。
:coords **
:copy-coords &optional dest
もしdestが与えられなかったとき、:copy-coordsは同じrotとpos スロットを持つ座標系オブジェクトを作る。 もし、destが与えられたとき、dest座標系にこの座標系のrotとposを コピーする。
:reset-coords **
この座標系の回転行列を単位行列にし、位置ベクトルをすべてゼロにする。
:worldpos **
:worldrot **
:worldcoords **
このオブジェクトのワールド座標系における位置ベクトル・回転行列・座標系 を計算する。 その座標系は、いつもワールド座標系で表現されていると仮定され、 これらのメソッドは簡単にposとrotとselfを返すことができる。 これらのメソッドはcascaded-coordsクラスと互換性がとられている。 cascaded-coordsではワールド座標系での表現と仮定していない。
:copy-worldcoords &optional dest
最初に、ワールド座標系が計算され、destにコピーされる。 もし、destが指定されてないとき、新たにcoordinates オブジェクトを作る。
:rotate-vector vec
この座標系の回転行列によってvecを回転させる。すなわち、 この座標系で表現される方向ベクトルをワールド座標系における表現 に変換する。 この座標系の位置は、回転に影響を与えない。
:transform-vector vec
この座標系で表現されるvecをワールド座標系の表現に変換する。
:inverse-transform-vector vec
ワールド座標系におけるvecをローカル座標系の表現に逆変換する。
:transform trans &optional (wrt :local)
座標系で表現されるtransによってこの座標系を変換する。 transは座標系の型でなければならないし、wrtは :local, :parent, :worldのキーワードあるいはcoordinatesの インスタンスでなければならない。 もしwrtが:localのとき、transをこの座標系の右 から適用する。もしwrtが:world, :parentのとき、 transを左から掛ける。 もしwrtがcoordinatesの型であるとき、wrt座標系で表現される transは最初にワールド座標系の表現に変換され、左から掛ける。
:move-to trans &optional (wrt :local)
で表現されるtransでこの座標系のrotとpos を置き換える。
:translate p &optional (wrt :local)
このオブジェクトの位置をwrt座標系で相対的に変更する。
:locate p &optional (wrt :local)
この座標系の位置をwrt座標系で絶対的に変更する。 もし、wrtが:localのとき、:translateと同一な 効果を生む。
:rotate theta axis &optional (wrt :local)
軸回りにthetaラジアンだけ相対的にこの座標系を回転させる。 axisは、軸キーワード(:x, :y, :z)あるいは任意のfloat-vector である。 axisはwrt座標系で表現されていると考える。 よって、もしwrtが:localでaxisが:zであるとき、 座標系はローカル座標系のz軸回りに回転される。 もしwrtが:world, :parentであるとき、ワールド座標系のz軸回りに 回転される。 言い換えると、もしwrtが:localのとき、 回転行列はこの座標系の右から掛けられる。 そして、もしwrtが:worldあるいは:parentのとき、 回転行列は左から掛けられる。 wrtが:worldあるいは:parentでさえ、 この座標系のposベクトルは変化しない。 本当にワールド座標系の軸回りに回転するためには、 回転を表現するcoordinatesクラスのインスタンスを :transformメソッドに与えなければならない。
:orient theta axis &optional (wrt :local)
を強制的に変更する。:rotateメソッドの絶対値版である。
:inverse-transformation **
この座標系の逆変換を持つ座標系を新しく作る。
:transformation coords (wrt :local)
この座標系と引き数で与えられるcoordsとの間の変換を作る。 もし、wrtが:localであるとき、ローカル座標系で表現される。 すなわち、もしこの:transformationの結果を:transformの引き数として wrt=:localと一緒に 与えたとき、この座標系はcoordsと同一な座標系に変換される。
:Euler az1 ay az2
オイラー角(az1, ay, az2)で表現される回転行列をrotに 設定する。
:roll-pitch-yaw roll pitch yaw
ロール・ピッチ・ヨー角で表現される回転行列をrotに設定する。
:4x4 &optional mat44
もし、mat44として4x4行列が与えられるとき、3x3回転行列と3次元位置ベクトル の座標表現に変換される。 もし、mat44が与えられないとき、この座標系の表現を 4x4の同次行列表現に変換して返す。
このcoordinatesオブジェクトを初期化し、rotとposを設定する。 それぞれのキーワードの意味は、以下に示す通りである。
- :dimension
- 2あるいは3 (デフォルトは 3)
- :pos
- 位置ベクトルを指定する (デフォルトは #f(0 0 0))
- :rot
- 回転行列を指定する (デフォルトは単位行列)
- :euler
- オイラー角として3つの要素の列を与える
- :rpy
- ロール・ピッチ・ヨー角として3つの要素の列を与える
- :axis
- 回転軸 (:x,:y,:z あるいは任意のfloat-vector)
- :angle
- 回転角 (:axisと一緒に使用)
- :wrt
- 回転軸を示す座標系 (デフォルトは :local)
- :4X4
- 4X4 行列(posとrotを同時に指定)
- :coords
- coordsからrotとposをコピーする
- :name
- :name値を設定する。
:angleは:axisと組みで唯一使用することができる。 その軸は:wrt座標系で決定される。 :wrtと関係なしに:Eulerはローカル座標系で定義されるオイラー角 (az1, ayとaz2)をいつも指定する。 また、:rpyはワールド座標系のz, yとx軸回りの角度 を指定する。 :rot, :Euler, :rpy, :axis, :4X4の中から2つ以上を連続で指定することは できない。しかしながら、指定してもエラーは返さない。 axisと:angleパラメータには列を指定することができる。 その意味は、与えられた軸回りの回転を連続的に処理する。 属性とその値の組みのリストを:propertiesの引き数として 与えることができる。これらの組みは、この座標系のplistにコピーされる。
連結座標系¶
cascaded-coords
連結された座標系を定義する。cascaded-coordsは、 しばしばcascoordsと略す。
:inheritance **
このcascaded-coordsの子孫をすべて記述した継承treeリストを返す。 もし、aとbがこの座標系の直下の子孫でcがaの 子孫であるとき、((a (c)) (b))を返す。
:assoc childcoords &optional relative-coords
は、この座標系の子孫として関係している。 もし、childcoordsが既に他のcascaded-coordsにassocされて いるとき、childcoordsはそれぞれのcascaded-coordsが1つの親しか 持っていないならdissocされる。 ワールド座標系におけるchildcoordsの方向あるいは位置は変更されない。
:dissoc childcoords
この座標系の子孫リストからchildcoordsを外す。 ワールド座標系におけるchildcoordsの方向あるいは位置は変更されない。
:changed **
この座標系の親座標系が変更されていることを通知する。 また、もっとあとでワールド座標系が要求されたとき、ワールド座標系を再計算する 必要がある。
:update **
現在のワールド座標系を再計算するために:worldcoordsメソッド を呼び出す。
:worldcoords **
ルートの座標系からこの座標系までの全ての座標系を連結させることにより、 この座標系をワールド座標系で表現したcoordinatesオブジェクトで返す。 その結果は、このオブジェクトが持ち、後に再利用される。 よって、この結果の座標系を変更すべきでない。
:worldpos **
ワールド座標系で表現したこの座標系のrotを返す。
:worldrot **
ワールド座標系で表現したこの座標系のposを返す。
:transform-vector vec
をこのローカル座標系での表現とみなして、ワールド座標系での 表現に変換する。
:inverse-transform-vector vec
ワールド座標系で表現されるvecをこのローカル座標系の表現に逆変換する。
:inverse-transformation **
この座標系の逆変換を表現するcoordinatesのインスタンスを作る。
:transform trans &optional (wrt :local)
:translate fltvec &optional (wrt :local)
:locate fltvec &optional (wrt :local)
:rotate theta axis &optional (wrt :local)
:orient theta axis &optional (wrt :local)
クラスの記述を参照すること。
make-coords &key pos rot rpy Euler angle axis 4X4 coords name
make-cascoords &key pos rot rpy Euler angle axis 4X4 coords name
coords &key pos rot rpy Euler angle axis 4X4 coords name
cascoords &key pos rot rpy Euler angle axis 4X4 coords name
これらの関数は、すべてcoordinatesあるいはcascaded-coordsを 新しく作る。 キーワードパラメータについては、coordinatesクラスの:initメソッドを 見ること。
transform-coords coords1 coords2 &optional (coords3 (coords))
がcoords2に左から適用(乗算)される。 その積はcoords3に蓄積される。
transform-coords* &rest coords
にリスト表現されている変換を連結させる。 連結された変換で表現されるcoordinatesのインスタンスを返す。
wrt coords vec
をcoordsにおける表現に変換する。 その結果は(send coords :transform-vector vec)と同一である。
変換行列とcoordinates classとの関係¶
変換行列Tを\(4\times4\)の同次行列表現として以下のように表したした時の、 coordinatesとの関係を説明する。
\(\mathbf{R}_T\)は\(3\times3\)行列、\(\mathbf{p}_T\)は\(3\times1\)行列(eus内部処理 では要素数3のfloat-vector)であって、 EusLispにおけるcoordinatesクラスは\(\mathbf{R}\)は\(3\times3\) の回転行列と 3 次元位置ベクトルの組で表現されており、 スロット変数のrotとposは、それぞれ、\(\mathbf{R}_T\)、\(\mathbf{p}_T\)に対応する。
回転行列と3次元位置の取り出し¶
coordinates classのメソッドを用いて、以下のように\(\mathbf{R}\)と\(\mathbf{p}\)を取り出せる。
以下、Tはcoordinateクラスのインスタンスである。
(send T :rot)
\(\Rightarrow\) \(\mathbf{R}_T\)
(send T :pos)
\(\Rightarrow\) \(\mathbf{p}_T\)
ベクトルを変換するメソッド¶
以下、\(\mathbf{v}\)は3次元ベクトルである。
(send T :rotate-vector :math:`mathbf{v}`)
\(\Rightarrow\) \(\mathbf{R}_T \mathbf{v}\)
(send T :inverse-rotate-vector :math:`mathbf{v}`)
\(\Rightarrow\) \(\mathbf{v}^T \mathbf{R}_T\)
(send T :transform-vector :math:`mathbf{v}`)
\(\Rightarrow\) \(\mathbf{R}_T\mathbf{v} + \mathbf{p}_T\)
ローカル座標系Tで表されたベクトルをワールド座標系で表されたベクトルに変換する
(send T :inverse-transform-vector :math:`mathbf{v}`)
\(\Rightarrow\) \(\mathbf{R}_T^{-1}\left( \mathbf{v} - \mathbf{p}_T \right)\)
ワールド座標系で表されたベクトルをローカル座標系Tで表されたベクトルに変換する
座標系を返すメソッド (座標系を変更しない)¶
(send T :inverse-transformation)
\(\Rightarrow\) \(T^{-1}\)
逆行列を返す。
(send T :transformation A (&optional (wrt :local)))
wrt == :local のとき、\(T^{-1}A\) を返す
wrt == :world のとき、\(AT^{-1}\) を返す
wrt == W (coordinates class) のとき、\(W^{-1}AT^{-1}W\) を返す
座標系を変更するメソッド¶
以下、A は coordinatesクラスのインスタンスである。
\(\Leftrightarrow\) はスロット変数と与えられたインスタンス(行列またはベクトル)が同一になることを表す。 一方の変更が、他方の変更に反映されるため、注意して使用すること。
\(\leftarrow\) は代入を表す。
(send T :newcoords A)
\(\mathbf{R}_T \Leftrightarrow \mathbf{R}_A\)
\(\mathbf{p}_T \Leftrightarrow \mathbf{p}_A\)
(send T :newcoords :math:`mathbf{R}` :math:`mathbf{p}`)
\(\mathbf{R}_T \Leftrightarrow \mathbf{R}\)
\(\mathbf{p}_T \Leftrightarrow \mathbf{p}\)
(send T :move-to A (&optional (wrt :local)))
wrt == :local のとき、\(T \leftarrow TA\)
wrt == :world のとき、\(T \Leftrightarrow A\)
wrt == W (coordinates class) のとき、\(T \leftarrow WA\)
(send T :translate :math:`mathbf{v}` (&optional (wrt :local)))
wrt == :local のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{p}_{T} + \mathbf{R}_{T}\mathbf{v}\)
wrt == :world のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{p}_{T} + \mathbf{v}\)
wrt == W (coordinates class) のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{p}_{T} + \mathbf{R}_{W}\mathbf{v}\)
(send T :locate :math:`mathbf{v}` (&optional (wrt :local)))
wrt == :local のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{p}_{T} + \mathbf{R}_{T} \mathbf{v}\)
wrt == :world のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{v}\)
wrt == W (coordinates class) のとき、 \(\mathbf{p}_{T} \leftarrow \mathbf{p}_{W} + \mathbf{R}_{W}\mathbf{v}\)
(send T :transform A (&optional (wrt :local)))
wrt == :local のとき、 \(T \leftarrow TA\)
wrt == :world のとき、 \(T \leftarrow AT\)
wrt == W (coordinates class) のとき、\(T \leftarrow\) \(\left( WAW \right)^{-1} T\)
幾何学モデリング¶
Euslispは、3次元の幾何学モデルの内部表現として(境界表現)を採用している。 Brep内の要素はedge, plane, polygon, face, hole,やbodyクラスによって 表現される。 基本bodyの作成関数とbodyの合成関数は、これらのクラスの新しい インスタンスを作る。 もっと属性を持った独自の幾何学クラスを使用するためには、 edge-class*, *face-class*とbody-class*の特殊変数に 独自のクラスオブジェクトを設定すること。
種々の幾何学関数¶
vplus vector-list
のすべての要素の合計を実数ベクトルとして 新しく作り、返す。 v+との違いは、vplusが2つ以上の引数について合計を計算し、 結果のベクトルが指定できない点である。
vector-mean vector-list
の平均ベクトルを返す。
triangle a b c &optional (normal #f(0 0 1))
は、2次元または3次元の実数ベクトルである。 normalは、a,b,cが置かれる平面の正規ベクトルである。 triangleはa,b,cで形作られる三角形の領域の2倍の大きさを返す。 normalと同じ方向から見たときにa,b,cが時計方向に回転する ならば、triangleは正である。 言い換えると、もしtriangleが正ならば、 cはa-bの線分の左手側に位置し、 bはa-cの右手側に位置している。
triangle-normal a b c
で定義される三角形に対して垂直方向の正規ベクトルを見つける。
vector-angle v1 v2 &optional (normal (v* v1 v2))
2つのベクトルの角度を計算する。 これは次の式であらわされるatan(normal\(\cdot\)(v1:math:timesv2), v1\(\cdot\)v2)。 v1,v2とnormalは正規ベクトルでなければならない。 normalが与えられないとき、v1,v2の共通垂線の正規ベクトルが 使用される。この場合、結果は\(0\)から\(\pi\)までの範囲の正の角度になる。 符号付きの角度を得るためには、normalを指定しなければならない。
face-normal-vector vertices
同じ平面の上にあるベクトルのリストから面の正規化ベクトルを計算する。
farthest p points
3次元ベクトルのリストpointsの中からpより最も遠い点を捜す。
farthest-pair points
3次元ベクトルのリストpointsからもっとも遠い点の組を 捜す。
maxindex 3D-floatvec
の3つの要素の中で絶対値が最大の要素の位置を捜す。
random-vector &optional (range 1.0)
3次元デカルト空間の中で同次的に分散されるランダムベクトルを発生する。
random-normalized-vector &optional (range 1.0)
3次元の正規化ランダムベクトルを返す。
random-vectors count range
の大きさのランダムベクトルをcount個つくり、そのリストを返す。
line-intersection p1 p2 p3 p4
は、すべて2次元以上の実数ベクトルである。 p1-p2とp3-p4が平面上の2つの線分として定義される。 line-intersectionは、これらの2つの線分の交差する点のパラメータ(線分に置ける 交点の位置の比率)を2要素のリストで返す。3次元で使用するとき、 p1, p2, p3, p4は共通平面内になければならない。
collinear-p p1 p2 p3 &optional tolerance
は、すべて3次元の実数ベクトルで3つの点を表現している。 collinear-pは、もし\(\Vert\)((p2:math:-p1)\(\times\)(p3:math:-p1))\(\Vert\)が coplanar-threshold*より小さければ、p1-p3の線分の上に p2を投影したときのパラメータを返す。そうでなければ、NILを返す。
find-coplanar-vertices p1 p2 p3 vlist
は、3次元の実数ベクトルで、この3つのベクトルから平面を表現している。 find-coplanar-verticesは、その平面内にある点を vlistの中から捜す。
find-connecting-edge vertex edgelist
に接続されたedgelistの中からエッジを捜す。
make-vertex-edge-htab bodfacs
は、bodyあるいはfaceのリストである。 make-vertex-edge-htabは、bodfacsの中の頂点を抽出し、それに接続されるエッジの検索ができる ハッシュテーブルを作る。
left-points points p1 p2 normal
は、正規化ベクトルnormalで表現される 平面内にあるものと仮定する。 left-pointsは、p1, p2間の線分の左側に置かれている点を pointsの中から捜し、集める。
right-points points p1 p2 normal
は、正規化ベクトルnormalで表現される 平面内にあるものと仮定する。 right-pointsは、p1, p2間の線分の右側に置かれている点を pointsの中から捜し、集める。
left-most-point points p1 p2 normal
は、正規化ベクトルnormalで表現される 平面内にあるものと仮定する。 left-most-pointsは、p1, p2で決定される線分の左側に置かれている点を pointsの中から捜し、その中でもっとも遠い点を返す。
right-most-point points p1 p2 normal
は、正規化ベクトルnormalで表現される 平面内にあるものと仮定する。 right-most-pointsは、p1, p2で決定される線分の右側に置かれている点を pointsの中から捜し、その中でもっとも遠い点を返す。
eps= num1 num2 &optional (tolerance *epsilon*)
2つの実数num1とnum2を比較して、torelanceの誤差範囲内で 等しいかどうかを返す。
eps:math:`<` num1 num2 &optional (tolerance *epsilon*)
が明らかにnum2よりも小さいときTを返す。すなわち、 num1\(<\)num2-toleranceである。
eps:math:`<=` num1 num2 &optional (tolerance *epsilon*)
が多分num2よりも小さいときあるいは等しいときTを返す。すなわち、 num1\(<\)num2+toleranceである。
eps:math:`>` num1 num2 &optional (tolerance *epsilon*)
が明らかにnum2よりも大きいときTを返す。すなわち、 num1\(>\)num2+toleranceである。
eps:math:`>=` num1 num2 &optional (tolerance *epsilon*)
が多分num2よりも大きいときあるいは等しいときTを返す。すなわち、 num1\(>\)num2-toleranceである。
bounding-box
xy-,yz-やzx-平面に平行な面を境界とする最小の四角柱を定義する。 bounding-boxは、初期に与えられるベクトルの次元によって、 どんな次元でも使用することができる。 bounding-boxは、surrounding-boxの名前で定義されていた。
:box **
このbounding-boxのオブジェクト自身を返す。
:volume **
このbounding-boxの体積を返す。
:grow rate
このbounding-boxのサイズをrate率で増加または減少させる。 rateが0.01のとき、1%拡大される。
:inner point
がこのbounding-box内にあればTを返し、 そうでないときはNILを返す。
:intersection box2 &optional tolerance
このbounding-boxとbox2との共通bounding-boxを返す。 もし、torelanceが与えられたならば、このboxはその誤差で拡大される。 もし、共通部分がなければ、NILを返す。
:union box2
このbounding-boxとbox2を結合したbounding-boxを返す。
:intersectionp box2
このbounding-boxとbox2との間に共通領域があればTを返し、 そうでなければNILを返す。 このメソッドは、:intersectionよりも速い。なぜなら、新しい bounding-boxのインスタンスを作らないためである。
:extreme-point direction
このbounding-boxの8つの頂点の中で、directionとの内積が最大のものを 返す。
:corners **
このbounding-boxのすべての頂点のリストを返す。 もし、このboxが2次元であれば、4点が返される。 同様に3次元の場合、8点が返される。
:below box2 &optional (direction #(0 0 1)
このbounding-boxがbox2に対してdirectionの示すベクトル の下の方向にあればTを返す。 このboundign-boxがdirectionの方向に動かされるとき、 2つのboxに共通部分でできるかどうかをチェックするために使用される。
:body **
このbounding-boxによって内包される立方体を表現する bodyを返す。
:init vlist &optional tolerance
とmaxpointスロットをvlistから設定する。 もし、torelanceが指定されたなら、このbounding-boxは その量で増大される。
make-bounding-box points &optional tolerance
のリストの中から最小と最大の座標値を見つけ、 bounding-boxのインスタンスを作る。
bounding-box-union boxes &optional (tolerance *contact-threshold*)
の結合で表現されるbounding-boxのインスタンスを作る。 その結果は、toleranceによって拡張される。
bounding-box-intersection boxes &optional (tolerance *contact-threshold*)
の共通領域を表現するbounding-boxのインスタンスを作る。 その結果は、toleranceによって拡張される。
線とエッジ¶
頂点の順番やエッジの順番の向きは、bodyを外から見たときに反時計方向 に整列するように定義される。 pvertexやnvertexやpfaceやnfaceは、 pfaceが外から見たときエッジの左側に位置しているとき、 pvertexからnvertexに向かう方向にエッジを定義する。
line
pvertとnvertの上を通る線分を定義する。 線分は、pvertからnvertに向かう方向を持つ。 t \(\cdot\) pvert +(1-t)nvert
:vertices **
とnvertのリストを返す。
:point p
この線分の上でpパラメータで示される位置の3次元のベクトルを返す。 p \(\cdot\) pvert + (1-p)nvert
:parameter point
この線分の上のpointに対するパラメータを計算する。 これは、:pointメソッドの逆メソッドである。
:direction **
からnvertへ向かう正規化ベクトルを返す。
:end-point v
この線分の他の端点を返す。すなわち、 もしvがpvertに等しいとき、nvertを返す。 もしvがnvertに等しいとき、pvertを返す。 それ以外のとき、NILを返す。
:box **
この線分のbounding-boxを作成し、返す。
:boxtest box
とこの線分のbounding-boxの共通部分をチェックする。
:length **
この線分の長さを返す。
:distance point-or-line
この線分とpoint-or-lineの間の距離を返す。 もし点からこの線分におろした垂線の足が pvertとnvertの間になければ、 最も近い端点までの距離を返す。 このメソッドを使うことにより、2つの線分の間の距離を計算することができるため、 2つの円柱の間の干渉をテストすることができる。
:foot point
からこの線分へおろした垂線の足である点を示すパラメータ を見つける。
:common-perpendicular l
この線分とlとに垂直な線分を見つけ、2つの3次元ベクトルのリスト として返す。 2つの線分が平行で共通な垂線が一意に決定できないとき、:parallelを返す。
:project plane
にpvertとnvertを投影した2つの点のリストを返す。
:collinear-point point &optional (tolerance *coplanar-threshold*)
を用いてtorelanceの誤差範囲内でpointがこの線分と 一直線上にあるかどうかをチェックする。 もし、pointがこの線分と一直線上にあるとき、その線分のその点に 対するパラメータを返す。そうでなければ、NILを返す。
:on-line-point point &optional (tolerance *coplanar-threshold*)
がこの線分と一直線上にあり、pvertとnvertとの間に あるかどうかをチェックする。
:collinear-line ln &optional (tolerance *coplanar-threshold*)
がこの線分と共通線上にあるとき、すなわちlnの両端がこの線分上に あるときTを返し、そうでないときNILを返す。
:coplanar ln &optional (tolerance *coplanar-threshold*)
とこの線分が共通平面上にあるかどうかをチェックする。 この線分の両端とlnの1つの端点で平面が定義される。 もし、lnの他の端点がその平面上にあるとき、Tを返す。 そうでなければ、NILを返す。
:intersection ln
は、この線分と共通平面上にあるとする。 :intersectionは、これら2つの線分の交点に対する2つのパラメータの リストを返す。 パラメータは0から1までの実数である。これは、両端で区切られた 線分の内分点を示す。2つの線が平行であるときNILを返す。
:intersect-line ln
は、この線分と共通平面上にあるとする。 交点のパラメータが:parallel, :collinearや:intersectのような シンボル情報と共に返される。
edge
2つの面の間の交差線分として定義されるエッジを表現する。 pfaceとnfaceがスロットの中に定義されているが、 それらの解釈はこのエッジの方向によって相対的に決まる。 例えば、このエッジがpvertからnvertに向かっていると 考えたとき、pfaceが正しいpfaceを表現している。 そのため、:pfaceや:nfaceメソッドで適当な面を選択するためには、 pvertとnvertの解釈を与えなければならない。
make-line point1 point2
をpvertとし、point2をnvertとする lineのインスタンスを作る。
:pvertex pf
をこのエッジのpfaceとみなしたpvertexを返す。
:nvertex face
をこのエッジのpfaceとみなしたnvertexを返す。
:body **
このエッジを定義するbodyオブジェクトを返す。
:pface pv nv
仮想的にpvとnvをこのエッジの pvertとnvertに解釈したときのpfaceを返す。
:nface pv nv
仮想的にpvとnvをこのエッジの pvertとnvertに解釈したときのnfaceを返す。
:binormal aface
このエッジとafaceの正規化ベクトルに垂直な方向ベクトルを見つける。
:angle **
このエッジでつながった2つの面の間の角度を返す。
:set-angle **
このエッジでつながった2つの面の間の角度を計算し、 それをangleスロットに置く。
:invert **
:set-face pv nv f
をpfaceとし、pvをpvertexとし、nvを nvertexとして設定する。 このメソッドは、このエッジのpfaceあるいはnfaceを変更することに 注意すること。
:contourp viewpoint
もし、このエッジが輪郭エッジであれば、すなわち、このエッジのpface あるいはnfaceのどちらかがviewpointから見え、もう一方が 見えないならTを返す。
:approximated-p **
このエッジが円柱の側面のような曲面を表現するための近似エッジであるならば、 Tを返す。 近似エッジは部分直線で曲線を表現するのに必要である。
:set-approximated-flag &optional (threshold 0.7)
Euslispでは、どんな曲面もたくさんの平面で近似される。 flagsのLSBは、このエッジの両側の面が曲面であるかどうかを 示すために使用される。
もし、2つの面の間の角度がthresholdより大きいなら、 :set-approximated-flagは、このフラグをTに設定する。
:init &key pface nface pvertex nvertex
平面と面¶
planeオブジェクトは、その平面の正規化ベクトルと座標原点から平面までの 距離で表現される。 2対の正規化ベクトルと距離がplaneオブジェクトに記録される。 1つは、変換後の現状を表現し、もう1つが平面を定義したときの 正規化ベクトルと距離を表現する。
plane
平面方程式を定義する。平面は境界がなく、無限に広がっているものとする。
:normal **
この平面の正規化ベクトルを返す。
:distance point
この平面とpointとの間の距離を計算する。
:coplanar-point point
もし、pointがこの平面の上に置かれているならTを返す。
:coplanar-line line
もし、lineがこの平面の上に置かれているなら、Tを返す。
:intersection point1 point2
とpoint2を端点とする線分とこの平面との交点 を計算する。その線分の上の交点に対するパラメータを返す。 もし、線分とこの平面が平行であるなら、:parallelを返す。
:intersection-edge edge
この平面とpoint1とpoint2で表現される線分あるいはエッジとの 交点のパラメータを返す。
:foot point
この平面上にpointを直角に投影した位置の3次元ベクトルを返す。
:init normal point
を通りnormalを面の正規化ベクトルとする平面を定義する。 normalは、正規化されていなければならない。\(|normal|=1\)
polygon
polygonは、平面の上の輪で表現される。 convexpは、その輪が凸面であるかどうかを示す論理フラグである。 edgesは、この輪の輪郭や頂点のリストであるverticesで 形成されるエッジのリストである。
:box &optional tolerance
この多角形のためのbounding-boxを返す。
:boxtest box2 &optional tolerance
この多角形のためのbounding-boxを作成し, そのboundign-boxとbox2との共通領域を返す。 もし,共通領域がなかった場合,NILを返す。
:edges **
この多角形のエッジのリストを返す。 そのリストは,この平面の正規化ベクトルに沿ってその多角形を見たとき, 時計方向の順番になっている。 もし,正規化ベクトルをねじと考えると,そのエッジは ねじを入れる方向に回転させる向きの順番になっている。 多角形または面が立体オブジェクトの面を表現するために使用されているとき, その正規化ベクトルはその立体の外側に向かっている。 多角形をそのオブジェクトの外側から見たとき,エッジは 反時計方向の順番になっている。
:edge n
エッジのn番目の要素を返す。
:vertices **
この多角形の頂点をエッジと同じ順番にならべたものを返す。 最初の頂点は,そのリストの最後に重複してコピーされているため, そのリストは実際の頂点の数より1だけ長くなっていることに注意すること。 これは,頂点のリストを用いてエッジへの変換を簡単にするためである。
:vertex n
頂点のn番目の要素を返す。
:insidep point &optional (tolerance *epsilon*)
この領域に対して相対的に置かれたpointの位置にしたがって :inside,:outsideあるいは:borderを返す。
:intersect-point-vector point vnorm
と正規化方向ベクトルvnormによって定義される 擬似線分との交点を計算する。
:intersect-line p1 p2
とp2で指定される線分との交点を計算する。 その結果は、交点がなければNILを返し,交点があればその交点の位置の パラメータのリストを返す。
:intersect-edge edge
で指定される線分との交点を計算する。 その結果は,交点がなければNILを返し、交点があれば 交点の位置のパラメータのリストを返す。
:intersect-face aregion
もし,この領域がaregionと交差しているなら,Tを返す。
:transform-normal **
:reset-normal **
この多角形の現在のverticesリストから面の正規化ベクトルを再計算する。
:invert **
:area **
この領域の面積を返す。
:init &key vertices edges normal distance
face
穴を持った面を定義する。 mbodyとtypeは、基本bodyとbody内の面の属性(:top, :bottom, :side) を表現する。
:all-edges **
:all-vertices **
この面および内部ループ(穴)の輪郭のエッジあるいは頂点をすべて返す。 :edgesと:verticiesメソッドは, 輪郭を構成するエッジと頂点のみを返す。
:insidep point
がこの面の内部にあるかどうかを決定する。 もしpointがこの面の外側の輪郭の中にあり,どれかの穴の 範囲内にあるならば,外側として分類される。
:area **
この面の面積を返す。 これは,外側のエッジで囲まれる面積から穴の面積を引いたものである。
:centroid &optional point
この面の重心を表現する実数と実数ベクトルのリストを返す。 もし,pointが与えられないならば,最初の数はこの多角形の 面積を表わし,2番目のベクトルがこの多角形の重心の位置を示す。 もし,pointが与えられたならば,この多角形を底面としその点を頂点 とするような多角錐を考え,その体積と重心のベクトルを返す。
:invert **
この面の向きをひっくり返す。 正規化ベクトルが逆方向とされ,エッジループの順番も反転される。
:enter-hole hole
この面に穴holeを加える。
:primitive-body **
この面を定義する基本bodyを返す。
:id **
や(:side seq-no.)の中の1つを返す。
:face-id **
基本bodyの型とこの面の型をリストで返す。 例えば,円柱の側面は ((:cylinder radius height segments) :side id)を返す。
:body-type **
この面を定義する基本bodyを返す。
:init &key normal distance edges vertices holes
hole
穴は,面の内部ループを表現する多角形である。faceのオブジェクトは、 自分のholesスロット の中にholeのリストを持っている。
:face **
このholeを含む面を返す。
:enter-face face
このholeを囲んでいる面faceへリンクを作る。 このメソッドは、faceクラスの:enter-holeメソッドと共に 使用されるものである。
:init &key normal distance edges vertices face
立体(body)¶
body
3次元形状を定義する。
:magnify rate
このbodyのサイズをrateで変更する。拡大は,csgリストの中に 記録される。
:translate-vertices vector
モデルの頂点を相対移動する。vectorはローカル座標系で与えられなければならない。 変換はcsgリストに記録される。
:rotate-vertices angle axis
モデルの頂点をaxis軸回りにangleラジアン回転させる。 回転はcsgリストに記録される。
:reset-model-vertices **
:newcoords rot &optional pos
座標系をrotやposを用いて変更する。 posが省略された時はnewrotにはcoordinatesのインスタンスを与える。
:vertices **
このbodyのすべての頂点のリストを返す。
:edges **
このbodyのすべてのエッジのリストを返す。
:faces **
このbodyを構成するすべての面のリストを返す。
:box **
このbodyのbounding-boxを返す。
:Euler **
このbodyのオイラー数を計算する。これは, faces+vertices\(-\)edges\(-\)2\(-\)holesである。 これは,\(-\)2ringsと等しくなるべきである。
:perimeter **
すべてのエッジの長さの合計を返す。
:volume &optional (reference-point #f(0 0 0))
このbodyの体積を返す。
:centroid &optional (point #f(0 0 0)
このbodyが均質な立体と仮定し,重心の位置を返す。
:possibly-interfering-faces box
:common-box body
このbodyと他のbodyの共通な最小のboxを返す。 もし,2つのbodyが干渉しているならば,その交差部分は この共通boxの中に存在するはずである。
:insidep point
もし,pointがこのbodyに属するなら,:insideを返す。 もし,pointがこのbodyの表面上にある場合,:borderを返す。 そうでなければ,:outsideを返す。
:intersect-face face
もし,このbodyの面とfaceの間に干渉がある場合,Tを返す。
:intersectp body
このbodyと他のbodyとの間の交差部分を返す。
:evert **
すべての面とエッジの方向を反転させる。 そのため,このbodyの内部は外部になる。
:faces-intersect-with-point-vector point direction
からdirectionの方向に伸びるベクトルと交差する面をすべて集める。
:distance target
は,実数ベクトルあるいは平面オブジェクトである。 :distanceメソッドは,targetから最も近い面を見つけ, その面と距離のリストを返す。
:csg **
が構築された履歴であるcsgスロットを返す。
:primitive-body **
このbodyを構築する基本bodyのリストを返す。
:primitive-body-p **
もし,このbodyが[primitive-body-creation] 節で示される関数の内の1つから作られた基本bodyであるなら,Tを返す。
:creation-form **
このbodyを作るためのLisp表現を返す。
:body-type **
もし,このbodyが基本bodyあるいはこのbodyの表現が複雑(に構成された) bodyなら,作成パラメータのリストを返す。
:primitive-groups **
2つの要素をもつリストを返す。 最初の要素は,このbodyを構成するために追加(body+)された基本body のリストである。次の要素は,差し引かれた基本bodyのリストである。
:get-face &optional body face id
は,このbodyを構成しているbodyのインスタンスであり, 基本body型の1つである。例えば,:cube, :prism, :cone, :solid-of-resolutionなどか あるいはNILである。 もし,faceもidも与えられないならば,bodyに一致する面をすべて返す。 もし,faceが与えられたなら,その上にフィルターが実行される。 faceは,:top,:bottomと:sideの内の1つでなければならない。 (send abody :get-face :cylinder :top)は,abodyを構成する円柱の上面すべてを返す。 もし,faceが:sideなら,idで番号付けされた面を取り出すことができる。 (send abody nil :side 2)は,idが0から始まるため,abodyを構成する bodyの側面から3番目の面をすべて返す。
:init &key faces edges vertices
よりこのbodyを初期化する。 :facesは,必要な引き数である。 :faces,:edgesと:verticesは完全な立体モデルを定義するために 矛盾のない関係を持っていなければならないので,矛盾した引き数でこのメソッドを 呼び出すことは,意味の無いことである。 bodyを作るために,[primitive-body-creation]節で書いている基本bodyの作成関数と [BodyComposition]節の**body**合成関数を使用する。
:constraint b
このbodyがbに接触しているとき, このbodyの拘束を返す。このメソッドの詳細な説明は[Contact]節を参照すること。
基本bodyの作成関数¶
make-plane &key normal point distance
を通り,normalの方向を向いたplaneオブジェクトを作る。 pointを与える代わりdistanceを指定することもできる。
*xy-plane* **
*yz-plane* **
*zx-plane* **
make-cube xsize ysize zsize &key name color
x,y,z軸の方向に大きさがxsize,ysize,zsizeである,直方体を作る。 この直方体の原点はbodyの中心に置かれる。
make-prism bottom-points sweep-vector &key name color
に沿ったbottom-pointsにより定義される 形状を積み上げることにより角柱を作る。 もし、sweep-vectorが実数ベクトルでなく数字であれば、\(z\)方向の 角柱の高さとして扱われる。 bottom-pointsは,このbodyの底面を定義する順番になっていなければならない。 例えば, (make-prism ’(#f(1 1 0) #f(1 -1 0) #f(-1 -1 0) #f(-1 1 0)) 2.0) は,高さ2.0の直方体を作る。
make-cylinder radius height &key (segments 12) name color
半径radiusと高さheightで指定される円柱を作る。 底面は,xy-平面に定義され,座標系の原点は底面の中心に置かれる。
make-cone top bottom &key (segments 16) color name
頂点がtopで底面がbottomである角錐を作る。 topは,3次元ベクトルである。 bottomは,底面の頂点のリストあるいは半径である。 もし,頂点のリストなら,順番を慎重にしなさい。 `` (make-cone #f(0 0 10) (list #f(10 0 0) #f(0 10 0) #f(-10 0 0) #f(0 -10 0)))`` は,正方形の底面を持つ四角錐を作る。
make-solid-of-revolution points &key (segments 16) name color
は,z軸まわりの時計方向に回転される。 もし、pointsのリストの2つの端点がz軸上に置かれてないならば, 曲面を作る。したがって, (make-solid-of-revolution ’(#f(0 0 1) #f(1 0 0))) は、円錐を作り、 (make-solid-of-revolution ’(#f(1 0 1) #f(1 0 0))) は、円柱を作る。 pointsは、順番が重要であり、\(z\)軸の高い方から低い方へ 整列しておくことが望まれる。
make-torus points &key (segments 16) name color
ドーナッツのようなtorus形状を作る。 pointsは,断面上の頂点のリストである。
make-icosahedron &optional (radius 1.0)
正20面体を作る。それぞれの面は正三角形である。
make-dodecahedron &optional (radius 1.0)
正12面体を作る。それぞれの面は,正五角形である。
make-gdome abody
の三角面を4つの面に小分けすることにより 測地ドームを新しく作る。 abodyは,最初正20面体とすべきである。 それから,make-gdomeの結果を再帰的にmake-gdomeに与えることができる。 それぞれの呼び出しで,測地ドームの面の数は,4倍に増加する。すなわち, 20, 80, 320, 1280, 5120などになる。
(setq g0 (make-icosahedron 1.0)) ; 20 facets (setq g1 (make-gdome g0)) ; 80 facets (setq g2 (make-gdome g1)) ; 320 facets ...
grahamhull vertices &optional (normal #f(0 0 1))
Grahamのアルゴリズムを用いて,2次元上で凸状の覆いを計算する。 quickhullよりも遅い。
quickhull vertices &optional (normal #f(0 0 1))
2分探索法を用いて2次元上で凸状の覆いを計算する。
convex-hull-3d vertices
gift-wrapping法を用いて3次元上で凸面の覆いを計算する。
make-body-from-vertices vertices-list
矛盾しない順番になっている面のループを定義する頂点のリストからbodyを返す。
bodyの合成関数¶
face+ face1 face2
face* face1 face2
とface2は,3次元上で共通平面上にある。 face+は,これらの面の結合を構築し,面のオブジェクトとして返す。 もし,交差領域がないなら,元の2つの面が返される。 face*は,これらの面の交差領域を返す。もし,交差領域がなければ,NILを返す。
cut-body body cutting-plane
をcutting-planeで切断し,その切断面に作られる面のリストを返す。
body+ body1 body2 &rest more-bodies
body- body1 body2
body* body1 body2
2つあるいはそれ以上のbodyの和,差あるいは積を計算する。 それぞれのbodyは,body+, body-, body*の処理を行う前に コピーされ,元のbodyは変更されない。 その結果のbodyの新しい座標系の位置・姿勢は,ワールド座標系のものと一致している。 もし,しきい値パラメータcoplanar-threshold*,contact-threshold*,parallel-threshold* を正確に設定するなら,2つのbodyが面同士で接触している場合でも これらの関数は正しく働くであろう。 しかしながら,もしbodyの頂点が他のbodyの頂点あるいは面に接触している場合, どの処理も失敗する。
body/ body plane
で作られたplaneクラスのインスタンスであるplaneで bodyを切断する。新しく作られたbodyが返される。
body-interference &rest bodies
の中で1対1の組み合わせにおける干渉をチェックし, 交差している2つのbodyのリストを返す。
座標軸¶
coordinates-axesクラスは,画面上に表示可能な3次元座標軸を定義する。 それぞれの軸とz軸の頂点の矢印は,lineオブジェクトで定義される。 このクラスは,cascaded-coordsを継承しているので, このクラスのオブジェクトは,bodyのような他のcascaded-coordsを元とする オブジェクトに付けることができる。 このオブジェクトは,bodyの座標軸あるいは他の座標の相対座標系を見るために 使用される。
coordinates-axes
表示可能な3次元座標軸を定義する。
立体の接触状態解析¶
この節のメソッドおよび関数は、次のファイルに記述されている。 contact/model2const.l, contact/inequalities.l, contact/drawconst.l
constrained-motion c
拘束cを満たしている 動作のリストを返す。
constrained-force m
拘束されているbodyから 拘束しているbodyに加わる力を返す。mは、constrained-motion から返される動作のリストである。
draw-constraint c
拘束cを描く。
draw-motion m a b
がbに接触しているときに 取り得る動作を描く。リターンキーを押すことにより描画を始める。
;;
;; peg in a hole with 6 contact points
;;
(in-package "GEOMETRY")
(load "view")
(load "../model2const.l" :package "GEOMETRY")
(load "../inequalities.l" :package "GEOMETRY")
(load "../drawconst.l" :package "GEOMETRY")
(setq x (make-prism '(#f(50 50 0) #f(50 -50 0) #f(-50 -50 0) #f(-50 50 0))
#f(0 0 200)))
(setq x1 (copy-object x))
(send x1 :translate #f(0 0 -100))
(send x1 :worldcoords)
(setq a1 (make-prism '(#f(100 100 -150) #f(100 -100 -150)
#f(-100 -100 -150) #f(-100 100 -150))
#f(0 0 150)))
(setq ana (body- a1 x1))
(send x :translate #f(0 -18.30127 -18.30127))
(send x :rotate -0.523599 :x)
(send x :worldcoords)
(setq c (list (send x :constraint ana)))
(setq m (constrained-motion c))
(setq f (constrained-force m))
(hidd x ana)
(draw-constraint c)
(draw-motion m)
ペグを穴に入れる作業において取り得る動作の例を次の図で示す。 この例は,上記のプログラムと一致している。
多角形のVoronoi Diagram¶
このプログラムは,Common Lispで書かれている。 “A sweepline algorithm for Voronoi diagrams”, Proceedings of the 2nd Annual ACM symposium on computational geometry, 1986, 313-322.を 手法として用い、 多角形の場合への応用を行った。これは,サンプルプログラム付きの簡単な説明である。 このプログラムは,ETLのEuslisp環境で書かれているため, 画像への出力もサポートしている。 どのCommon Lisp上でも使用することはできるが, utilities.lで与えられている画像への関数を自分のディスプレイ環境へ 合うように書き換える必要がある。この節の最後にその関数を示す。
- 目的:
- 多角形の集合のvoronoi diagramの計算を行う。 語彙を理解するために上記の文献を読んで、使用してください。 ここでは、このプログラムに対する説明をしません。
- 入力:
多角形のリストと囲むための枠は,次のように定義する。
DATA= ( (x11 y11 x12 y12 x13 y13 ...) first polygon, counterclocwise enumeration of vertices (x21 y21 x22 y22 x23 y23 ...) second polygon ... (xn1 yn1 xn2 yn2 xn3 yn3 ...) nth polygon (xf1 yf1 xf2 yf2 xf3 yf3 xf4 yf4) enclosing frame )
囲む枠は,DATA内のどの位置にも配置することができる。また, 内部と外部が矛盾しないように時計方向の順番でなければならない。 多角形は交差の無い簡単な図形でなければならない。 一直線あるいは平坦なエッジは受け付けない。 独立した点あるいは線分も受け付けない。
- 出力:
diagram*:2重に接続されたエッジリストのリスト (utilities.lファイルを参照)を返す。それぞれのエッジは,symbolであり,次に示す ようなfieldを含むproperty-listを持っている。
(start <pointer to a vertex>) (end <pointer to a vertex>) (pred <pointer to an edge>) (succ <pointer to an edge>) (left <pointer to a site>) (right <pointer to a site>) (type <:endpoint or :point-point or :segment-segment or :point-segment>) (outflag <t or nil>)
vertexは,symbolで“pos”fieldを含むproperty-listを持つ。 このfieldは,cons(x,y)を含み,vertexの平面座標を示す。 predとsuccのfieldは,decl形式にしたがって反時計方向の 前者と後者を与える(ShamosとPreparataの, Computational Geometry: An introduction, 1985, pp 15-17を参照)。 siteもsymbolであり,関連した情報を含むproperty-listを持つ。 siteは,元の入力データを記述しており,多角形の頂点であるpoint あるいは多角形のエッジであるsegmentを持つ。
typeは,2等分線の中点であり,それを分割するsiteの型より 決定される。 規約により,外側はstart-endエッジの右側である。 voronoi diagramは,2等分線の内部と同様に外側を計算する。 必要とするoutflagを保つためにoutflagをソートする。
- サンプル:
サンプルプログラムを実行するためには,以下のようなステップを実施してください。
- 自分の環境に以下のプログラムをコピーする。
utilities.l 幾何学ユーティリティ関数とeusxの画像出力関数 polygonalvoronoi.l プログラム本体 testdata.l 上記の書式によるデモデータ もし,Euslispを使用しないなら,命令にしたがってutilities.lを書き換え, “compatibility package”を修正する。。
- 以下の3つのファイルをコンパイルしてロードするか、あるいはそのままロードする。
utilities.l polygonalvoronoi.l testdata.l 上記の書式によるデモデータを含んでいる。 (pv demoworld)でデモデータ上でプログラムが実行される。 グローバル変数diagram*には,voronoi diagramの2等分線が含まれている。
eusx(Xwindowインターフェースを持つEuslisp)のもとでは,以下の命令でdiagramの結果を画面上に表示することができる。
(make-display) ;;Initializes the *display* window object
(dps demoworld *thick*) ;; Shows original data in thick lines
(dbs *diagram*) ;; Shows the result
pv data
上記の書式で書かれたdataから多角形のvoronoi diagramを計算する。
視界とグラフィックス¶
視界(viewing)¶
viewingオブジェクトは、viewing座標系を処理する。 この座標系の原点は仮想カメラの位置に置かれる。 -z軸方向がオブジェクトの視線方向で、xy平面が投影画面である。 viewingがcascaded-coordsクラスを継承するので、 :translateや:rotateや:transformのような 座標変換メッセージを受け付ける。 また、cascaded-coordsから得られる他のオブジェクトを張り付けることができる。 したがって、移動物体上のカメラシステムのシミュレーションができる。 viewingの主な目的は、ワールド座標系で表現されるベクトルを カメラ座標系に変換することである。 変換は、一般の座標変換に対して逆方向で与えられる。 このローカル座標系内のベクトルはワールド座標系における表現に変換される。 したがって、viewingはviewcoordsスロットに逆変換された左手系変換を持つ。 このスロットは、viewing座標系として普通参照される。
viewing
viewing変換を定義する。
:viewpoint **
このviewingの原点のベクトル位置を返す。
:view-direction **
の原点から画面の中心までのベクトルを返す。 これは、viewing座標系のz軸方向である。
:view-up **
ワールド座標系におけるこのviewingのy軸ベクトルを返す。 y軸は、viewportの上方である。
:view-right **
ワールド座標系におけるこのviewingのx軸ベクトルを返す。 x軸は、viewportの水平右方向である。
:look from &optional (to #f(0 0 0))
は、その目がfromに位置されており、toの位置を 見ているとしてviewing座標系を設定する。
viewingは、cascaded-coordsを継承するので、:posや:rotや:euler や:rpyなどの:initのパラメータはすべてviewing座標系の位置や姿勢を 指定することに使用できる。 しかしながら、viewingの:initは回転を決定する簡単な方法を持っている。 もし、:targetだけが与えられたとき、視線方向は視点からtarget位置 の方向に決定され、:view-rightベクトルはワールド座標系のxy平面に平行な x軸に決定される。 :view-directionを:targetの代わりに指定しても同じ様な 効果を得られる。 もし、:view-upまたは:view-rightパラメータを:targetあるいは :view-directionに加えて指定するならば、3つの回転パラメータをすべて 自分自身で決定することができる。
投影¶
parallel-projectionとperspective-projectionクラスは、 投影変換を処理する。この変換は4X4の行列で表現される。すなわち、変換は 3次元の同次座標系で与えられる。 projectionクラスは、両方のクラスの抽象クラスである。 これらの投影クラスは、viewingクラスを継承しているので、 2つの座標変換(ワールド座標からviewing座標系への変換と投影変換)を 同時に実行することができる。 3Dベクトルと:project3メッセージを投影オブジェクトに送ることにより、 4要素の実数ベクトル返す。 homo2normal関数は、この同次ベクトルを標準のベクトル表現に変換 するために使用される。 その結果は、標準デバイス座標系(NDC)と呼ばれる座標系上に表現される ベクトルである。 その中で、見えるベクトルはそれぞれのx,y,z次元において-1から1までの 範囲で表される。 ロボット世界の本当のカメラをシミュレートするために、 perspective-projectionはparallel-projectionよりも多く使用される。 perspective-projectionは、定義されているパラメータが少し多い。 screenxとscreenyは、見える物体が投影されるviewing平面の上のwindowの大きさで、 大きな画面と広い空間が投影される。 viewdistanceは、視点とview平面との距離を定義しているが、 視角にも関係する。 viewdistanceを大きくすると、view平面のwindowに狭い範囲が投影される。 hitherとyonパラメータは、クリップする平面の前面と後面の距離を 定義する。 これら2つの平面の外側に位置するオブジェクトは、クリップから除外される。 実際に、このクリップ処理はviewportオブジェクトによって実現されている。
projection
4x4行列であらわされる投影変換を定義する。
:projection &optional pmat
もし、pmatが与えられたならば、 projection-matrixのスロットに設定する。 :projectionは、現在の4x4投影行列を返す。
:project vec
は、4要素を持つ3次元同次ベクトルである。 vecは、投影行列により変換される。 そして、変換された結果である同次表現が返される。
:project3 vec
は、標準の3Dベクトル。 vecは、投影行列により同次化され変換される。 そして、変換された結果である同次表現が返される。
:view vec
にviewing変換と投影変換を連続的に適用する。 そして、変換された結果である同次表現が返される。
:screen xsize (&optional (ysize xsize))
viewing画面の大きさを変える。 大きくすると、広いviewが得られる。
:hither depth-to-front-clip-plane
視点からクリップ前面までの距離を決定する。 このクリップ前面よりも前にあるオブジェクトはクリップから除外される。
:yon depth-to-back-clip-plane
視点からクリップ後面までの距離を変える。 このクリップ後面よりも後ろにあるオブジェクトはクリップから除外される。
:aspect &optional ratio
アスペクト比は、screen-yとscreen-xとの比である。 もし、ratioが与えられたならば、 アスペクト比は変えられ、screen-yはscreen-x * ratioに設定される。 :aspectは、現在のアスペクト比を返す。
viewingとprojectionを初期化する。
parallel-viewing
平行投影を定義する。 hid(陰線消去関数)は平行投影では扱うことが出来ない。
:make-projection **
perspective-viewing
透視投影変換を定義する。
:make-projection **
:ray u v
視点から正規化画面の上にある(u,v)への単位方向ベクトルを返す。
:viewdistance &optional vd
は、視点から画面迄の距離である。 もし、vdが与えられたならば、viewdistanceに設定される。 viewdistanceは、カメラの焦点距離と一致する。 vdを大きくすれば、ズームアップされたviewを得ることができる。 :viewdistanceは、現在のviewdistanceを返す。
:view-angle &optional ang
画面の対角線を見込む角度がangラジアンであるように画面の大きさを設定する。 20度(約0.4ラジアン)から50度(約0.9ラジアン)までの角度が自然な透視view を生成することができる。 角度を大きくすると歪んだviewを生成する。 そして、狭くすると直角(平行)viewingのような平坦なviewが生成される。 :view-angleは、現在の視角あるいは新しい視角をラジアンで返す。
:zoom &optional scale
もし、scaleが与えられたならば、画面はscaleによって 現在の大きさを相対的に変化させる(viewdistanceは変化しない)。 もし、scaleに0.5を与えるならば、以前のviewより2倍広いviewを得られる。 :zoomは、新しい視角をラジアンで返す。
:lookaround alfa beta
視点を移動し回転させる。 回転中心は、視線の上でhither平面とyon平面の中間点 に与えられる。 viewing座標系は、ワールド座標系のz軸回りにalfaラジアン回転し、 ローカル座標系のx軸回りにbetaラジアン回転される。 :lookaroundは、viewingの中心にあるオブジェクト回りに視線を 動かすことができる。
:look-body bodies
視線、画面の大きさおよびhither/yonをすべてのbodiesに適合するviewport となるよう変える。視点は変化しない。 視線は、すべてのbodiesのbounding boxの中心を通る視線から選択される。
:init &key (viewdistance 100.0) &allow-other-keys
Viewport¶
viewportクラスは、正規デバイス座標系(NDC)の中の3次元viewportのクリップ を実行する。そして、デバイスに依存する座標系に結果を作る。 viewportは、画面上の見える四角領域の境界表現である。 viewportの物理的な大きさ(x軸とy軸方向のドット数)は、 :initメッセージの中の:widthと:heightとの引き数 で与えられなければならない。 :xcenterと:ycenter引き数は、viewportの物理的な位置を決定する。 画面の原点からのそれぞれの次元が絶対的に与えられているテクトロニクス4014 のような基本的なディスプレイデバイスを使っているとき、これら2つのパラメータは、実際に画面の上にオブジェクトを描く位置を決定する。 もし、位置が親windowから相対的に決まるXwindowのような精巧なディスプレイ デバイスを使っているなら、 viewportを動かすためにviewportのパラメータを変える必要はない。 なぜなら、これらのパラメータは、実際のディスプレイ位置に依存しないからである。。
viewportクラスは、四角領域の左下をviewportの原点と仮定している。 そして、y軸は上方向に伸びているとする。 しかし、多くのwindowシステムやディスプレイデバイスでは原点を左上とし、 y軸が下方向に伸びているとしている。 この問題を回避するために、:heightパラメータに負の値を与えればよい。
homo-viewport-clip v1 v2
とv2は、4要素を持つ同次ベクトルであって、 3次元空間の線分として表現される。 その線分は、\(x=-1, x=1, y=-1, y=1, z=0, z=1\)の境界でクリップされる。 そして、2つのベクトルのリストを返す。 もし、その線分がviewportの外側に完全に置かれているならば、 NILを返す。
viewport
viewport変換は、デバイスで指定される座標系にNDC(正規化デバイス座標系)を作る。 coordinatesクラスを継承しているため、viewportはサイズと投影画面の 相対位置を定義している。
:xcenter &optional xcenter
このviewportのx軸の中心を返す。 もし、xcenterが与えられていれば、設定を行う。
:ycenter &optional ycenter
このviewportのy軸の中心を返す。
:size &optional size
このviewportのx軸とy軸方向の大きさのリストを返す。
:width &optional width
このviewportの幅をwidthに設定する。
:height &optional height
このviewportの高さをheightに設定する。
:screen-point-to-ndc p
は、物理的画面の中の位置を表現する実数ベクトルである。 pは、正規化デバイス座標系(NDC)の中での表現に変換される。
:ndc-point-to-screen p
このviewportのNDC表現であるpを画面の物理的位置に変換する。
:ndc-line-to-screen p1 p2 &optional (do-clip t)
2つの3次元ベクトルp1とp2は、NDCの中の線分を定義する。 これらの2つの端点は、画面空間の表現に変換される。 もし、do-clipがnon-NILなら、その線分はクリップされる。
:init &key (xcenter 100) (ycenter 100) (size 100) (width 100) (height 100)
新しいviewportオブジェクトを作る。
Viewer¶
画面の上に描画するためには、4つのオブジェクトが必要である。 1つは描かれたオブジェクト、2つはviewing座標系と投影で定義されるviewing、 3つはNDCの中でのクリップ処理のためのviewportとNDCから物理的画面座標系への 変換、4つは 物理的ディスプレイデバイスの上に描画関数を実行するviewsurface。 viewerオブジェクトは、viewingとviewportとviewsurface オブジェクトを持ち、 座標系変換を連続的に制御する。 [Drawings]節に記述される**draw**とhid関数はviewerの インスタンスを使用する。
viewer
viewingからviewportを経由してviewsurfaceへ移るCascaded Coordinatesの変換を定義する。
:viewing &rest msg
もし、msgが与えられたならば、msgはviewing(eye)オブジェクト に送られる。そうでなければ、viewing(eye)オブジェクトが返される。
:viewport &rest msg
もし、msgが与えられたならば、msgはviewport(port)オブジェクト に送られる。そうでなければ、viewport(port)オブジェクトが返される。
:viewsurface &rest msg
もし、msgが与えられたならば、msgはviewsurface(surface)オブジェクト に送られる。そうでなければ、viewsurface(surface)オブジェクトが返される。
:adjust-viewport **
の大きさが変えられたとき、:adjust-viewportは portに固有のメッセージを送ることによりviewportの変換を変える。
:resize width height
に:resizeメッセージを送り、viewportに:sizeメッセージを送る ことによりviewsurfaceの大きさを変える。
:draw-line-ndc p1 p2 &optional (do-clip t)
NDCの中に定義される2つの端点p1,p2を結ぶ線を描く。
:draw-polyline-ndc polylines &optional color
NDCの中に定義される端点を結ぶ多角形を描く。
:draw-star-ndc center &optional (size 0.01) color
NDCの中に十字マークを描く。
:draw-box-ndc low-left up-right &optional color
NDCの中に四角形を描く。
:draw-arc-ndc point width height angle1 angle2 &optional color
NDCの中に円弧を描く。 このviewerに結び付くviewsurfaceオブジェクトは、:arcメッセージを 受けなければならない。
:draw-fill-arc-ndc point width height angle1 angle2 &optional color
NDCの中に塗り潰し円弧を描く。
:draw-string-ndc position string &optional color
NDCの中に定義されるpositionにstringを描く。
:draw-image-string-ndc position string &optional color
:draw-rectangle-ndc position width height &optional color
:draw-fill-rectangle-ndc point width height &optional color
:draw-line p1 p2 &optional (do-clip t)
ワールド座標系に定義される2つの端点p1,p2を結ぶ線を描く。
:draw-star position &optional (size 0.01) color
ワールド座標系のposition位置に十字マークを描く。
:draw-polyline vlist &optional color
ワールド座標系のvlist端点を結ぶ多角形を描く。
:draw-box center &optional (size 0.01)
ワールド座標系のcenterに四角形を描く。
:draw-arrow p1 p2
からp2へ向けての矢印を描く。
:draw-edge edge
:draw-edge-image edge-image
:draw-faces face-list &optional (normal-clip nil)
:draw-body body &optional (normal-clip nil)
:draw-axis coordinates &optional size
で定義される軸をsizeの長さで描く。
:draw &rest things
3次元の幾何学オブジェクトを描く。 もし、オブジェクトが3次元ベクトルならば、その位置に小さな十字マークを描く。 もし、3次元ベクトルのリストであれば、多角形を描く。 もし、thingが:drawメッセージを受けたならば、 このviewerを引き数としてそのメソッドが呼び出される。 もし、オブジェクトが:drawnersメソッドを定義しているならば、 :drawメッセージは:drawnersの結果に送られる。 line, edge, polygon, faceおよびbodyオブジェクトは、 viewerに定義されている:draw-xxx(xxxにそのオブジェクトのクラス名が入る) メソッドによって描かれる。
:erase &rest things
背景色でthingsを描く。
:init &key viewing viewport viewsurface
およびviewsurfaceをこのviewerのスロット eye, portとsurfaceに設定する。
新しいviewerを作り、viewer*リストに置く。
描画¶
draw &optional viewer &rest thing
にthingを描く。 thingは、座標系、立体、面、エッジ、ベクトル、2つのベクトルのリストのどれでも可能である。 (progn (view) (draw (make-cube 10 20 30))) は、xwindowに立方体を描く。
draw-axis &optional viewer size &rest thing
の中にthingの座標系の軸をsizeの長さで描く。 thingは、座標系から得られるどのオブジェクトでも可能である。
draw-arrow p1 p2
にp1からp2に向かう矢印を描く。
hid &optional viewer &rest thing
に陰線処理された画像を描く。 thingは、faceまたはbodyが可能である。
hidd &optional viewer &rest thing
陰線を点線で描くことを除いて、hidと同じである。
hid2 body-list viewing
edge-imageオブジェクトで表現される陰線処理画像を生成する。 その結果はhid*に置かれる。
render &key bodies faces (viewer *viewer*) (lights *light-sources*) (colormap *render-colormap*) (y 1.0)
とfacesにレイトレーシングを行い、陰面消去した画像を生成する。 viewing, viewportおよびviewsurfaceは、viewerから得られる。 lightsは、light-source(光源)オブジェクトのリストである。 colormapは、Xwindowのcolormapオブジェクトである。 それぞれのbodiesとfacesは、割り当てられるカラー属性を 持たなければならない。 colormapに定義されているカラーLUTの名前を:colorメッセージで 送ることによりカラー属性を設定できる。 一般にこの関数は、Xlib環境下でのみ働く。 demo/renderdemo.lのサンプルプログラムを見ること。
make-light-source pos &optional (intensity 1.0)
の位置に光源オブジェクトを作る。 intensityは、デフォルトの光の強さを増す拡大比である。 もっと正確に強さを決定するためには、光源の:intensityメソッドを 使用する。
tektro file &rest forms
ストリームのためにfileをオープンし、 formsを評価する。 これは、tektro描画の出力を直接fileに書き込むために使用される。
kdraw file &rest forms
は、kdrawまたはidrawで読み込めるポストスクリプトファイルを 生成するためのマクロ命令である。 kdrawは、:outputモードでfileをオープンし、 viewer*を置き換えるためのkdraw-viewsurfaceとviewportを 作り、formsを評価する。 それぞれのformsは、drawやhidのような描画関数の どれかを呼び出す。 これらのformsからの描画メッセージは、kdraw-viewsurfaceに 直接出力される。この出力はidrawやkdrawで認識できる ポストスクリプト表現にメッセージを変換する。 そして、fileに蓄積する。 idrawまたはkdrawが呼び出されfileがオープンされたとき、 EusViewer windowに書いたものと同一の図形を見ることができる。 その図形は、idrawの機能で変更することができる。 そして、最終描画はepsfile環境を用いることによりLaTeXドキュメント に組み込むことができる。 この機能は、“llib/kdraw.l”のファイルに記述されている。
pictdraw file &rest forms
は、MacintoshのPICTフォーマットで画像ファイルを 生成するためのマクロである。 pictdrawは、fileを:outputモードでオープンし、 pictdraw-viewsurfaceを作り、viewer*のviewportに置き換え、 formsを評価する。 formsは、それぞれdrawあるいはhidのような描画関数のどれかを 呼び出すものである。 これらの書式からの描画メッセージは、kdraw-viewsurfaceに 直接出力された後、PICTフォーマットへのメッセージに変換され, fileへ蓄積される。 このPICTフォーマットは、Macintoshのmacdrawやteachtextで 認識することができる。
hls2rgb hue lightness saturation &optional (range 255)
HLS(Hue, Lightness, Saturation)で表現される色を、RGB表現に変換する。 HLSは、しばしばHSLとして参照される。 hueは、rainbow circle(0から360)の色で表現される。 0が赤で45が黄で120が緑で240が青で270が紫そして360が再び赤となる。 lightnessは、0.0から0.1の値を持ち、黒から白までの明るさを表現する。 lightnessが0のときは、hueやsaturationにかかわらず 黒となる。そして、lightnessが1のときは、白となる。 saturationは、0.0から1.0までの値を持ち、色の強さを表現する。 saturationの値が大きいと鮮明な色調を生成し、小さい値は弱く濁った色調 を生成する。 rangeは、RGB値の限界を示す。 もし、それぞれの色に8ビットの値が割り当てられているカラーディスプレイ を使っているならば、rangeは255とすべきである。 もし、RGBに16ビットの整数が仮想的に割り当てられているXwindowを使って いるならば、rangeは65536とすべきである。 HSVとHLSとの違いに注意すること。 HLSでは、鮮明な(rainbow)色はlightness=0.5で定義されている。
rgb2hls red green blue &optional (range 255)
RGBの色表現を、HLS表現に変換する。
アニメーション¶
EusLispのアニメーションは、グラフィックアクセラレータを持たない 普通のワークステーション上での擬似リアルタイムグラフィックス機能を備えている。 その基本的な考え方は、長い時間かかって生成された1連の画像を高速に 再表示することである。 画像は2つの方法で保存される。 1つは、完全なピクセル画像を持つたくさんのXwindow pixmapを保存する。 もう1つは、陰線処理で得られる線分データを保存する。 前者は、高速で陰面処理された画像を表示するための方法であるが、 長いアニメーションではたくさんのメモリーをX serverに要求するため 適さない。 後者は、メモリーが少なくて済み、データをディスクに蓄積するのに適する。 しかし、線分の数が増加したならば、性能を悪化させる。
他の方法として、描かれるオブジェクトの構成を得て、 viewer*に描画を生成する関数をユーザーが作ることもできる。 pixmap-animationは、count引数で指定された数と同じ回数この関数を呼び出す。 それぞれの呼び出し後、Xwindowと仮定されるviewsurfaceの内容は、 新しく作られたXwindow pixmapにコピーされる。 これらのpixmapは、playback-pixmapで再表示される。 同様に、hid-lines-animationはhidの結果から見える線分を抜き出し、 リストに蓄積する。 そのリストは、playback-hid-linesによって再表示される。
以下に示す関数は、“llib/animation.l”に定義されており、 “llib/animdemo.l”の中にはETA3 マニピュレータのモデルに関して hid-lines-animationを用いたアニメーションの サンプルプログラムを含んでいる。
pixmap-animation count &rest forms
は、count回評価される。 それぞれの評価後、viewsurface*の内容は新しいpixmapにコピーされる。 count枚のpixmapのリストが、返される。
playback-pixmaps pixmaps &optional (surf *viewsurface*)
リストのなかのpixmapはそれぞれ、 surfに連続的にコピーされる。
hid-lines-animation count &rest forms
への呼び出しを含むformsがcount回評価される。 それぞれの評価後、hid*が持つhidの結果は検索され、 見える線分は2点一組のリストの形で集められる。 count長さのリストが返される。
playback-hid-lines lines &optional (view *viewer*)
は、2点一組のリストである。 viewの上に線分を連続的に描く。 他のpixmapを割り当てるときにフリッカーフリーアニメーションを生成するために 2重バッファ技法が使用される。
list-visible-segments hid-result
のedge画像のリストから見える線分を集める。
Xwindow インターフェース¶
Euslisp上のXwindowインターフェースは、’eusx’という 名前でEuslispが呼び出されたとき、実行可能となる。 [1] eusxは、起動時に環境変数“DISPLAY”を参照してXserverに接続を試みるため、 自分のXseverに環境変数“DISPLAY”が正しく設定されていなければならない。
Euslispには、次の3つのレベルのXwindowインターフェースが定義されている。 (1) Xlib関数, (2) Xlibクラスと(3) XToolKitクラスである。 この節と次のXToolKitの節に記述されている 全てのXwindow関数は、“X”パッケージの中に含まれている。 それらの関数名は、元のXlib関数名から最初の“X”を省いき、全ての文字を大文字に 変更したものとなっている。 例えばXdefaultGCはX:DEFAULTGCと名付けられていて、 X:XDEFAULTGCではない。
Xlib関数は、Xwindowシステムへの低レベルインターフェースで、 foreign関数として定義されている。 これらのXlib関数は、パラメータの型チェックあるいは パラメータの数のチェックを実行していないため、 十分注意して使用しなければならない。 例えば、すべてのXlibの呼び出しにおいてXserverとの接続を確認するために x:*display*を引き数として要求する。もし、指定し忘れたならば、Xlibは エラーを通知し、そのプロセスは死ぬ。 このような不便を避け、オブジェクト指向のインターフェースを作るために、 2番めのレベルのインターフェースであるXlibクラスが備わっている。 この節では、この2番めのレベルのインターフェースに焦点を当てる。 XToolKitと呼ばれるもっと高レベルのXwindowライブラリは、次節で 説明されている。
この節に記述されているクラスは、以下の継承の階層を持っている。
propertied-object viewsurface x:xobject x:gcontext x:xdrawable x:xpixmap x:xwindow colormap
Xlibのグローバル変数とその他関数¶
x:*display* **
Xのdisplay ID(整数)。
x:*root* **
デフォルトのroot windowオブジェクト。
x:*screen* **
デフォルトのscreen ID(整数)。
x:*visual* **
デフォルトのvisual ID(整数)。
x:*blackpixel* **
黒色のpixel値 = 1
x:*whitepixel* **
白色のpixel値 = 0
x:*fg-pixel* **
window作成時に参照されるデフォルトの文字色のpixel値、ふつうblackpixel*。
x:*bg-pixel* **
window作成時に参照される背景色のpixel値、ふつうwhitepixel。
x:*color-map* **
システムのデフォルトカラーマップ。
x:*defaultGC* **
pixmap生成時に参照されるデフォルトgcontext。
x:*whitegc* **
文字色が白色のgcontext。
x:*blackgc* **
文字色が黒色のgcontext。
*gray-pixmap* **
の結果。
*gray25-pixmap* **
1/4のピクセルがfg-pixel*であり、3/4がbg-pixel*である16x16のpixmap。
*gray50-pixmap* **
1/2のピクセルがfg-pixel*である16x16のpixmap。
*gray75-pixmap* **
3/4のピクセルが黒色である16x16のpixmap。
*gray25-gc* **
から作る25%のグレーGC。
*gray50-gc* **
から作る50%のグレーGC。
*gray75-gc* **
から作る75%のグレーGC。
*gray* **
*bisque1* **
*bisque2* **
*bisque3* **
*lightblue2* **
*lightpink1* **
*maroon* **
*max-intensity* **
65535
font-cour8 **
font-cour10 **
font-cour12 **
font-cour14 **
font-cour18 **
font-courb12 **
font-courb14 **
font-courb18 **
font-helvetica-12 **
font-lucidasans-bold-12 **
font-lucidasans-bold-14 **
font-helvetica-bold-12 **
font-a14 **
x:*xwindows* **
Euslispによる子windowを含んだ全てのwindowのリストを保持する。
x:*xwindow-hash-tab* **
drawable IDからxwindowオブジェクトを探すためのハッシュテーブル。 x:nexteventで得られるイベント構造はwindow IDであるため、 x:window-main-loopはこのテーブルを使用して一致するxwindowオブジェクト を知るためにx:event-windowを呼び出す。
xflush **
Xlibのコマンドバッファに保有するコマンドをすべてXserverに送る。 XlibバッファがXserverに出力するため、 Xserverに発行されたコマンドは、すぐに実行されない。 これは、ネットワークの渋滞およびプロセスの切替え頻度を減少させるために 必要である。 コマンドの効果を見るためにコマンドバッファを掃き出す方法として、 xflushを使用するかあるいは:flushメッセージをxwindowオブジェクトに 送る。
find-xwindow subname
*xwindows*の中から、名前にsubnameを含むもののリストを還す。
Xwindow¶
Xobject
すべてのXwindowに関連するクラスの共通のスーパークラスである。 現在、スロットもメソッドも定義されていない。
Xdrawable
Xdrawableは、線分や文字列のようなグラフィックオブジェクト を描くための四角領域を定義する。 Xdrawableは、xwindowやxpixmapのための共通メソッド を定義するための抽象クラスであり、 このクラスのインスタンスは何の効果も持っていない。
:init id
は、このdrawableのIDとしてdrawableスロットに設定される。 新しいGC(graphic context)が生成され、このdrawableオブジェクトの デフォルトGCとしてgconに設定される。
:drawable **
drawable IDを返す。
:flush **
Xlibのバッファに保有されるコマンドを掃き出す。
:geometry **
7つの幾何学属性のリストを返す。 そのリストは、root-window-id, x座標, y座標, 幅, 高さ, 枠線の幅, visualの深さである。
:height **
このXdrawableの高さ(y軸方向のドット数)を返す。
:width **
このXdrawableの幅(x軸方向のドット数)を返す。
:gc &rest newgc
もし、newgcが与えられない場合、現在のGCオブジェクトを返す。 もし、newgcがgcontextのインスタンスなら、 このXdrawableのgcに設定する。 そうでなければ、newgcはメッセージとみなされ、 現在のgcに送られる。
:pos **
このXdrawableの位置を示す整数ベクトルを返す。 位置は親windowの相対位置としていつも定義され、 windowマネージャの仲介のもとにルートwindowの直接の子windowとして 生成されたwindowは、ルートwindowの本当の位置に関わらず、環境の タイトルwindowの固定座標を返す。
:x **
このXdrawableの親windowとの相対的な現在のx座標を返す。
:y **
このXdrawableの親windowとの相対的な現在のy座標を返す。
:copy-from drw
は、他のdrawableオブジェクト(Xwindowまたはpixmap)である。 drwの内容がこのXdrawableにコピーされる。
:point x y &optional (gc gccon)
\((x, y)\)の位置にオプションのgcで点を描く。
:line x1 y1 x2 y2 &optional (gc gcon)
から(x2,y2)へオプションのgcを用いて 線分を描く。x1, y1, x2, y2は整数でなければならない。
:rectangle x y width height &optional (gc gcon)
を中心としてwidthの幅とheightの高さを持つ 四角形を描く。
:arc x y width height angle1 angle2 &optional (gc gcon)
を中心としてwidthの幅とheightの高さを持つ 四角形に内接する楕円の円弧を描く。angle1が始まりの角度を示し、 angle2が終わりの角度を示す。これらの角度の単位はラジアンである。
:fill-rectangle x y width height &optional (gc gcon)
四角領域を埋める。
:fill-arc x y width height angle1 angle2 &optional (gc gcon)
円弧の中を埋める。
:string x y str &optional (gc gcon)
の位置から文字列strを表示する。背景は、書かない。
:image-string x y str &optional (gc gcon)
文字列strを表示する。文字列は、背景色で満たされる。
:getimage &key x y width height (mask #ffffffff) (format 2)
serverからximageを取り、ピクセルデータを文字列として返す。 serverから送られるピクセルデータは、一端 Xlibのximage構造に蓄積される。 その後、行毎に文字列にコピーされる。 ximage構造は、自動的に破壊される。 :getimageにより得られた画像文字列は、pixel-imageを作るために 使用できる。また、[PBMfile]節に書かれているようにpbmフォーマットのファイルに 書き込むことができる。
:putimage image &key src-x src-y dst-x dst-y width height (gc gcon)
このXdrawableの指定された位置にimageを表示する。 imageは、文字列あるいはximage構造へのアドレスポインターである。
:draw-line from to
メソッドと同じである。 他のviewsurfaceクラスとの互換性を提供できる。
:line-width &optional dots
このXdrawableのデフォルトGCの線の幅を設定する。 :gc :line-widthメッセージの使用を推薦する。
:line-style &optional dash
このXdrawableのデフォルトGCの線スタイルを設定する。 :gc :line-styleの使用が好まれる。
:color &optional c
このXdrawableの色を設定する。
:clear **
全画面を消去する。この関数は、:clear-areaを呼び出す。
:clear-area &key x y width height gc
メソッドを用いて四角領域を消去する。
Xpixmap
pixmapは、画像バッファあるいは背景のパターンとしてしばしば用いられる drawableである。xwindowと異なり、xwindowにコピーされるまで pixmap自身を見ることはできないし、pixmapはどんなイベントも発生しない。
:init id
このpixmapを初期化する。
:create &key (width 500) (height 500) (depth 1) (gc *defaultgc*)
デフォルトGCとして:gcを持つ、width\(\times\)heightのpixmapを作成する。
:create-from-bitmap-file fname
で指定されるbitmapファイルからpixmapを作る。
:write-to-bitmap-file fname
このpixmapの内容をfnameで指定されるbitmapファイルに書き込む。 このファイルは、:create-from-bitmap-fileメソッドで pixmapを作り、読み戻すことができる。
:destroy **
このpixmapを破壊し、X resourceを開放する。
Xwindow
Xwindowは、画面の見える四角領域を定義する。 これは、text-windowやグラフィックオブジェクトを描くためのcanvas だけでなく、windowというよりはむしろグラフィックオブジェクトのような たくさんのpanel-itemやscroll-barsからも継承される。
:map **
このXwindowとその子windowを全て表示する。
:unmap **
このXwindowをとその子windowを全て非表示にする。
:selectinput event-mask
は、整数かあるいはイベントマスクsymbolのリストである。 ビットが1となっているかあるいはevent-maskリスト に列挙されているイベントは、それぞれこのwindowに通知される。
:destroy **
このXwindowを破壊し、X resourceを開放する。 windowオブジェクトは、ガーベージコレクトされないため、 xwindow*やxwindow-hash-tab*の中の一致するエントリも削除される。 全ての子windowも:destroyを送ることにより削除する。 このwindowは、親windowの子windowのリストから削除される。 drawableIDは、NILに設定される。
:parent **
親windowオブジェクトを返す。
:subwindows **
全ての子windowのリストを返す。 子windowは、もっとも最近作られたものがリストの最初である。 このwindowの直接の子windowだけがリストされ、子windowの子windowは リストされない。
:associate child
このwindowの子windowとしてchild windowを登録する。
:dissociate child
子windowのリストからchild windowを削除する。
:title title
このwindowのタイトル名を変更する。そのタイトル名はXserverに送られるため、 一旦蓄積され、window managerによって表示される。
:attributes **
このwindowの属性を表現する整数ベクトルを返す。
:visual **
このXwindowのvisual resource IDを返す。
:screen **
このXwindowのscreen resource IDを返す。
:root **
root window IDを返す。
:location **
このwindowのxとy座標を記述する2次元の整数ベクトルを返す。
:depth **
このwindowの深さ(カラープレーンの数)を返す。
:size **
このwindowのサイズ(高さと幅)を返す。
:colormap **
このwindowのcolormap resource IDを返す。
:move newx newy
このwindowの位置を(newx,newy)に変更する。 位置は、親windowの相対位置で与えられる。
:resize width height
このwindowのサイズを変更する。 たぶん、大きさのパラメータがクライアント側のXlibに中にキャッシュされるため、 :resizeの直後に:geometryメッセージを 送ると誤った(古い)結果を返す。
:raise **
このwindowを前面に持ってくる。
:lower **
このwindowを後ろに置く。
:background pixel
背景のピクセル値(カラーマップのインデックス)をpixelに変更する。 pixel値は、bg-colorスロットにも保存される。 :clear処理は、現在の背景を指定されたpixelで埋める。
:background-pixmap pixmap
背景のpixmap値をpixmapに変更する。
:border pixel
このwindowの枠線の色をpixelに設定する。
:set-colormap cmap
colormapを設定する。
:clear **
このXwindow内を全て消去する。
:clear-area &key x y width height
このXwindowの指定された四角領域を消去する。
make-xwindow &rest args
引き数argsで示されるXwindowを作る。
init-xwindow &optional (display (getenv “DISPLAY”))
eusxが起動するときに最初に呼び出される関数である。 init-xwindowは、displayで指定されるXserverに接続し、 [xvariables]節に記述されているデフォルト変数を初期化する。 init-xwindowは、デフォルトフォントをロードし、 グローバル変数に設定する。例えば、font-courb12, lucidasans-bold-12など。 このフォントロードは、起動時に時間遅れを引き起こす。 フォントロードの数を減らしたり、ワイルドカード文字“*”を使用せずに 正確なフォント名を指定することにより、その遅れを短くできる。
Graphic Context¶
gcontext
graphic context(GC)を定義する。 Euslispの中で、全てのwindowはデフォルトGCを持っている。
与えられた属性でGCを作成する。 drawableは、画面と画面の深さを知るためにXserverにより使用される。 結果のGCは、同じ画面上で作成される限り、 どのdrawableでも使用できる。
:gc **
XのGC IDを返す。
:free **
このGCを開放する。
:copy **
このGCのコピーを作る。
:foreground &optional color
もし、colorが与えられたならば、 文字色にcolorを設定する。colorはピクセル値である。
:background &optional color
もし、colorが与えられたならば、 背景色にcolorを設定する。colorはピクセル値である。
:foreback fore back
一度に文字色と背景色を設定する。
:planemask &optional plane-mask
plane-maskを設定する。
:function x
描画機能を設定する。 xは、以下に示す数字かキーワードの内の1つである。 0=Clear, 1=And, 2=AndReverse, 3=Copy, 4=AndInverted, 5=NoOp, 6=Xor, 7=Or, 8=Nor, 9=Equiv, 10=Invert, 11=XorReverse, 12=CopyInverted, 13=OrInverted, 14=Nand, 15=Set, :clear, :and, :andReverse, :copy, :andInverted, :NoOp, :Xor, :Or, :Nor, :Equiv, :Invert, :XorReverse, :CopyInverted, :OrInverted, :Nand, :Set
:font x
このGCのフォント属性を設定する。 xは、フォント名あるいはフォントIDである。 もし、xがフォント名(文字列)であったならば、:fontは フォントIDを決めるためにx:LoadQueryFontを呼び出す。 もし、見つからなかった場合、“no such font ...”が警告される。 もし、xがNIL(与えられなかった)ならば、このGCの現在の フォントIDが返される。
:line-width x
線幅をピクセル数xで設定する。
:line-style x
線スタイル(実線、点線など)を設定する。
:dash &rest x
のそれぞれの要素は、整数である。 :dashは、線スタイルの点線パターンを設定する。
:tile pixmap
をこのGCのタイルパターンに設定する。
:stipple pixmap
をこのGCの点画に設定する。
:get-attribute attr
属性値を得る。 attrは、:function, :plane-mask, :foreground, :background, :line-width, :line-style, :cap-style, :join-style, :fill-style, :fill-rule, :fontの内の1つである。 属性値を表す整数が返される。
属性値を変更する。 同時に複数の属性値を変更できる。
font-id fontname
もし、fontnameが整数であるなら、フォントIDとみなしてその値を返す。 もし、fontnameが文字列であるなら、x:LoadQueryFontを使用して フォント構造を得て、そのフォントIDを返す。 fontnameは、正確な名前の略語でも良い。例えば、 24ポイントのクーリエフォントとして“*-courier-24-*”を指定できる。 もし、フォントが見つからなければ、can’t load fontの警告を 出力する。
textdots str font-id
文字列のascent descent widthをドット単位に示す3つの整数のリストを 返す。
色とカラーマップ¶
colormap
Xwindowのカラーマップおよびアプリケーション指向のカラールックアップテーブル を定義する。 カラーはRGB値で表現され、その範囲は0〜65535である。 カラーマップのカラーセルは、8ビットの擬似カラーディスプレイの上の 0〜255の範囲の値に設定される。
ここで、8ビットの擬似カラーディスプレイの機能があり、 256色を選択することができると仮定する。 基本的にカラーマップを使用する2つの方法がある。 1つは、システムデフォルトのカラーマップを共有する方法で、 もう1つはプロセスに独自のカラーマップを作成する方法である。 もし、システムのデフォルトカラーマップを使用する場合、 マップのすべてのカラーセルを使いきらないように注意しなければならない。 なぜなら、マップは多くののプロセスから共有されているからである。 もし、独自のカラーマップを使用する場合、 他のプロセスを気にすることなく256色すべてを使用することができる。 しかし、そのマップは明確に独自のwindowに設定しなければならない。 マウスのポインターがwindow内のどこかに動かされたとき、 カラーマップはwindow managerにより活性化される。
システムデフォルトのカラーマップは eusxが実行される最初にx:colormapのクラスのインスタンスとして、 x:*color-map*に設定されている。 もし、独自のカラーマップを使用するとき、x:colormapのインスタンスを 作る。 これらのインスタンスは、x serverで定義されたcolormapオブジェクトと 一致しており、それぞれのインスタンスのcmapidに示されている。
システムデフォルトのカラーマップを使用するとき、 他のプロセスと共有するカラーを読み込み専用(read-only)に、 Euslispの独自カラーを読み書き可能(read-write)に定義することができる。 “読み込み専用”は、カラーセルに割り当てられる 任意のカラーに定義することができる。 しかし、割り当てた後変更することができない。 もう一方で、“読み書き可能”カラーは定義した後でさえ、変更することができる。 共有カラーは、他のプロセスが変更を予期していないため“読み込み専用”である。 この“読み込み専用”と“読み書き可能”の属性は、それぞれのカラーに付けられる。 (しばしば、カラーセルとして参照される)
colormapオブジェクトは、color IDからRGBの物理的な表現への変換を 定義する。 しかしながら、これらの論理的なcolor IDは、任意に選択することができない。 特に、システムのデフォルトのカラーマップを使用しているとき、使用できない。 color ID(しばしば’pixel’として参照される)は、カラーマップの特別な色 のインデックスである。 Xlibは、割り当ての要求があると、共有カラーのために空いたインデックスの 1つを選択する。 したがって、たくさんのグレー階調のカラーを連続的に割り当てることを 保証することあるいは最初(0番目)のインデックスから始めることはできない。
アプリケーションの観点から、もっと論理的なカラー名が必要とされる。 例えば、グレー階調の数は明るさをインデックスとして参照すべきである。 レイトレーシングプログラムは、 HLSで定義される違った明るさのカラーのグループのために 連続的なインデックスの割り当てを要求する。
この問題に対処するために、Euslispのカラーマップはルックアップテーブル(LUT) と呼ばれる別の変換テーブルを提供している。 論理的なカラーグループのために、LUTを定義でき、symbol名を付けることができる。 1つ以上のLUTをカラーマップとして定義できる。 LUTは、Xserverが認識できるように、アプリケーションが指定した論理カラーの インデックスを物理ピクセル値に変換するために整数ベクトルである。
:id **
を返す。
:query pix
指定されたピクセル数のRGB値を返す。
:alloc r g b
このメソッドは、:store nil r g bと同一である。 新しいカラーセルがこのカラーマップに配置され、指定されたRGB値に割り当てられる。
:store pix r g b
番目のカラーセルのRGB値を設定する。
:store pix color-name
は、カラーマップに色を設定する低レベルメソッドである。 1つの書式として、RGB値を0〜65535で指定する方法である。 他の書式として、“red” や“navy-blue”のようなカラー名で指定する。 もし、color-nameがなければ、NILを返す。 ピクセルはカラーマップのインデックスあるいはNILである。 もし整数なら、カラーセルは読み書き可能でなければならない。 もしNILなら、共有の読み込み専用カラーセルが割り当てられている。 :storeは、カラーマップ内のカラーセルのインデックスを返す。
:store-hls pix hue lightness saturation
HLS(Hue, Lightness and Saturation)で 指定される色をカラーマップのpix番目に蓄積する。 もし、pixがNILなら、共有の読み込み専用のカラーセルが割り当てられる。 :store-hlsは、カラーセルに割り当てられるインデックスを返す。
:destroy **
このcolormapを破壊し、リソースを空にする。
:pixel LUT-name id
の中からid番目を調べて、ピクセル値を返す。 LUT-nameは、:define-LUTで定義されたルックアップテーブルの名前である。
:allocate-private-colors num
独自のカラーマップにnum個のカラーセルを割り当てる。
:allocate-colors rgb-list &optional private
のそれぞれの要素は、red,green,blueのリストである。 カラーセルは、それぞれのRGB値が割り当てられ、ピクセル値を要素とする 整数ベクトルを返す。
:define-LUT LUT-name rgb-list &optional private
に記述されたカラーが割り当てられ、 LUTがLUT-nameのシンボリック名で登録される。 独自のカラーセルを定義するためには、privateをTに設定すること。
:define-gray-scale-LUT LUT-name levels &optional private
線形のグレースケールカラーで表現されるlevels階調の カラーセルを割り当て、LUTを返す。 例えば、(send x:*color-map* :define-gray-scale-LUT ’gray8 8) は、システムのデフォルトカラーマップの中に8つのグレーカラーを配置し、 #i(29 30 31 48 49 50 51 0)のような整数ベクトルを返す。 物理ピクセル値は、:pixelメッセージを送ることにより得られる。 例えば、(send x:*color-map* :pixel ’gray8 2)は、31を返す。
:define-rgb-LUT LUT-name red green blue &optional private
RGB表現を縮小したLUTを定義する。 例えば、もし、red=green=blue=2なら、カラーセルには\(2^{2+2+2}=2^6=64\) が割り当てられる。
:define-hls-LUT LUT-name count hue low-brightness high-brightness saturation &optional private
HLSで使用するcount数のカラーを配置する。 hue (0..360),*saturation* (0..1),*low-brightness* とhigh-brightnessの明るさの差をカラーマップに蓄積される。 LUT-nameで名付けられるLUTも作られる。
:define-rainbow-LUT LUT-name &optional (count 32) (hue-start 0) (hue-end 360) (brightness 0.5) (saturation 1.0) private
HLSモデルを用いてcountの色を配置する。 brightness (0..1)と saturation (0..1)と, hue-startとhue-end間の異なったhueを持つ色を カラーマップに蓄積する。 LUT-nameを名付けられたLUTも生成される。
:LUT-list **
このカラーマップに定義されている全てのLUTのリストを返す。 リストのそれぞれのエントリは、LUT名と整数ベクトルの組である。
:LUT-names **
このカラーマップの全てのLUTの名前のリストを返す。
:LUT name
で指定される整数ベクトル(LUT)を返す。
:size LUT
の長さを返す。
:planes **
このカラーマップのプレーンを返す。
:set-window xwin
このカラーマップをxwinのwindowと関連付ける。 このカラーマップは、xwinにカーソルが入ったとき活性化される。
:free pixel-or-LUT
の場所にあるカラーセルを開放するか あるいはLUTのすべてを開放する。
:init &optional cmapid
このカラーマップをcmapidで初期化する。 登録されたLUTはすべて捨てられる。
:create &key (planes 0) (colors 1) (visual *visual*) contiguous
新しいカラーマップを作成する。
XColor
RGBモデルのカラーを定義する。 それぞれのスロットに値を割り当てるには、setfを用いる。 RGB値は、符合拡張され、最大値は\(-1\)と表現される。
:red **
このXColorの赤色の値を返す。
:blue **
このXColorの青色の値を返す。
:green **
このXColorの緑色の値を返す。
:rgb **
このXColorのRGB値のリストを返す。
:init pix R G B &optional (f 7)
を初期化する。
find-visual type depth &optional (screen 0)
とdepthで指定されるvisual-IDを見つける。 typeは、:StaticGray, :GrayScale, :StaticColor, :pseudoColor, :TrueColorあるいは:DirectColorのどれかである。 ふつう、depthは1, 8 または 24である。
[1] | eusxは、eusへのシンボリックリンクである。 |
XToolKit¶
XToolKitは、 ボタン、プルダウンメニュ、テキストwindowなどのGUI要素を使用して GUI (Graphical User Interface)を作成するのを容易にするための 高レベルXwindowインターフェースである。 Xlibクラスとの大きな違いは、XToolKitがXserverから送られる Xeventと一致するユーザーが定義した対話ルーチンを呼び出し、 それらの対話指向windowパーツと一致した外観を提供することである。 XToolKitに含まれるクラスは、以下の継承構造を持っている。
xwindow
panel
menubar-panel
menu-panel
filepanel
textviewpanel
confirmpanel
panel-item
button-item
menu-button-item
bitmap-button-item
menu-item
text-item
slider-item
choice-item
joystick-item
canvas
textwindow
buffertextwindow
scrolltextwindow
textedit
scroll-bar
horizontal-scroll-bar
以下に示すxwindowクラスはXToolKitの5つの基本クラスである。 panel, panel-item, canvas, textWindowとscroll-bar。 menubar-panelとmenu-panelは、panelの下に定義される。 新しいアプリケーションwindowを作り、イベントの上でそれを実行させるための 基本的な方策は、以下の通りである。
- アプリケーションクラスの定義 アプリケーションクラスwindowは、 XToolKitの要素を置く能力を持つpanelのサブクラスとして 定義されなければならない。
- イベントハンドラの定義 アプリケーションクラスにおいて、 ボタンが押されたり、メニューアイテムが選択されたりしたときに 呼び出されるイベントハンドラを定義する。 イベントハンドラは、panel-itemの指定された引数を持つメソッドとして 定義すべきである。
- サブパネルの定義 もし、menubar-panelを使用するなら、 アプリケーションwindowの一番上におかれる。 したがって、:create-menubarによって最初に作成されなければ ならない。 同様に、menu-panelは、そのmenu-panelと関連する menu-button-itemより前に定義する必要がある。
- パネルアイテムの作成 button-item, text-item, slider-itemなどのようなパネルアイテムは、 (send-super :create-item class label object method)によって 作成することができる。 上記で定義されたイベントハンドラは、それぞれのパネルアイテムと 接続される。 これらの初期化手続きは、アプリケーションwindowクラスの :createメソッドの中で定義すべきである。 必要なときはいつでもイベント送信を停止するためのquitボタンを 定義することを忘れないこと。 どんなtextWindowとcanvasも、:locate-itemメソッドを経由して アプリケーションwindowの中に置くことができる。
- window全体の作成 :createメッセージをアプリケーション クラスに送ることで、windowにXToolKitの要素を正しく置いたアプリケーション windowを作成する。
- イベント送信の実行 Xserverからイベントを受け、一致する windowに配るためには、window-main-loopを実行すること。 Solaris2上では、イベントを配るための異なったスレッドである window-main-threadで実行する。 window-main-threadでは、最上位レベルの対話が活きている。 window-main-threadを2回以上実行してはならない。
Xイベント¶
現在の実行において、 イベント構造は固定イベントバッファ(25要素の整数ベクトル)から受け、 同じバッファが全てのイベントに関して再使用される。 イベント構造は、同時に2つ以上のイベントを参照する必要があるとき、 コピーされなければならない。
window-main-loopは、Xserverから送られる全てのイベントを 捕獲し、イベントが発生したwindowに配るための関数である。
event **
もっとも最近のイベント構造を持つ25要素の整数ベクトル
next-event **
の中にイベント構造を蓄積し、 もし1つでも未決定のイベントがあればそれを返し、 なければNILを返す。
event-type event
event-window event
が発生したwindowオブジェクトを返す。
event-x event
からそのイベントが発生したx座標を抜き出す。 (すなわち、window内におけるマウスポインタの横方向の相対的な位置)
event-y event
からそのイベントが発生したy座標を抜き出す。 (すなわち、window内におけるマウスポインタの縦方向の相対的な位置)
event-width event
イベントに幅パラメータを表現する eventの8つの要素を返す。
event-height event
イベントに高さパラメータを表現する eventの8つの要素を返す。
event-state event
キーの状態で変更されたマウスボタンを表現するキーワードのリストを返す。 キーワードは、:shift, :control, :meta, :left, :middleと:rightである。 例えば、もしシフトキーが押されている状態で左のボタンが押されたならば、 (:shift :left)が返される。
display-events **
によって捕獲された全てのxwindowイベントを表示する。 Control-Cは、この関数を停止させる唯一の方法である。
window-main-loop &rest forms
window-main-thread **
スレッドであることを除いてwindow-main-loopと同じことをする。 window-main-threadは、Solaris2でのみ実現されている。 window-main-threadは、read-eval-printが入力されない エラーハンドラをインストールしている。 エラー情報を表示した後、そのイベントは処理を続ける。
パネル¶
panel
panelは、パネルアイテムや他のpanelを含んだどんなxwindowも置くこと ができるxwindowである。 panelオブジェクトは、panelの中で生成されたパネルアイテムへの デフォルトフォントを供給する。 アプリケーションwindowは、panelのサブクラスとして定義 去れなければならない。
panelを生成し、初期化する。 スーパークラスの:createが呼び出されるため、 xwindowに対する全ての生成用パラメータ(:width, :height, :border-widthなど)が許される。 :item-heightと:item-widthは、最小の高さと幅をそれぞれのパネルアイテムに 与える。
:items **
関連するアイテムを全てリストで返す。
:locate-item item &optional x y
は、xwindowオブジェクト(ふつうはパネルアイテム)である。 もしxとyが与えられたならば、アイテムはそこに置かれる。 そうでなければ、itemは、もっとも最近に置かれたアイテムに 隣接するように置かれる。 アイテムは、 図 [panellayout]のように 上から下に向かって、また左から右に向かって置かれていく。 :locate-itemは、またitemsやsubwindowsリストに itemを追加し、:mapを送ることにより見えるようにする。
klassで指定されるパネルアイテムのクラス (すなわち、button-item, menu-button-item, slider-item, joystick-itemなど), のインスタンスを作り、:locate-itemを用いてpanelにアイテムを置く。 argsは、klassの:createメソッドに送られる。 labelは、パネルアイテムの中に書かれる識別文字列である。 receiverとmethodは、一致するイベントを呼び出すイベントハンドラを 指定する。
:delete-items **
パネルアイテムを全て削除する。
menubar-panelを作成し、panelの最上部に置く。
以下に示すメソッドは、イベントがイベントハンドラのないpanelに送られたとき、 “subclass’s responsibility”警告メッセージを避けるために提供されている。 ユーザーのアプリケーションでは、これらのメソッドを上書きしなければならない。
:quit &rest a
に:quitメッセージを送り、 イベント処理を停止する。
:KeyPress event
NILを返す。
:KeyRelease event
NILを返す。
:ButtonPress event
NILを返す。
:ButtonRelease event
NILを返す。
:MotionNotify event
NILを返す。
:EnterNotify event
NILを返す。
:LeaveNotify event
NILを返す。
サブパネル(メニューとメニューバー)¶
menu-panel
menu-panelは、panel-buttonとmenu-itemのみを 含むことができるパネルの一種である。 panelと異なり、menu-panelはふつう見えないし、 menu-panelと関連したbutton-itemが押された時に 表示される。 もし、menu-panelがいつも見えるように作られたならば、 ピンを刺したメニューとなる。 マウスイベントに対するmenu-itemの応答は、アイテムの外のどこかで 押されたマウスボタンのようにふつうのmenu-buttonと 全く異なっている。 menu-panelを使用するためには、最初に作成し、 その中にbutton-itemを置く。 それから、menu-button-itemがpanelの中あるいはmenubarの中に :menuの引数としてmenu-panelと一緒に作成される。
menu-panel windowを作成する。 そのwindowの大きさは、新しいmenu-itemが追加される時に 拡張される。
:add-item label name &optional (receiver self) &rest mesg
このmenu-panel windowの中にmenuアイテムを追加し、 対応する行動を張り付ける。 マウスボタンがアイテムの上で外されたとき、 receiverオブジェクトはmesgを受け取る。
menubar-panel
menubar-panelは、親panelの最上部にいつも置かれるサブパネルである。 メニューバーに置かれるパネルアイテムは、menu-button-itemで なければならない。 menubar-panelは、panelの:create-menubarメソッドにより 生成される。
ファイルパネル¶
FilePanelは、ファイルやディレクトリを対話的に処理する アプリケーションwindowである。 cdやgo-upボタンを使用することにより、 どんなディレクトリも見に行くことができるし、 以下のScrollTextWindowの中にディレクトリ内に含まれるファイルを 表示する。 テキストファイルは、異なったwindow(TextViewPanel)の中に 表示することができる。 ファイルは、また印刷することができ、削除することができ、 ボタンをクリックすることにより簡単にコンパイルすることができる。 ファイルを印刷するとき、a2ps file | lprコマンドがforkされたプロセスとして実行される。
テキスト表示パネル¶
TextViewPanelは、テキストファイルを表示するための アプリケーションwindowクラスである (図 [textviewpanel])。 プログラムテキストは、もっとも簡単なアプリケーションwindowの1つが どのように記述されているかを見れる。 :createメソッドにおいて、quitボタンとfindボタンと ファイルの中を捜すための文字列を供給するためのtext-itemを 作成する。 view-windowは、縦と横にスクロールバーを持ちファイルを表示するための ScrollTextWindowである。 TextViewPanelは、windowマネージャーにより一番外側のタイトルwindowの 大きさを変えたときview-windowの大きさを変えるために :ConfigureNotifyイベントを捕獲する。
(defclass TextViewPanel :super panel
:slots (quit-button find-button find-text view-window))
(defmethod TextViewPanel
(:create (file &rest args &key (width 400) &allow-other-keys)
(send-super* :create :width width args)
(setq quit-button
(send self :create-item panel-button "quit" self :quit))
(setq find-button
(send self :create-item panel-button "find" self :find))
(setq find-text
(send self :create-item text-item "find: " self :find))
(setq view-window
(send self :locate-item
(instance ScrollTextWindow :create
:width (setq width (- (send self :width) 10))
:height (- (setq height (send self :height)) 38)
:scroll-bar t :horizontal-scroll-bar t
:map nil :parent self)))
(send view-window :read-file file))
(:quit (event) (send self :destroy))
(:find (event)
(let ((findstr (send find-text :value)) (found)
(nlines (send view-window :nlines)))
(do ((i 0 (1+ i)))
((or (>= i nlines) found))
(if (substringp findstr (send view-window :line i)) (setq found i)))
(when found
(send view-window :display-selection found)
(send view-window :locate found))))
(:resize (w h)
(setq width w height h)
(send view-window :resize (- w 10) (- h 38)))
(:configureNotify (event)
(let ((newwidth (send self :width))
(newheight (send self :height)))
(when (or (/= newwidth width) (/= newheight height))
(send self :resize newwidth newheight))) ) )
パネルアイテム¶
panel-item
panel-itemは、パネルアイテムwindowのすべての種類において、 アイテムが指定するイベントが発生したとき notify-objectのnotify-methodを呼び出すための 抽象クラスである。
:notify &rest args
のnotify-methodを呼び出す。 イベント応答やnotify-methodへ送るための引き数が アイテムにより区別される。
- button-item
- ボタンは、同じbutton-itemの押し、外し時に応答。 引き数はbutton-itemオブジェクトである。
- menu-button-item
- メニューアイテムの選択時に応答。 引き数は、menu-button-itemオブジェクトである。
- choice-item
- 新しい選択ボタンの選択時に応答。 引き数は、choice-itemオブジェクトとその選択番号である。
- text-item
- 改行あるいはリターンの入力時に応答。 引き数は、text-itemオブジェクトと入力行(文字列)である。
- slider-item
- スライダーノブは、つかみと移動時に応答。 引き数は、slider-itemオブジェクトと新たな値である。
- joystick-item
- ジョイスティックは、つかみと移動時に応答。 引き数はslider-itemオブジェクトと新しいxとyの値である。
パネルアイテムを作成する。 パネルアイテムは、抽象クラスである。 このメソッドは、サブクラスによってsend-superを通してのみ 呼び出すべきである。
button-item
button-itemは、簡単なパネルアイテムである。 button-itemは、四角ボックスとその中のラベル文字列を持っている。 クリックされたとき、button-itemはpanel-itemオブジェクトを唯一の引き数として notify-objectのnotify-method を呼び出す。
:draw-label &optional (state :top) (color bg-color) (border 2) offset
のラベルを書く。
button-itemを作成する。 もし、ボタンの幅と高さが与えられないなら、サイズは 与えられたフォントを用いて書かれた ラベル文字列に合わせて自動的に設定される。 :border-widthはデフォルトで0であるが、 擬似3次元表現でボタンを浮き出しにする。 背景やフォントは親window(すなわち、panel)で定義されているものを デフォルトとする。
:ButtonPress event
もし、ボタンであれば、背景色をグレーにする。
:ButtonRelease event
の背景色を標準に変更する。
menu-button-item
プルダウンメニューを定義する。 menu-button-itemは、button-itemのようであるが、 menu-button-itemは、ボタンの下の関連するmenu-panelが 押されたとき、 notify-objectにすぐにメッセージを送る代わりに、 活性化させる。 メニューアイテムの1つの上でマウスボタンが外されたときに、本当のメッセージが 送られる。
プルダウンメニューを作成する。 receiverとmethod引き数は、影響を与えない。
:ButtonPress event
プルダウンメニューのボタンを反転させ、 ボタンの下に関連するmenu-panelをさらす。
:ButtonRelease event
このボタンの下のmenu-panelを消し、 このボタンを元に戻す。
bitmap-button-item
bitmap-button-itemの関数は、button-itemに似ているが、 表現が異なっている。 button-itemの場合にボタンの上に簡単なラベル文字列を描く代わりに、 bitmap-button-itemでは、ボタンが作られたときにbitmapファイルから ロードされるpixmapを描く。
bitmap-button-itemを作成する。 最初の引き数bitmap-fileは、button-itemのlabel引き数 を置き換えたものである。
:draw-label &optional (state :flat) (color bg-color) (border 2)
ボタンの上にbitmapかpixmapを描く。
:create-bitmap-from-file fname
という名のbitmapファイルからpixmapを作り、 pixmap-idにそのIDを入れる。
choice-item
choice-itemは、丸い選択ボタンの集合である。 1つの選択はいつも活性化しており、同時に1つの選択だけが 活性化することができる。 choice-itemは、ラジオボタンと同様な機能を提供する。
choice-item-buttonを作成する。 それぞれの選択ボタンは:button-sizeの半径を持つ円である。 新しい選択ボタンが選択されたとき、 notify-objectのnotify-methodが choice-itemオブジェクトと選択された選択ボタンの番号と一緒に呼び出される。
:value &optional new-choice invocation
もし、new-choiceが与えられたならば、現在の活性化選択ボタンとして 設定し、対応する円が黒色になる。 もしinvocationも指定されているなら、notify-objectの notify-methodが呼び出される。 :valueは、現在の(あるいは新しい)選択ボタンの番号を返す。
:draw-active-button &optional (old-choice active-choice) (new-choice active-choice)
ボタンを活性化として書く。
:ButtonPress event
もし、選択ボタンのどこかでマウスボタンが押されているなら、 その番号がtransient-choiceに記録される。 マウスボタンが外されるまでそれ以上の行動は、起こさない。
:ButtonRelease event
もし、既に押されていたところと同じボタンの上でマウスボタンが外されたなら、 active-choiceが更新され、 notify-objectのnotify-methodが呼び出される。
slider-item
choice-itemが離散的な値の選択に使用されるのに対し、 slider-itemはmin-valueとmax-valueの間の範囲の 連続的な値に対して使用される。 それぞれ値が変化した瞬間、slider-itemオブジェクトと新しい値が引き数として 一緒にnotify-objectのnotify-methodが呼び出される。
slider-itemを作成する。 スライドのノブは、バーの上に小さな黒の四角として表示される。 左端が:min値を表現し、右端が:max値を表現する。 バーの長さは、:spanドットに引き伸ばす。 現在の値は、:value-formatでslider-itemの右に表示する。
:value &optional newval invocation
もし、newvalが与えられたなら、現在の値として設定され、 ノブは対応する位置にスライドする。 もし、invocationもnon NILに指定されていたなら、 notify-objectのnotify-methodが呼び出される。 :valueは、現在の(新しい)値を返す。
joystick-item
joystick-itemは、2次元のslider-itemとしてみなすことができる。 2つの連続値はクモの巣のような同心円図の上を動く黒い円によって 指定することができる(図 [panelitem])。
:stick-sizeは、スティックの黒い円の半径である。 同心円図の円の大きさは、joystick-item windowの幅と高さ に合うように決定される。 もし、:returnがnon NILであるなら、 ジョイスティックは、マウスボタンが外された時の原点に帰る。 そうでないなら、ジョイスティックは、外された位置に残る。
:value &optional newx newy invocation
もし、newxとnewyが与えられたなら、 現在の位置として設定され、ジョイスティックは同心円図の 対応する位置に移動する。 もし、invocationもnon NILに指定されたなら、 notify-objectのnotify-methodが、 joystick-itemオブジェクトとx,y値を引き数として一緒に呼び出される。 :valueは、現在の(新しい)値のリストを返す。
以下に上に記述されているpanel-itemを使った短いプログラムを示し、 図 [panelitem]がパネルの中にどのように表示されるかを示したものである。
(in-package "X")
(defclass testPanel :super panel
:slots (quit joy choi sli))
(defmethod testPanel
(:create (&rest args)
(send-super* :create :width 210 :height 180
:font font-courb12 args)
(send-super :create-item button-item "quit" self :quit :font font-courb14)
(send-super :create-item choice-item "choice" self :choice
:choices '(" A " " B " " C ")
:font font-courb12)
(send-super :create-item slider-item "slider" self :slider
:span 90)
(send-super :create-item joystick-item "joy" self :joy)
self)
(:choice (obj c) (format t "choice: ~S ~d~%" obj c))
(:slider (obj val) (format t "slider: ~S ~s~%" obj val))
(:joy (obj x y) (format t "joy: ~S ~s ~s~%" obj x y)) )
(instance testPanel :create)
(window-main-thread)
text-item
text-itemは、ファイル名のような短いテキストを表示したり入力したり するために使用する。 text-itemは、ラベル文字列とその右側に小さなテキストwindowを持っている。 テキストwindow内にポインタが置かれたとき、キー入力が可能となり、 入力された文字がバッファに入れられる。 テキストwindow内の行修正が可能である。 control-Fとcontrol-Bは前後に1文字動かし、 delはカーソルの左の1文字を削除し、 control-Dはカーソル位置の文字を削除し、 カーソル位置にはどんなグラフィック文字も挿入できる。 マウスボタンをクリックすれば、クリックされた文字にカーソルを 移動させる。 enter(改行)キーを打つことにより、バッファされたテキストが notify-objectのnotify-methodに送られる。
text-itemを作成する。 テキストwindowの行バッファには、長さの制限が無いけれども、 見える部分はcolumns文字に制限されている。
:getstring **
キーバッファ内の文字列を返す。
キャンバス¶
canvas
canvasは、図や画像を入れるためのXwindowである。 現在、領域選択機能のみ実現されている。 ButtonPressイベントにより、canvasは押された位置を左上の端とし、 現在の位置を右下の端とする四角を描き始める。 ButtonReleaseにより、notify-objectのnotify-methodが 送られる。 canvas内に図や画像を描くためにはXdrawableのメソッドが使用される。
テキストwindow¶
TextWindowとBufferTextWidnowとScrollTextWindowの 3つのテキストwindowがある。
textWindow
メッセージを表示するために使用可能な仮想端末を実現する。 表示される内容は、バッファされないし、TextWindowに既に表示された 文字や行を引き出す方法はない。 基本的に、TextWindowは カーソル移動、行削除、領域削除、表示テキストのスクロール、文字列挿入 などを持つダンプ端末と似た能力を持っている。 また、テキストカーソルはマウスポインタで指示された位置に 移動することができる。
:init id
番目のテキストwindowを初期化する。
text-windowを作成する。 windowの大きさは、:widthと:heightかあるいは:rowsと :columnsで指定されたものとなる。 :notify-objectの:notify-methodは、改行文字が入力された ときに呼び出される。
:cursor flag
は、:on, :off, :toggleのどれかが可能である。 テキストカーソルは、win-rowとwin-colの位置である。 もし、flagが:onであれば、テキストカーソルは表示され、 flagが:offならば、消される。 また、flagがtoggleならば、反対になる。 このメソッドは、カーソルの位置の文字を更新するときはいつでも、 呼び出されなければならない。
:clear **
テキストwindow内を消去する。
:clear-eol &optional (r win-row) (c win-col) (csr :on)
とcで指定される位置の文字以降の残りの行を 消去する。カーソル位置の文字も含む。
:clear-lines lines &optional (r win-row)
番目の行以降の複数行を消去する。
:clear-eos &optional (r win-row) (c win-col)
とcで指定される位置から画面の最後までの領域を消去する。
:win-row-max **
このwindowに表示可能な最大行数を返す。
:win-col-max **
このwindowに表示可能な最大列数を返す。
:xy &optional (r win-row) (c win-col)
とcで指定される位置の文字のピクセル座標を計算する。
:goto r c &optional (cursor :on)
番目の行のc番目の列にカーソルを移動する。
:goback &optional (csr :on)
カーソルを1文字戻す。
:advance &optional (n 1)
文字だけカーソルを進める。
:scroll &optional (n 1)
行だけ縦方向にテキストwindowをスクロールする。
:horizontal-scroll &optional (n 1)
列だけ横方向にテキストをスクロールする。
:newline **
次の行の最初にカーソルを移動する。
:putch ch
カーソル位置に文字chを挿入する。 行の残りは、1文字前方に進められる。
:putstring str &optional (e (length str))
カーソル位置にstrを置く。
:event-row event
:event-col event
における、テキストカーソルの位置をを返す。
:KeyPress event
カーソル位置に入力された文字を挿入する。 もし、文字が改行であったなら、notify-objectに通知する。
textWindowStream
TextWindowStreamは、TextWdinowに接続された出力ストリームである。 print, format, write-byteなどによってこのストリームに出力 される文字や文字列がTextWdindowに表示される。 通常のファイルストリームとしては、 出力データはバッファされる。
:flush **
バッファされたテキスト文字列を掃き出し、TextWindowに送る。 finish-outputやこのストリームへの改行文字の書き込みは、 このメソッドを自動的に呼び出す。
make-text-window-stream xwin
を作り、そのストリームオブジェクトを返す。
BufferTextWindow
TextWindowの内容を表現する行バッファを保持する。 linebufは、行のベクトルである。exbufは、 タブ拡張されたテキストを持つ。 windowに表示可能な行のみが保持される。 BufferTextWindowは、数行のテキストを持つ 簡単なテキストエディタとして使用することができる。 text-itemは、表示可能な行バッファとしてBufferTextWindowを 使う。
:line n
番目の行の内容を文字列として返す。
:nlines **
の行数を返す。
:all-lines **
文字列のベクトルであるlinebufを返す。
:refresh-line &optional (r win-row) (c win-col)
番目の行のc番目の列以降を再書き込みする。
:refresh &optional (start 0)
番目の行以降の行を再書き込みする。
:insert-string string
カーソル位置にstringを挿入する。
:insert ch
カーソル位置に文字を挿入する。
:delete n
カーソル以降のn文字を削除する。
expand-tab src &optional (offset 0)
は、タブを含んだ可能性のある文字列である。 これらのタブは、タブの停止位置が8の倍数であると仮定して空白文字に 置き換えられる。
ScrollTextWindow
ScrollTextWindowは、行数制限がなく、縦と横にスクロールバーを持った BufferTextWindowを定義する。 ScrollTextWindowは、スクロールバーを伴ってwindowの大きさを変更するため、 あるいはテキストを再表示するために:configureNotifyイベントを 扱うことができる。 クリックすることによって、行を選択することができる。
:create &rest args &key scroll-bar horizontal-scroll-bar &allow-other-keys
スクロールバーが必要なとき、それぞれのキーワードの引き数にTを指定する。
:locate n
windowの上部からn番目の行にバッファされたテキストを表示する。
:display-selection selection
は、選択された行の位置を表現する。 選択された行がすべて高輝度で表示される。
:selection **
選択された行(文字列)を返す。
:read-file fname
で指定されるテキストファイルをlinebufに読み込み、 タブを拡張し、windowに表示する。 カーソルは、画面の最初に置かれる。
:display-string strings
は、行(文字列)の列である。 stringsは、linebufにコピーされ、windowに表示される。
:scroll n
行、縦にスクロールする。
:horizontal-scroll n
列、横にスクロールする。
:buttonRelease event
マウスポインタが置かれている行が選択される。 もし、windowが作成されたときにnotificationが指定されている ならば、notify-objectのnotify-methodが呼び出される。
:resize w h
windowの大きさを変更し、新しいサイズに合うように 内容を再表示する。 もし、スクロールバーがあれば、同じメッセージが送られる。
ロボットモデリング¶
ロボットのデータ構造とモデリング¶
ロボットのデータ構造と順運動学¶
ロボットの構造はリンクと関節から構成されていると考えることが出来るが, ロボットを関節とリンクに分割する方法として
- (a)切り離されるリンクの側に関節を含める
- (b)胴体,あるいは胴体に近いほうに関節を含める
が考えられる.コンピュータのデータ構造を考慮し, (a)が利用されている.その理由は胴体以外のすべてのリンクにおいて, 必ず関節を一つ含んだ構造となり,すべてのリンクを同一のアルゴリズムで扱う ことが出きるためである.
この様に分割されたリンクを計算機上で表現するためにはツリー構造を利用する ことが出来る.一般的にはツリー構造を作るときに二分木にすることでデータ構 造を簡略化することが多い.
ロボットのリンクにおける同次変換行列の求め方としては,関節回転座標系上に 原点をもつ\(\Sigma_j\)を設定し,親リンク座標系からみた回転軸ベクトルが \(a_j\), \(\Sigma_j\)の原点が\(b_j\)であり,回転の関節角度を\(q_j\)とする.
このとき\(\Sigma_j\)の親リンク相対の同次変換行列は
ここで,\(e^{\hat{a}_jq_j}\)は,一定速度の角速度ベクトルによって生ずる回 転行列を与える以下のRodriguesの式を用いている.これを回転軸\(a\)周りに \(wt[rad]\)だけ回転する回転行列を与えるものとして利用している.
親リンクの位置姿勢\(p_i, R_i\)が既知だとすると,\(\Sigma_i\)の同次変換行列を
として計算できる.これをロボットのルートリンクから初めてすべてのリンクに 順次適用することでロボットの全身の関節角度情報から姿勢情報を算出すること ができ,これを順運動学と呼ぶ.
EusLispによる幾何情報のモデリング¶
Euslispの幾何モデリングでは,基本モデル(body)の生成,bodyの合成関数,複 合モデル(bodyset)の生成と3つの段階がある.
これまでに以下のような基本モデルの生成,合成が可能な事を見てきている.
(setq c1 (make-cube 100 100 100))
(send c1 :locate #f(0 0 50))
(send c1 :rotate (deg2rad 30) :x)
(send c1 :set-color :yellow)
(objects (list c1))
(setq c2 (make-cylinder 50 100))
(send c2 :move-to
(make-coords
:pos #f(20 30 40)
:rpy (float-vector 0 0 (deg2rad 90)))
:world)
(send c2 :set-color :green)
(objects (list c1 c2))
(setq c3 (body+ c1 c2))
(setq c4 (body- c1 c2))
(setq c5 (body* c1 c2))
bodysetはirteusで導入された複合モデルであり,bodyで扱えない複数の物体や 複数の色を扱うためのものである.
(setq c1 (make-cube 100 100 100))
(send c1 :set-color :red)
(setq c2 (make-cylinder 30 100))
(send c2 :set-color :green)
(send c1 :assoc c2) ;;; これを忘れいように
(setq b1 (instance bodyset :init
(make-cascoords)
:bodies (list c1 c2)))
(objects (list b1))
幾何情報の親子関係を利用したサンプルプログラム¶
(setq c1 (make-cube 100 100 100))
(setq c2 (make-cube 50 50 50))
(send c1 :set-color :red)
(send c2 :set-color :blue)
(send c2 :locate #f(300 0 0))
(send c1 :assoc c2)
(objects (list c1 c2))
(do-until-key
(send c1 :rotate (deg2rad 5) :z)
(send *irtviewer* :draw-objects)
(x::window-main-one) ;; process window event
)
bodyset-linkとjointを用いたロボット(多リンク系)のモデリング¶
irteusではロボットリンクを記述するクラスとしてbodyset-link(irtmodel.l) というクラスが用意されている.これは機構情報と幾何情報をもち,一般的な木 構造でロボットの構造が表現されている.また,jointクラスを用いて関節情報 を扱っている.
(defclass bodyset-link
:super bodyset
:slots (joint parent-link child-links analysis-level default-coords
weight acentroid inertia-tensor
angular-velocity angular-acceleration
spacial-velocity spacial-acceleration
momentum-velocity angular-momentum-velocity
momentum angular-momentum
force moment ext-force ext-moment))
ジョイント(関節)のモデリングはjointクラス(irtmodel.l)を用いる.jointクラスは基底ク ラスであり,実際にはrotational-joint, linear-joint等を利用する. jointの子クラスで作られた関節は,:joint-angleメソッドで関節角度を指定す ることが出来る.
(defclass joint
:super propertied-object
:slots (parent-link child-link joint-angle min-angle max-angle
default-coords))
(defmethod joint
(:init (&key name
((:child-link clink)) ((:parent-link plink))
(min -90) (max 90) &allow-other-keys)
(send self :name name)
(setq parent-link plink child-link clink
min-angle min max-angle max)
self))
(defclass rotational-joint
:super joint
:slots (axis))
(defmethod rotational-joint
(:init (&rest args &key ((:axis ax) :z) &allow-other-keys)
(setq axis ax joint-angle 0.0)
(send-super* :init args)
self)
(:joint-angle
(&optional v)
(when v
(setq relang (- v joint-angle) joint-angle v)
(send child-link :rotate (deg2rad relang) axis)))
joint-angle))
ここでは,joint, parent-link, child-links, defualt-coordsを利用する.
簡単な1関節ロボットの例としてサーボモジュールを作ってみると
(defun make-servo nil
(let (b1 b2)
(setq b1 (make-cube 35 20 46))
(send b1 :locate #f(9.5 0 0))
(setq b2 (make-cylinder 3 60))
(send b2 :locate #f(0 0 -30))
(setq b1 (body+ b1 b2))
(send b1 :set-color :gray20)
b1))
(defun make-hinji nil
(let ((b2 (make-cube 22 16 58))
(b1 (make-cube 26 20 54)))
(send b2 :locate #f(-4 0 0))
(setq b2 (body- b2 b1))
(send b1 :set-color :gray80)
b2))
(setq h1 (instance bodyset-link :init (make-cascoords) :bodies (list (make-hinji))))
(setq s1 (instance bodyset-link :init (make-cascoords) :bodies (list (make-servo))))
(setq j1 (instance rotational-joint :init :parent-link h1 :child-link s1 :axis :z))
;; instance cascaded coords
(setq r (instance cascaded-link :init))
(send r :assoc h1)
(send h1 :assoc s1)
(setq (r . links) (list h1 s1))
(setq (r . joint-list) (list j1))
(send r :init-ending)
となる.
ここでは,h1
,s1
というbodyset-link
と,
j1
というrotational-joint
を作成し,ここから
cascaded-link
という,連結リンクからなるモデルを生成している.
cascaded-link
はcascaded-coords
の子クラスであるため,
r (cascaded-link)
,h1
,s1
の座標系の親子関係を
:assoc
を利用して設定している.
(r . links)
という記法はr
というオブジェクトのスロット変数
(メンバ変数)であるlinks
にアクセスしている.ここでは,
links
およびjoint-list
に適切な値をセットし,
(send r :init-ending)
として必要な初期設定を行っている.
これでr
という2つのリンクと1つの関節情報
を含んだ1つのオブジェクトを生成できる.これで例えば
(objects (list h1 s1))
ではなく,
(objects (list r))
としてロボットをビューワに表示できる.
また,(send r :locate #f(100 0 0))
などの利用も可能になっている.
cascaded-link
クラスのメソッドの利用例としては以下ある.
:joint-list
,:links
といった関節リストやリンクリストへの
アクセサに加え,関節角度ベクトルへのアクセスを提供する
:angle-vector
メソッドが重要である.これを引数なしで呼び出せば現
在の関節角度が得られ,これに関節角度ベクトルを引数に与えて呼び出せば,その引
数が示す関節角度ベクトルをロボットモデルに反映させることができる.
$ (objects (list r))
(#<servo-model #X628abb0 0.0 0.0 0.0 / 0.0 0.0 0.0>)
;; useful cascaded-link methods
$ (send r :joint-list)
(#<rotational-joint #X6062990 :joint101067152>)
$ (send r :links)
(#<bodyset-link #X62ccb10 :bodyset103598864 0.0 0.0 0.0 / 0.0 0.0 0.0>
#<bodyset-link #X6305830 :bodyset103831600 0.0 0.0 0.0 / 0.524 0.0 0.0>)
$ (send r :angle-vector)
#f(0.0)
$ (send r :angle-vector (float-vector 30))
#f(30.0)
cascaded-linkを用いたロボット(多リンク系)のモデリング¶
一方で多リンク系のモデリング用のクラスとしてcascaded-linkというクラス
がある. これには,links,
joint-listというスロット変数があり,ここにbodyset-link,
ならびにjointのインスタンスのリストをバインドして利用する. 以下は,
cascaded-link
の子クラスを定義しここでロボットモデリングに
関する初期化処理を行うという書き方の例である.
(defclass cascaded-link
:super cascaded-coords
:slots (links joint-list bodies collision-avoidance-links))
(defmethod cascaded-link
(:init (&rest args &key name &allow-other-keys)
(send-super-lexpr :init args)
self)
(:init-ending
()
(setq bodies (flatten (send-all links :bodies)))
(dolist (j joint-list)
(send (send j :child-link) :add-joint j)
(send (send j :child-link) :add-parent-link (send j :parent-link))
(send (send j :parent-link) :add-child-links (send j :child-link)))
(send self :update-descendants))
)
(defclass servo-model
:super cascaded-link
:slots (h1 s1 j1))
(defmethod servo-model
(:init ()
(let ()
(send-super :init)
(setq h1 (instance bodyset-link :init (make-cascoords) :bodies (list (make-hinji))))
(setq s1 (instance bodyset-link :init (make-cascoords) :bodies (list (make-servo))))
(setq j1 (instance rotational-joint :init :parent-link h1 :child-link s1 :axis :z))
;; instance cascaded coords
(setq links (list h1 s1))
(setq joint-list (list j1))
;;
(send self :assoc h1)
(send h1 :assoc s1)
;;
(send self :init-ending)
self))
;;
;; (send r :j1 :joint-angle 30)
(:j1 (&rest args) (forward-message-to j1 args))
)
(setq r (instance servo-model :init))
このようなクラスを定義して(setq r (instance servo-model :init))
としても同じようにロボットモデルのインスタンスを作成することができ,先
ほどのメソッドを利用できる.クラス定義するメリットは
(:j1 (&rest args) (forward-message-to j1 args))
というメソッド定
義により,関節モデルのインスタンスへのアクセサを提供することができる.
これにより,特定の関節だけの値を知りたいとき,あるいは値をセットしたい
時には(send r :j1 :joint-angle)
や
(send r :j1 :joint-angle 30)
という指示が可能になっている.
このロボットを動かす場合は前例と同じように
(objects (list r))
(dotimes (i 300)
(send r :angle-vector (float-vector (* 90 (sin (/ i 100.0)))))
(send *irtviewer* :draw-objects))
などとするとよい.
(setq i 0)
(do-until-key
(send r :angle-vector (float-vector (* 90 (sin (/ i 100.0)))))
(send *irtviewer* :draw-objects)
(incf i))
とすると,次にキーボードを押下するまでプログラムは動きつづける.
さらに,少し拡張して これを用いて3リンク2ジョイントのロボットをモデリングした例が以下にな る.:joint-angleというメソッドに#f(0 0)というベクトルを引数に与えるこ とで全ての関節角度列を指定することが出来る.
(defclass hinji-servo-robot
:super cascaded-link)
(defmethod hinji-servo-robot
(:init
()
(let (h1 s1 h2 s2 l1 l2 l3)
(send-super :init)
(setq h1 (make-hinji))
(setq s1 (make-servo))
(setq h2 (make-hinji))
(setq s2 (make-servo))
(send h2 :locate #f(42 0 0))
(send s1 :assoc h2)
(setq l1 (instance bodyset-link :init (make-cascoords) :bodies (list h1)))
(setq l2 (instance bodyset-link :init (make-cascoords) :bodies (list s1 h2)))
(setq l3 (instance bodyset-link :init (make-cascoords) :bodies (list s2)))
(send l3 :locate #f(42 0 0))
(send self :assoc l1)
(send l1 :assoc l2)
(send l2 :assoc l3)
(setq joint-list
(list
(instance rotational-joint
:init :parent-link l1 :child-link l2
:axis :z)
(instance rotational-joint
:init :parent-link l2 :child-link l3
:axis :z)))
(setq links (list l1 l2 l3))
(send self :init-ending)
)))
(setq r (instance hinji-servo-robot :init))
(objects (list r))
(dotimes (i 10000)
(send r :angle-vector (float-vector (* 90 (sin (/ i 500.0))) (* 90 (sin (/ i 1000.0)))))
(send *irtviewer* :draw-objects))
EusLispにおける順運動学計算¶
順運動学計算を行うには,cascaded-corods, bodyset, bodyset-link 各クラ スに定義された :worldcoords メソッドを用いる. :worldcoords メソッドは,ルートリンクが見つかる(親リンクがなくなる) か, スロット変数 changed が nil であるリンク (一度順運動学計算を行ったことがある)が見つかるまで さかのぼって親リンクの :worldcoords メソッドを呼び出すことで 順運動学計算を行う. その際,スロット変数 changed を nil で上書く. したがって,二度目の :worldcoords メソッドの呼び出しでは,一度計算され たリンクの順運動学計算は行われず,即座にリンクの位置姿勢情報を取り出す ことができる.
また,bodyset-link クラスの :worldcoords メソッドは, level 引数を取る
ことができ,それが :coords である場合には,リンクのもつ bodies
スロット変数 の順運動学計算は行われない. bodies
にリンクの頂点を構成する faceset が含まれている場合には,これら
についての順運動学計算を省略することで大幅な高速化が期待できるだろう.
なお, level 引数の初期値には,リンクのもつ analysis-level スロット変数
が用いられるため,常に bodies の順運動学計算を行わない場合は,
リンクのインスタンス l について (send l :analysis-level :coords)
とすればよい.
(defmethod bodyset-link
(:worldcoords
(&optional (level analysis-level))
(case
level
(:coords (send-message self cascaded-coords :worldcoords))
(t (send-super :worldcoords)))
))
(defmethod bodyset
(:worldcoords
()
(when changed
(send-super :worldcoords)
(dolist (b bodies) (send b :worldcoords)))
worldcoords))
(defmethod cascaded-coords
(:worldcoords () ;calculate rot and pos in the world
(when changed
(if parent
(transform-coords (send parent :worldcoords) self
worldcoords)
(send worldcoords :replace-coords self))
(send self :update)
(setf changed nil))
worldcoords))
ロボットの動作生成¶
逆運動学¶
逆運動学においては, エンドエフェクタの位置・姿勢\(^0_n\bm{H}\)から マニピュレータの関節角度ベクトル \(\bm{\theta}=(\theta_1, \theta_2, ..., \theta_n)^T\) を求める.
ここで, エンドエフェクタの位置・姿勢\(\bm{r}\) は関節角度ベクトルを用いて
における\(f^{-1}\)は一般に非線形な関数となる. そこでを時刻tに関して微分することで, 線形な式
\(\bm{J}(\bm{\theta})\)は\(m \times n\)のヤコビ行列である. \(m\)はベクトル\(\bm{r}\)の次元, \(n\)はベクトル\(\bm{\theta}\)の次元である. \(\bm{\dot{r}}\)は速度・角速度ベクトルである.
ヤコビ行列が正則であるとき逆行列\(\bm{J}(\bm{\theta})^{-1}\)を用いて 以下のようにしてこの線型方程式の解を得ることができる.
しかし, 一般にヤコビ行列は正則でないので, ヤコビ行列の疑似逆行列\(\bm{J}^{\#}(\bm{\theta})\) が用いられる().
は, \(m>n\)のときはを, \(n>=m\)のときはを, 最小化する最小二乗解を求める問題と捉え,解を得る.
関節角速度は次のように求まる.
しかしながら, に従って解を 求めると, ヤコビ行列\(\bm{J}(\bm{\theta})\)がフルランクでなくなる特異点に近づく と, \(\left|\dot{\bm{\theta}}\right|\)が大きくなり不安定な振舞いが生じる. そこで, Nakamura et al.のSR-Inverse [1] を用いること で, この特異点を回避する.
本研究では ヤコビ行列の疑似逆行列\(\bm{J}^{\#}(\bm{\theta})\)の代わりに, に示す\(\bm{J}^{*}(\bm{\theta})\) を用いる.
これは, の代わりに, を最小化する最適化問題を 解くことにより得られたものである.
ヤコビ行列\(\bm{J}(\bm{\theta})\)が特異点に近づいているかの指標には 可操作度\(\kappa(\bm{\theta})\) [2] が用いられる().
微分運動学方程式における タスク空間次元の選択行列 [3] は見通しの良い定式化のために省略するが, 以降で導出する全ての式において 適用可能であることをあらかじめことわっておく.
基礎ヤコビ行列¶
一次元対偶を関節に持つマニピュレータのヤコビアンは 基礎ヤコビ行列 [4] により 計算することが可能である. 基礎ヤコビ行列の第\(j\)関節に対応するヤコビアンの列ベクトル\(\bm{J}_j\)は
と表される. \(\bm{a}_j\)・\(\bm{p}_j\)はそれぞれ第\(j\)関節の関節軸単位ベクトル・位置ベクトルであり, \(\bm{p}_{end}\)はヤコビアンで運動を制御するエンドエフェクタの位置ベクトルである. 上記では1自由度対偶の 回転関節・直動関節について導出したが, その他の関節でもこれらの列ベクトルを 連結した行列としてヤコビアンを定義可能である. 非全方位台車の運動を表す2自由度関節は 前後退の直動関節と 旋回のための回転関節から構成できる. 全方位台車の運動を表す3自由度関節は 並進2自由度の直動関節と 旋回のための回転関節から構成できる. 球関節は姿勢を姿勢行列で, 姿勢変化を等価角軸変換によるものとすると, 3つの回転関節をつなぎ合わせたものとみなせる.
関節角度限界回避を含む逆運動学¶
ロボットマニピュレータの軌道生成において, 関節角度限界を考慮することはロボットによる実機実験の際に重要となる. 本節では,文献 [5] [6] の式および文章を引用しつつ, 関節角度限界の回避を 含む逆運動学について説明する.
重み付きノルムを以下のように定義する.
ここで, \(\bm{W}\)は\(\bm{W} \in \bm{R}^{n \times n}\)であり, 対象で全ての要 素が正である重み係数行列である. この\(\bm{W}\)を用いて, \(\bm{J}_{\bm{W}}, \bm{\dot{\theta}}_{\bm{W}}\)を以下のよう に定義する.
この\(\bm{J}_{\bm{W}}, \bm{\dot{\theta}}_{\bm{W}}\)を用いて, 以下の式を得 る.
これによって線型方程式の解はから 以下のように記述できる.
また、現在の関節角度\(\theta\)が関節角度限界\(\theta_{i,\max}, \theta_{i, \min}\)に対してどの程度余裕があるかを評価する ための関数\(H(\bm{\theta})\)は以下のようになる [7]).
次にに示すような\(n \times n\)の重み係数行列 \(\bm{W}\)を考える.
さらにから次の式を得る.
関節角度限界から遠ざかる向きに関節角度が動いている場合には重み係数行列を 変化させる必要はないので,\(w_i\)を以下のように定義しなおす.
この\(w_i\)および\(\bm{W}\)を用いることで関節角度限界回避を含む逆運動学を解くこ とができる.
衝突回避を含む逆運動学¶
ロボットの動作中での自己衝突や環境モデルとの衝突は 幾何形状モデルが存在すれば計算することが可能である. ここではSugiura et al. により提案されている効率的な衝突回避計算 [8] [9] を応用した動作生成法を示す. 実際の実装はSugiura et al. の手法に加え, タスク作業空間のNullSpaceの利用を係数により制御できるようにした点や 擬似逆行列ではなくSR-Inverseを用いて特異点に ロバストにしている点などが追加されている.
衝突回避のための関節角速度計算法¶
逆運動学計算における目標タスクと衝突回避の統合は リンク間最短距離を用いたblending係数により行われる. これにより,衝突回避の必要のないときは目標タスクを厳密に満し 衝突回避の必要性があらわれたときに目標タスクを あきらめて衝突回避の行われる関節角速度計算を行うことが可能になる. 最終的な関節角速度の関係式はで得られる. 以下では\(ca\)の添字は衝突回避計算のための成分を表し, \(task\)の部分は衝突回避計算以外のタスク目標を表すことにする.
blending係数\(f(d)\)は, リンク間距離\(d\)と閾値\(d_a\)・\(d_b\)の関数として計算される ().
\(d_a\)は衝突回避計算を行い始める値 (yellow zone)であり, \(d_b\)は目標タスクを阻害しても衝突回避を行う閾値 (orange zone)である.
衝突計算をする2リンク間の最短距離・最近傍点が計算できた場合の 衝突を回避するための動作戦略は 2リンク間に作用する仮想的な反力ポテンシャルから導出される.
2リンク間の最近傍点同士をつなぐベクトル\(\bm{p}\)を用いた 2リンク間反力から導出される速度計算を に記す.
これを用いた関節角速度計算は となる.
\(k_{joint}\)・\(k_{null}\)はそれぞれ反力ポテンシャルを 目標タスクのNullSpaceに分配するかそうでないかを制御する係数である.
衝突回避計算例¶
以下ではロボットモデル・環境モデルを用いた衝突回避例を示す. 本研究では, ロボットのリンク同士,またはリンクと物体の衝突判定には,衝突判定ライブラリ PQP(A Proximity Query Package) [10]_を用いた.
では \(d_a = 200[mm]\),\(d_b = 0.1 * d_a = 20[mm]\), \(k_{joint} = k_{null} = 1.0\)と設定した.
この衝突判定計算では,衝突判定をリンクの設定を
- リンクのリスト\(n_{ca}\)を登録
- 登録されたリンクのリストから全リンクのペア\(_{n_{ca}}C_2\)を計算
- 隣接するリンクのペア,常に交わりを持つリンクのペアなどを除外
のように行うという工夫を行っている.
例では衝突判定をするリンクを 「前腕リンク」「上腕リンク」「体幹リンク」「ベースリンク」 の4つとして登録した. この場合, \(_4C_2\)通りのリンクのペア数から 隣接するリンクが除外され,全リンクペアは 「前腕リンク-体幹リンク」 「前腕リンク-ベースリンク」 「上腕リンク-ベースリンク」 の3通りとなる.
の3本の線(赤1本,緑2本)が 衝突形状モデル間での最近傍点同士をつないだ 最短距離ベクトルである. 全リンクペアのうち赤い線が最も距離が近いペアであり, このリンクペアより衝突回避のための 逆運動学計算を行っている.

Example of Collision Avoidance
非ブロック対角ヤコビアンによる全身協調動作生成¶
ヒューマノイドは枝分かれのある複雑な構造を持ち, 複数のマニピュレータで協調して動作を行う必要がある ().
複数マニピュレータの動作例として,
- リンク間に重複がない場合それぞれのマニピュレータについて 式を用いて関節角速度を求める. もしくは,複数の式を連立した方程式(ヤコビアンはブロック対角行列となる) を用いて関節角速度を求めても良い.
- リンク間に重複がある場合リンク間に重複がある場合は, リンク間の重複を考慮したヤコビアンを考える必要がある. 例えば,双腕動作を行う場合,左腕のマニピュレータのリンク系列と 右腕のマニピュレータのリンク系列とで,体幹部リンク系列が重複し, その部位は左右で協調して関節角速度を求める必要がある.
次節ではリンク間に重複がある場合の 非ブロック対角なヤコビアンの計算法 および それを用いた関節角速度計算法を述べる (前者の重複がない場合も以下の計算方法により後者の一部として計算可能で ある).
リンク間重複があるヤコビアン計算と関節角度計算¶
微分運動学方程式を求める際の条件を以下に示す.
マニピュレータの本数 \(L\)本
全関節数 \(N\)個
マニピュレータの先端速度・角速度ベクトル \([\bm{\xi}_0^T,...,\bm{\xi}_{L-1}^T]^T\)
各関節角速度ベクトル \([\bm{\dot{\theta}_0}^T,...,\bm{\dot{\theta}_{L-1}}^T]^T\)
- 関節の添字和集合 \(S = \{0,\hdots,N-1\}\)ただし,マニピュレータ\(i\)の添字集合\(S_i\)を用いて\(S\)は \(S = S_0 \cup \hdots \cup S_{L-1}\)と表せる.
\(S\)に基づく関節速度ベクトル \([\dot{\theta}_0, ..., \dot{\theta}_{N-1}]^T\)
とする.
運動学関係式はのようになる.
小行列\(\bm{J}_{i,j}\)は以下のように求まる.
ここで,\(\bm{J}_j\)はのもの.
を単一のマニピュレータの 逆運動学解法と同様にSR-Inverseを用いて関節角速度を 求めることができる.
- ここでの非ブロック対角ヤコビアンの計算法は, アーム・多指ハンドの動作生成
- [11]_に おいて登場する運動学関係式から求まるヤコビアンを
導出することが可能である.
ベースリンク仮想ジョイントを用いた全身逆運動学法¶
一般に関節数が\(N\)であるのロボットの運動を表現するためには ベースリンクの位置姿勢と関節角自由度を合わせた\(N+6\)個の変数が必要であ る. ベースリンクとなる位置姿勢の変数を用いたロボットの運動の定式化は 宇宙ロボット [12]_だけでなく, 環境に固定されないヒューマノイドロボット
[13]_の場合にも重要である.
ここでは 腕・脚といったマニピュレータに ベースリンクに3自由度の直動関節と 3自由度の回転関節が仮想的に付随したマニピュレータ構成を考える (). 上記の仮想的な6自由度関節を 本研究ではベースリンク仮想ジョイントと名づける. ベースリンク仮想ジョイントを用いることにより ヒューマノイドの腰が動き全身関節が駆動され, 運動学,ひいては動力学的な解空間が拡充されることが期待できる.
|Concept of the Virtual Joint of the Base Link (Left figure) Overview of the Robot Model (Right figure) Skeleton Figure of Robot Model with the Virtual Joint | |Concept of the Virtual Joint of the Base Link (Left figure) Overview of the Robot Model (Right figure) Skeleton Figure of Robot Model with the Virtual Joint |
ベースリンク仮想ジョイントヤコビアン¶
ベースリンク仮想ジョイントのヤコビアンは 基礎ヤコビ行列の計算() を利用し, 絶対座標系\(x\),\(y\),\(z\)軸の直動関節と 絶対座標系\(x\),\(y\),\(z\)軸回りの回転関節を それぞれ連結した\(6\times6\)行列である. ちなみに,並進・回転成分のルートリンク仮想ジョイントのヤコビアンは 以下のように書き下すこともできる.
\(\bm{p}_{B\to l}\)はベースリンク位置から添字\(l\)で表現する位置までの 差分ベクトルである.
マスプロパティ計算¶
複数の質量・重心・慣性行列を統合し 単一の質量・重心・慣性行列の組 \([m_{new}, \bm{c}_{new}, \bm{I}_{new}]\) を計算する演算関数を次のように定義する.
運動量・角運動量ヤコビアン¶
シリアルリンクマニピュレータを対象とし, 運動量・角運動量ヤコビアンを導出する. 運動量・原点まわりの角運動量を各関節変数で表現し, その偏微分でヤコビアンの行を計算する.
第\(j\)関節の運動変数を\(\theta_j\)とする. まず,回転・並進の1自由度関節を考える.
_j =
_j =
ここで, \([\tilde{m}_j, \tilde{\bm{c}}_j, \tilde{\bm{I}}_j]\)は AddMassProperty関数に第\(j\)関節の子リンクより 末端側のリンクのマスプロパティを与えたものであり, 実際には再帰計算により計算する [14]. これらを\(\dot{\theta}_j\)で割ることにより ヤコビアンの各列ベクトルを得る.
_j =
_j =
これより慣性行列は次のように計算できる.
直動関節\(x\),\(y\),\(z\)軸, 回転関節\(x\),\(y\),\(z\)軸を もつと考え整理し,次のようになる.
重心位置\(\bm{p}_{G}\), 慣性テンソル\(\tilde{\bm{I}}\)は次のように 全リンクのマスプロパティ演算より求める.
重心ヤコビアン¶
重心ヤコビアンは 重心速度と関節角速度の間のヤコビアンである. 本論文ではベースリンク仮想ジョイントを用いるため, ベースリンクに6自由度関節がついたと考え ベースリンク速度角速度・関節角速度の 重心速度に対するヤコビアンを重心ヤコビアンとして用いる. 具体的には, ベースリンク成分\(\bm{M}_{B}\)と 使用関節について抜き出した成分\(\bm{M}_{\dot{\bm{\theta}}}^{\prime}\) による運動量ヤコビアンを 全質量で割ることで重心ヤコビアンを計算する.
ロボットの動作生成プログラミング¶
三軸関節ロボットを使ったヤコビアン,逆運動学の例¶
3軸関節をもつロボットを定義し, 逆運動学やヤコビアンの計算例を紹介する.
ロボットの定義は以下の用になる.
(defclass 3dof-robot
:super cascaded-link
:slots (end-coords l1 l2 l3 l4 j1 j2 j3))
(defmethod 3dof-robot
(:init ()
(let (b)
(send-super :init)
(setq b (make-cube 10 10 20))
(send b :locate #f(0 0 10))
(send b :set-color :red)
(setq l4 (instance bodyset-link :init (make-cascoords) :bodies (list b) :name 'l4))
(setq end-coords (make-cascoords :pos #f(0 0 20)))
(send l4 :assoc end-coords)
(send l4 :locate #f(0 0 100))
;;
(setq b (make-cube 10 10 100))
(send b :locate #f(0 0 50))
(send b :set-color :green)
(setq l3 (instance bodyset-link :init (make-cascoords) :bodies (list b) :name 'l3))
(send l3 :assoc l4)
(send l3 :locate #f(0 0 100))
;;
(setq b (make-cube 10 10 100))
(send b :locate #f(0 0 50))
(send b :set-color :blue)
(setq l2 (instance bodyset-link :init (make-cascoords) :bodies (list b) :name 'l2))
(send l2 :assoc l3)
(send l2 :locate #f(0 0 20))
;;
(setq b (body+ (make-cube 10 10 20 :pos #f(0 0 10)) (make-cube 300 300 2)))
(send b :set-color :white)
(setq l1 (instance bodyset-link :init (make-cascoords) :bodies (list b) :name 'l1))
(send l1 :assoc l2)
;;
(setq j1 (instance rotational-joint :init :name 'j1
:parent-link l1 :child-link l2 :axis :y :min -100 :max 100)
j2 (instance rotational-joint :init :name 'j2
:parent-link l2 :child-link l3 :axis :y :min -100 :max 100)
j3 (instance rotational-joint :init :name 'j3
:parent-link l3 :child-link l4 :axis :y :min -100 :max 100))
;;
(setq links (list l1 l2 l3 l4))
(setq joint-list (list j1 j2 j3))
;;
(send self :init-ending)
self))
(:end-coords (&rest args) (forward-message-to end-coords args))
)
ここではロボットの手先の座標をend-coords
というスロット変数に格
納し,さらにこれにアクセスするためのメソッドを用意してある.
これまでと同様,
(setq r (instance 3dof-robot :init))
(objects (list r))
(send r :angle-vector #f(30 30 30))
としてロボットモデルの生成,表示,関節角度の指定が可能である. さらに,
(send (send r :end-coords) :draw-on :flush t)
とすると,ロボットのend-coords
(端点座標系)の表示が可能であるが,
マウスイベントが発生すると消えてしまう.恒久的に表示するためには
(objects (list r (send r :end-coords)))
とするとよい.
次に,ヤコビアン,逆運動学の例を示す.まず基本になるのが,
(send r :link-list (send r :end-coords :parent))
として得られるリンクのリストである.これはロボットのルート(胴体)から 引数となるリンクまでのたどれるリンクを返す.
:calc-jacobian-from-link-list
メソッドはリンクのリストを引数にと
り,この各リンクに存在するジョイント(関節)に
対応するヤコビアンを計算することができる.
また,:move-target
キーワード引数でエンドエフェクタの座標系を
指定してる.その他のキーワード引数については後述する.
(dotimes (i 100)
(setq j (send r :calc-jacobian-from-link-list
(send r :link-list (send r :end-coords :parent))
:move-target (send r :end-coords)
:rotation-axis t
:translation-axis t))
(setq j# (sr-inverse j))
(setq da (transform j# #f(1 0 0 0 0 0)))
;;(setq da (transform j# #f(0 0 0 0 -1 0)))
(send r :angle-vector (v+ (send r :angle-vector) da))
(send *irtviewer* :draw-objects)
)
ここではリンクの長さ(ジョイントの数)は3個なので6行3列のヤコビアン(j
)が
計算される.これの逆行列(j#
)を作り,位置姿勢の6自由度の目標速度・角速度
(#f(1 0 0 0 0 0)
)を与えると,それに対応する関節速度(da
)
が計算でき,これを現在の関節角度に足している
((v+ (send r :angle-vector) da)
).
次に,ロボットの端点作業の位置は合わせるが姿勢は拘束せず任意のままでよい,とい
う場合の例を示す.ここでは,:calc-jacobian-from-link-list
のオプ
ショナル引数として:rotation-axis
, :translation-axis
があり,それぞれ位置,姿勢での拘束条件を示す.
t
は三軸拘束,nil
は拘束なし,その他に:x
, :y
,
:z
を指定することができる.
(setq translation-axis t)
(setq rotation-axis nil)
(dotimes (i 2000)
(setq j (send r :calc-jacobian-from-link-list
(send r :link-list (send r :end-coords :parent))
:move-target (send r :end-coords)
:rotation-axis rotation-axis
:translation-axis translation-axis))
(setq j# (sr-inverse j))
(setq c (make-cascoords :pos (float-vector (* 100 (sin (/ i 500.0))) 0 200)))
(setq dif-pos (send (send r :end-coords) :difference-position c))
(setq da (transform j# dif-pos))
(send r :angle-vector (v+ (send r :angle-vector) da))
(send *irtviewer* :draw-objects :flush nil)
(send c :draw-on :flush t)
)
ここでは位置の三軸のみを拘束した3行3列のヤコビアンを計算し,これの 逆行列からロボットの関節に速度を与えている.さらに,ここでは
(send *irtviewer* :draw-objects :flush nil)
として*irtviewer*
に画面を描画しているが,実際に
ディスプレイに表示するフラッシュ処理は行わず,その次の行の
(send c :draw-on :flush t)
で目標座標は表示し,かつフラッシュ処理を行っている.
上記の計算をまとめた逆運動学メソッドが:inverse-kinematics
である.
第一引数に目標座標系を指定し,ヤコビアン計算のときと同様にキーワード
引数で :move-target
, :translation-axis
, :rotation-axis
を指定する.
また,:debug-view
キーワード引数にt
を与えると計算中の様
子をテキスト並びに視覚的に提示してくれる.
(setq c (make-cascoords :pos #f(100 0 0) :rpy (float-vector 0 pi 0)))
(send r :inverse-kinematics c
:link-list (send r :link-list (send r :end-coords :parent))
:move-target (send r :end-coords)
:translation-axis t
:rotation-axis t
:debug-view t)
逆運運動学が失敗する場合のサンプルとして以下のプログラムを見てみよう.
(dotimes (i 400)
(setq c (make-cascoords
:pos (float-vector (+ 100 (* 80 (sin (/ i 100.0)))) 0 0)
:rpy (float-vector 0 pi 0)))
(send r :inverse-kinematics c
:link-list (send r :link-list (send r :end-coords :parent))
:move-target (send r :end-coords) :translation-axis t :rotation-axis t)
(x::window-main-one)
(send *irtviewer* :draw-objects :flush nil)
(send c :draw-on :flush t)
)
このプログラムを実行すると以下のようなエラーが出てくる.
;; inverse-kinematics failed.
;; dif-pos : #f(11.7826 0.0 0.008449)/(11.7826/1)
;; dif-rot : #f(0.0 2.686130e-05 0.0)/(2.686130e-05/0.017453)
;; coords : #<coordinates #X4bcccb0 0.0 0.0 0.0 / 0.0 0.0 0.0>
;; angles : (14.9993 150 15.0006)
;; args : ((#<cascaded-coords #X4b668a0 39.982 0.0 0.0 / 3.142 1.225e-16 3.14
2>) :link-list (#<bodyset-link #X4cf8e60 l2 0.0 0.0 20.0 / 0.0 0.262 0.0> #<body
set-link #X4cc8008 l3 25.866 0.0 116.597 / 3.142 0.262 3.142> #<bodyset-link #X4
c7a0d0 l4 51.764 0.0 20.009 / 3.142 2.686e-05 3.142>) :move-target;; #<cascaded-
coords #X4c93640 51.764 0.0 0.009 / 3.142 2.686e-05 3.142> :translation-axis t :
rotation-axis t)
これは,関節の駆動範囲の制限から目標位置に手先が届かない状況である.
このような場面では,例えば,手先の位置さえ目標位置に届けばよく姿勢を
無視してよい場合:rotation-axis nil
と指定することができる.
また,:thre
や:rthre
を使うことで逆運動学計算の終了条件で
ある位置姿勢の誤差を指定することができる.正確な計算が求められていない
状況ではこの値をデフォルトの1
, (deg2rad 1)
より大きい値を
利用するのもよい.
また,逆運動学の計算に失敗した場合,デフォルトでは逆運動学計算を始める
前の姿勢まで戻るが,:revert-if-fail
というキーワード引数をnilと指定
すると,指定されたの回数の計算を繰り替えしたあと,その姿勢のまま関数か
ら抜けてくる.指定の回数もまた,:stop
というキーワード引数で指
定することができる.
(setq c (make-cascoords :pos #f(300 0 0) :rpy (float-vector 0 pi 0)))
(send r :inverse-kinematics c
:link-list (send r :link-list (send r :end-coords :parent))
:move-target (send r :end-coords)
:translation-axis t
:rotation-axis nil
:revert-if-fail nil)
irteusのサンプルプログラムにおける例¶
cascaded-coordsクラスでは
- (:link-list (to &optional form))
- (:calc-jacobian-from-link-list (link-list &key move-target (rotation-axis nil)))
というメソッドが用意されている.
前者はリンクを引数として,ルートリンクからこのリンクまでの経路を計算し, リンクのリストとして返す.後者はこのリンクのリストを引数とし, move-target座標系をに対するヤコビアンを計算する.
concatenate result-type a bは a bを 連結しresult-type型に変換し返し,scale a b はベクトルbの全ての要素をス カラーa倍し,matrix-logは行列対数関数を計算する.
(if (not (boundp '*irtviewer*)) (make-irtviewer))
(load "irteus/demo/sample-arm-model.l")
(setq *sarm* (instance sarmclass :init))
(send *sarm* :reset-pose)
(setq *target* (make-coords :pos #f(350 200 400)))
(objects (list *sarm* *target*))
(do-until-key
;; step 3
(setq c (send *sarm* :end-coords))
(send c :draw-on :flush t)
;; step 4
;; step 4
(setq dp (scale 0.001 (v- (send *target* :worldpos) (send c :worldpos))) ;; mm->m
dw (matrix-log (m* (transpose (send c :worldrot)) (send *target* :worldrot))))
(format t "dp = ~7,3f ~7,3f ~7,3f, dw = ~7,3f ~7,3f ~7,3f~%"
(elt dp 0) (elt dp 1) (elt dp 2)
(elt dw 0) (elt dw 1) (elt dw 2))
;; step 5
(when (< (+ (norm dp) (norm dw)) 0.01) (return))
;; step 6
(setq ll (send *sarm* :link-list (send *sarm* :end-coords :parent)))
(setq j (send *sarm* :calc-jacobian-from-link-list
ll :move-target (send *sarm* :end-coords)
:trnaslation-axis t :rotation-axis t))
(setq q (scale 1.0 (transform (pseudo-inverse j) (concatenate float-vector dp dw))))
;; step 7
(dotimes (i (length ll))
(send (send (elt ll i) :joint) :joint-angle (elt q i) :relative t))
;; draw
(send *irtviewer* :draw-objects)
(x::window-main-one))
実際のプログラミングでは:inverse-kinematicsというメソッドが用意されて おり,ここでは特異点や関節リミットの回避,あるいは自己衝突回避等の機能 が追加されている.
実際のロボットモデル¶
実際のロボットや環境を利用した実践的なサンプルプログラムを見てみよう.
まず,最初はロボットや環境のモデルファイルを読み込む.これらのファイル
は$EUSDIR/modelsに,これらのファイルをロードしインスタンスを生成す
るプログラムは以下のように書くことができる.(room73b2)
や
(h7)
はこれらのファイル内で定義されている関数である.
ロボットのモデル(robot-model
)はirtrobot.l
ファイルで定義
されており,cascaded-link
クラスの子クラスになっている.
ロボットとはlarm,rarm,lleg,rleg,head
のリンクのツリーからなる
ものとして定義されており,
(send *robot* :larm)
や(send *robot* :head)
として
ロボットのリム(limb)にアクセスでき,右手の逆運動学,左手の逆運動学等と
いう利用方法が可能になっている.
(load "models/room73b2-scene.l")
(load "models/h7-robot.l")
(setq *room* (room73b2))
(setq *robot* (h7))
(objects (list *robot* *room*))
ロボットには:reset-pose
というメソッドがありこれで初期姿勢をとる
ことができる.
(send *robot* :reset-pose)
次に,ロボットを部屋の中で移動させたい.部屋内の代表的な座標は
(send *room* :spots)
で取得できる.この中から目的の座標を得る
場合はその座標の名前を引数として:spot
メソッドを呼び出す.
ちなみに,このメソッドの定義はprog/jskeus/irteus/irtscene.l
にあり
(defmethod scene-model
(:spots
(&optional name)
(append
(mapcan
#'(lambda(x)(if (derivedp x scene-model) (send x :spots name) nil))
objs)
(mapcan #'(lambda (o)
(if (and (eq (class o) cascaded-coords)
(or (null name) (string= name (send o :name))))
(list o)))
objs)))
(:spot
(name)
(let ((r (send self :spots name)))
(case (length r)
(0 (warning-message 1 "could not found spot(~A)" name) nil)
(1 (car r))
(t (warning-message 1 "found multiple spot ~A for given name(~A)" r name) (car r)))))
)
となっている.
ロボットもまたcoordinates
クラスの子クラスなので:move-to
メソッドを利用できる.また,このロボットの原点は腰にあるので足が地面に
つくように:locate
メソッドを使って移動する.
(send *robot* :move-to (send *room* :spot "cook-spot") :world)
(send *robot* :locate #f(0 0 550))
現状では*irtviewer*
の画面上でロボットが小さくなっているので,
以下のメソッド利用し,ロボットが画面いっぱいになるように調整する.
(send *irtviewer* :look-all
(geo::make-bounding-box
(flatten (send-all (send *robot* :bodies) :vertices))))
次に環境中の物体を選択する.ここでは:object
メソッドを利用する.
これは,:spots, :spot
と同様の振る舞いをするため,
どのような物体があるかは,(send-all (send *room* :objects) :name)
として知ることができる. room73b2-kettle
の他に
room73b2-mug-cup
やroom73b2-knife
等を利用するとよい.
(setq *kettle* (send *room* :object "room73b2-kettle"))
環境モデルの初期化直後は物体は部屋にassocされているため,以下の用に 親子関係を解消しておく.こうしないと物体を把持するなどの場合に問題が生 じる.
(if (send *kettle* :parent) (send (send *kettle* :parent) :dissoc *kettle*))
ロボットの視線を対象物に向けるためのメソッドとして以下のようなものがあ る.
(send *robot* :head :look-at (send *kettle* :worldpos))
対象物体には,その物体を把持するための利用したらよい座標系が
:handle
メソッドとして記述されている場合がある.このメソッドは
リストを返すため以下の様に(car (send *kettle* :handle))
として
その座標系を知ることができる.この座標がどこにあるか確認するためには
(send (car (send *kettle* :handle)) :draw-on :flush t)
とすると
よい.
したがってこの物体手を伸ばすためには
(send *robot* :larm :inverse-kinematics
(car (send *kettle* :handle))
:link-list (send *robot* :link-list (send *robot* :larm :end-coords :parent))
:move-target (send *robot* :larm :end-coords)
:rotation-axis :z
:debug-view t)
となる.
ここで,ロボットの手先と対象物体の座標系を連結し,
(send *robot* :larm :end-coords :assoc *kettle*)
以下の様にして世界座標系で100[mm]持ち上げることができる.
(send *robot* :larm :move-end-pos #f(0 0 100) :world
:debug-view t :look-at-target t)
:look-at-target
は移動中に首の向きを常に対象を見つづけるようにす
るという指令である.
inverse-kinematicsのtarget-coordsに関数を指定する例¶

Example of Dual Arm InverseKinematics
:inverse-kinematicsの引数target-coordsは``coordinates``クラス以外に
coordinates
クラスを返す関数を指定することができる。
以下に示すプログラムは2つの腕を利用してカクテルをふる動作を行うものである()。
(load "irteus/demo/sample-robot-model.l")
(setq *robot* (instance sample-robot :init))
(setq *obj* (make-cylinder 20 100))
(send *obj* :set-color #f(1 1 0))
(send *robot* :reset-pose)
(objects (list *robot* *obj*))
(send *robot* :inverse-kinematics
(list (make-coords :pos #f(400 0 0)))
:move-target
(list (send *robot* :larm :end-coords))
:link-list
(list (send *robot* :link-list
(send (send *robot* :larm :end-coords) :parent)
(car (send *robot* :larm :links))))
:translation-axis (list t)
:rotation-axis (list nil))
(let* ((cnt 0.0))
(do-until-key
(incf cnt 0.1)
(send *robot* :inverse-kinematics
(list (make-coords :pos (float-vector (+ 400 (* 100 (sin cnt))) (* 50 (cos cnt)) 0))
#'(lambda ()
(send (send (send *robot* :larm :end-coords) :copy-worldcoords)
:translate #f(0 0 100) :local)))
:move-target
(list (send *robot* :larm :end-coords)
(send *robot* :rarm :end-coords))
:link-list
(list (send *robot* :link-list
(send (send *robot* :larm :end-coords) :parent)
(car (send *robot* :larm :links)))
(send *robot* :link-list
(send (send *robot* :rarm :end-coords) :parent)
(car (send *robot* :rarm :links))))
:translation-axis (list :z t)
:rotation-axis (list nil :z))
(send *obj* :newcoords (send (send *robot* :larm :end-coords) :copy-worldcoords))
(send *irtviewer* :draw-objects)))
(list (make-coords :pos (float-vector (+ 400 (* 100 (sin cnt))) (* 50 (cos cnt)) 0))
#'(lambda ()
(send (send (send *robot* :larm :end-coords) :copy-worldcoords)
:translate #f(0 0 100) :local)))
の行で実際にtarget-coordsに関数を指定している。
この例では、まずカクテルを持つ左手の位置を最初に決める。この時に
:translation-axis :z
, :rotation-axis nil
となっているため、
z方向の移動量と回転方向は左手の逆運動学の計算に考慮されない。
そして、決まった左手の位置に対して関数が評価されることで
手先のlocal座標から見てz方向に100の位置に対して右手の位置が決まる。
この時、右手の拘束条件は:translation-axis t
,
:rotation-axis :z
となっ
ているためz方向、つまりカクテルの長さ方向を軸としてその軸に対する回転は許した条
件で逆運動学を解くことになる。
このように、拘束条件を踏まえて逆運動学を解きたい場合にはtarget-coordsを関数とし
て扱うことが必要になる。
重心位置を考慮したfullbody-inverse-kinematicsの例¶

Example of InverseKinematics with root link virtual joint
:fullbody-inverse-kinematicsはロボットの関節に加えてベースリンク仮想ジョイントを駆動した 逆運動学を解く関数である。以下に示すプログラムは、両足を地面に固定し、重心を両足の上に 位置させた状態で、左手を目標に到達させる動作を行うものである。
(load "irteus/demo/sample-robot-model.l")
(setq *robot* (instance sample-robot :init))
(send *robot* :reset-pose)
(setq *obj* (make-cylinder 10 600))
(send *obj* :rotate pi :x)
(send *obj* :set-color #f(1 1 0))
(objects (list *robot* *obj*))
(let* ((rleg-coords (send *robot* :rleg :end-coords :copy-worldcoords))
(lleg-coords (send *robot* :lleg :end-coords :copy-worldcoords)))
(send *robot* :torso :waist-p :joint-angle 10)
(send *robot* :fullbody-inverse-kinematics
(list rleg-coords
lleg-coords
(make-coords :pos (float-vector 400 100 -600)))
:move-target
(list (send *robot* :rleg :end-coords)
(send *robot* :lleg :end-coords)
(send *robot* :larm :end-coords))
:link-list
(list (send *robot* :link-list (send *robot* :rleg :end-coords :parent))
(send *robot* :link-list (send *robot* :lleg :end-coords :parent))
(send *robot* :link-list (send *robot* :larm :end-coords :parent)))
:translation-axis (list t t t)
:rotation-axis (list t t nil)
:target-centroid-pos (midpoint 0.5
(send *robot* :rleg :end-coords :worldpos)
(send *robot* :lleg :end-coords :worldpos))
:cog-translation-axis :z)
(send *obj* :locate (send *robot* :centroid) :world)
(send *irtviewer* :draw-objects))
(list rleg-coords
lleg-coords
(make-coords :pos (float-vector 400 100 -600)))
の行でtarget-coordsに右足、左足、左手の目標位置姿勢を指定している。
右足、左足は動かさないため、現在の座標をコピーしたものを与えている。
このときに、:translation-axis (list t t t)
,
:rotation-axis (list t t nil)
となっているため、右足、左足は位置姿勢を完全に拘束し、左手は姿勢の
回転は許した条件で逆運動学を解くことになる。
:target-centroid-pos (midpoint 0.5 (send *robot* :rleg :end-coords :worldpos)
(send *robot* :lleg :end-coords :worldpos))
:cog-translation-axis :z)
の行では重心の逆運動学を指定している。:cog-translation-axis :z
で
z方向の重心の移動は許した状態で、:target-centroid-pos
で目標重心位置として
両足の中間の座標を与えることによって、重心のxy座標を両足の中間に一致させる
条件のもとで逆運動学を解くことができる。これらの引数は、デフォルト値になっている
ので、省略可能である。
外力を考慮したfullbody-inverse-kinematicsを解く例¶

Example of InverseKinematics with external force
ロボットが外力、外モーメントを受ける場合、外力による足裏まわりのモーメントと 釣り合うようにロボットの重心をオフセットすることによって、バランスをとることができる。 以下に示すプログラムは両手に外力、外モーメントが加わる場合に、両手両足を目標の位置に 到達させかつバランスが取れる姿勢を逆運動学によって求めるものである。
(load "irteus/demo/sample-robot-model.l")
(setq *robot* (instance sample-robot :init))
(send *robot* :reset-pose)
(setq *obj* (make-cylinder 10 600))
(objects (list *robot*))
(let* ((force-list '(#f(-20 0 0) #f(-20 0 0)))
(moment-list '(#f(10 0 0) #f(10 0 0))))
(send *robot* :fullbody-inverse-kinematics
(list (send *robot* :rleg :end-coords :copy-worldcoords)
(send *robot* :lleg :end-coords :copy-worldcoords)
(make-coords :pos #f(400 -300 0))
(make-coords :pos #f(400 300 0)))
:move-target (mapcar #'(lambda (x)
(send *robot* x :end-coords))
(list :rleg :lleg :rarm :larm))
:link-list (mapcar #'(lambda (x)
(send *robot* :link-list (send *robot* x :end-coords :parent)))
(list :rleg :lleg :rarm :larm))
:centroid-offset-func #'(lambda () (send *robot* :calc-static-balance-point
:force-list force-list
:moment-list moment-list))
:target-centroid-pos (midpoint 0.5 (send *robot* :rleg :end-coords :worldpos)
(send *robot* :lleg :end-coords :worldpos))
:cog-translation-axis :z)
(send *irtviewer* :draw-objects)
;; draw force
(mapcar
#'(lambda (f cc)
(let* ((prev-color (send *viewer* :viewsurface :color))
(prev-width (send *viewer* :viewsurface :line-width)))
(send *viewer* :viewsurface :color #F(1 0.3 1))
(send *viewer* :viewsurface :line-width 5)
(send *irtviewer* :viewer :draw-arrow
(send cc :worldpos)
(v+ (send cc :worldpos) (scale 10 f)))
(send *viewer* :viewsurface :color prev-color)
(send *viewer* :viewsurface :line-width prev-width)))
force-list
(list (send *robot* :rarm :end-coords)
(send *robot* :larm :end-coords)))
(send *irtviewer* :viewer :viewsurface :flush)
)
この例では、
:centroid-offset-func #'(lambda () (send *robot* :calc-static-balance-point
:force-list force-list
:moment-list moment-list))
の行で外力、外モーメントを考慮している。force-listは右手に作用する外力と左手に作用する外力のリスト、force-listは右手に作用する外モーメントと左手に作用する外モーメントのリストであり、単位はそれぞれ[N]、[Nm]である。:calc-static-balance-pointは、現在の両手の位置に作用する外力外モーメントと現在の重心の位置に作用する重力に対して釣り合う足裏圧力中心の位置を返す関数である。:centroid-offset-funcはfloat-vector
クラスを返す関数を指定することができ、現在の重心位置の代わりにこの関数の返り値を用いて目標重心位置との距離を縮める逆運動学を解く。:cog-translation-axis :z
でz方向の重心の移動は許した状態で:target-centroid-pos
で目標重心位置として両足の中間の座標を与えることによって、:centroid-offset-funcの返り値、即ち外力に釣り合いがとれる足裏圧力中心のxy座標を、両足の中間に一致させる逆運動学を解くことができる。
ロボットモデル¶
ロボットの身体はリンクとジョイントから構成されるが、それぞれ
bodyset-link
とjoint
クラスを利用しモデル絵を作成する。ロ
ボットの身体はこれらの要素を含んだcascaded-link
という,連結リン
クとしてモデルを生成する.
実際にはjoint
は抽象クラスであり
rotational-joint
,linear-joint
,
wheel-joint
,omniwheel-joint
,
sphere-joint
を選択肢、また四肢を持つロボットの場合は
cascaded-link
ではなくrobot-model
クラスを利用する。
joint
:min-angle &optional v
If v is set, it updates min-angle of this instance. :min-angle returns minimal angle of this joint in degree.
:max-angle &optional v
If v is set, it updates max-angle of this instance. :max-angle returns maximum angle of this joint in degree.
:parent-link &rest args
Returns parent link of this joint. if any arguments is set, it is passed to the parent-link.
:child-link &rest args
Returns child link of this joint. if any arguments is set, it is passed to the child-link.
:joint-dof **
Returns Degree of Freedom of this joint.
:speed-to-angle &rest args
Returns values in deg/mm unit of input value in SI(rad/m) unit.
:angle-to-speed &rest args
Returns values in SI(rad/m) unit of input value in deg/mm unit.
:joint-velocity &optional jv
If jv is set, it updates joint-velocity of this instance. :joint-velocity returns velocity of this joint in SI(m/s, rad/s) unit.
:joint-acceleration &optional ja
If ja is set, it updates joint-acceleration of this instance. :joint-acceleration returns acceleration of this joint in SI(m/\(s^2\), rad/\(s^2\)) unit.
:joint-torque &optional jt
If jt is set, it updates joint-torque of this instance. :joint-torque returns torque of this joint in SI(N, Nm) unit.
:max-joint-velocity &optional mjv
If mjv is set, it updates min-joint-velocity of this instance. :min-joint-velocity returns velocity of this joint in SI(m/s, rad/s) unit.
:max-joint-torque &optional mjt
If mjt is set, it updates min-joint-torque of this instance. :min-joint-torque returns velocity of this joint in SI(N, Nm) unit.
:calc-dav-gain dav i periodic-time
:calc-jacobian &rest args
:joint-min-max-table &optional mm-table
:joint-min-max-target &optional mm-target
:joint-min-max-table-angle-interpolate target-angle min-or-max
:joint-min-max-table-min-angle &optional (target-angle (send joint-min-max-target :joint-angle))
:joint-min-max-table-max-angle &optional (target-angle (send joint-min-max-target :joint-angle))
:max-joint-torque &optional mjt
If mjt is set, it updates min-joint-torque of this instance. :min-joint-torque returns velocity of this joint in SI(N, Nm) unit.
:max-joint-velocity &optional mjv
If mjv is set, it updates min-joint-velocity of this instance. :min-joint-velocity returns velocity of this joint in SI(m/s, rad/s) unit.
:joint-torque &optional jt
If jt is set, it updates joint-torque of this instance. :joint-torque returns torque of this joint in SI(N, Nm) unit.
:joint-acceleration &optional ja
If ja is set, it updates joint-acceleration of this instance. :joint-acceleration returns acceleration of this joint in SI(m/\(s^2\), rad/\(s^2\)) unit.
:joint-velocity &optional jv
If jv is set, it updates joint-velocity of this instance. :joint-velocity returns velocity of this joint in SI(m/s, rad/s) unit.
:angle-to-speed &rest args
Returns values in SI(rad/m) unit of input value in deg/mm unit.
:speed-to-angle &rest args
Returns values in deg/mm unit of input value in SI(rad/m) unit.
:joint-dof **
Returns Degree of Freedom of this joint.
:child-link &rest args
Returns child link of this joint. if any arguments is set, it is passed to the child-link.
:parent-link &rest args
Returns parent link of this joint. if any arguments is set, it is passed to the parent-link.
:max-angle &optional v
If v is set, it updates max-angle of this instance. :max-angle returns maximum angle of this joint in degree.
:min-angle &optional v
If v is set, it updates min-angle of this instance. :min-angle returns minimal angle of this joint in degree.
:joint-min-max-table-max-angle &optional (target-angle (send joint-min-max-target :joint-angle))
:joint-min-max-table-min-angle &optional (target-angle (send joint-min-max-target :joint-angle))
:joint-min-max-table-angle-interpolate target-angle min-or-max
:joint-min-max-target &optional mm-target
:joint-min-max-table &optional mm-table
:calc-jacobian &rest args
:calc-dav-gain dav i periodic-time
rotational-joint
create instance of rotational-joint. :axis is either (:x, :y, :z) or vector. :min-angle and :max-angle takes in radius, but velocity and torque are given in SI units.
Return joint-angle if v is not set, if v is given, set joint angle. v is rotational value in degree.
:joint-dof **
Returns DOF of rotational joint, 1.
:speed-to-angle v
Returns degree of given input in radian
:angle-to-speed v
Returns radian of given input in degree
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian &rest args
:angle-to-speed v
Returns radian of given input in degree
:speed-to-angle v
Returns degree of given input in radian
:joint-dof **
Returns DOF of rotational joint, 1.
Return joint-angle if v is not set, if v is given, set joint angle. v is rotational value in degree.
create instance of rotational-joint. :axis is either (:x, :y, :z) or vector. :min-angle and :max-angle takes in radius, but velocity and torque are given in SI units.
:calc-jacobian &rest args
:calc-angle-speed-gain dav i periodic-time
linear-joint
Create instance of linear-joint. :axis is either (:x, :y, :z) or vector. :min-angle and :max-angle takes in [mm], but velocity and torque are given in SI units.
return joint-angle if v is not set, if v is given, set joint angle. v is linear value in [mm].
:joint-dof **
Returns DOF of linear joint, 1.
:speed-to-angle v
Returns [mm] of given input in [m]
:angle-to-speed v
Returns [m] of given input in [mm]
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian &rest args
:angle-to-speed v
Returns [m] of given input in [mm]
:speed-to-angle v
Returns [mm] of given input in [m]
:joint-dof **
Returns DOF of linear joint, 1.
return joint-angle if v is not set, if v is given, set joint angle. v is linear value in [mm].
Create instance of linear-joint. :axis is either (:x, :y, :z) or vector. :min-angle and :max-angle takes in [mm], but velocity and torque are given in SI units.
:calc-jacobian &rest args
:calc-angle-speed-gain dav i periodic-time
wheel-joint
Create instance of wheel-joint.
return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is (float-vector translation-x[mm] rotation-z[deg])
:joint-dof **
Returns DOF of linear joint, 2.
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:joint-dof **
Returns DOF of linear joint, 2.
return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is (float-vector translation-x[mm] rotation-z[deg])
Create instance of wheel-joint.
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:calc-angle-speed-gain dav i periodic-time
omniwheel-joint
create instance of omniwheel-joint.
return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is (float-vector translation-x[mm] translation-y[mm] rotation-z[deg])
:joint-dof **
Returns DOF of linear joint, 3.
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:joint-dof **
Returns DOF of linear joint, 3.
return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is (float-vector translation-x[mm] translation-y[mm] rotation-z[deg])
create instance of omniwheel-joint.
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:calc-angle-speed-gain dav i periodic-time
sphere-joint
Create instance of sphere-joint. min/max are defind as a region of angular velocity in degree.
:joint-angle-rpy &optional v &key relative
Return joint-angle if v is not set, if v is given, set joint-angle vector by RPY representation, i.e. (float-vector yaw[deg] roll[deg] pitch[deg])
:joint-dof **
Returns DOF of linear joint, 3.
:speed-to-angle dv
Returns degree of given input in radian
:angle-to-speed dv
Returns radian of given input in degree
Return joint-angle if v is not set, if v is given, set joint-angle vector by euler representation.
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
Return joint-angle if v is not set, if v is given, set joint-angle vector by euler representation.
:angle-to-speed dv
Returns radian of given input in degree
:speed-to-angle dv
Returns degree of given input in radian
:joint-dof **
Returns DOF of linear joint, 3.
:joint-angle-rpy &optional v &key relative
Return joint-angle if v is not set, if v is given, set joint-angle vector by RPY representation, i.e. (float-vector yaw[deg] roll[deg] pitch[deg])
Create instance of sphere-joint. min/max are defind as a region of angular velocity in degree.
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:calc-angle-speed-gain dav i periodic-time
6dof-joint
Create instance of 6dof-joint.
Return joint-angle if v is not set, if v is given, set joint angle vector, which is 6D vector of 3D translation[mm] and 3D rotation[deg], i.e. (find-if #’(lambda (x) (eq (send (car x) :name) ’sphere-joint)) (documentation :joint-angle))
:joint-angle-rpy &optional v &key relative
Return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is 6D vector of 3D translation[mm] and 3D rotation[deg], for rotation, please see (find-if #’(lambda (x) (eq (send (car x) :name) ’sphere-joint)) (documentation :joint-angle-rpy))
:joint-dof **
Returns DOF of linear joint, 6.
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:calc-angle-speed-gain dav i periodic-time
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:angle-to-speed dv
Returns SI unit [m/rad] of given input in [mm/deg]
:speed-to-angle dv
Returns [mm/deg] of given input in SI unit [m/rad]
:joint-dof **
Returns DOF of linear joint, 6.
:joint-angle-rpy &optional v &key relative
Return joint-angle if v is not set, if v is given, set joint angle. v is joint-angle vector, which is 6D vector of 3D translation[mm] and 3D rotation[deg], for rotation, please see (find-if #’(lambda (x) (eq (send (car x) :name) ’sphere-joint)) (documentation :joint-angle-rpy))
Return joint-angle if v is not set, if v is given, set joint angle vector, which is 6D vector of 3D translation[mm] and 3D rotation[deg], i.e. (find-if #’(lambda (x) (eq (send (car x) :name) ’sphere-joint)) (documentation :joint-angle))
Create instance of 6dof-joint.
:calc-jacobian fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
:calc-angle-speed-gain dav i periodic-time
bodyset-link
Create instance of bodyset-link.
:worldcoords &optional (level analysis-level)
Returns a coordinates object which represents this coord in the world by concatenating all the cascoords from the root to this coords.
:analysis-level &optional v
Change analysis level :coords only changes kinematics level and :body changes geometry too.
:weight &optional w
Returns a weight of the link. If w is given, set weight.
:centroid &optional c
Returns a centroid of the link. If c is given, set new centroid.
:inertia-tensor &optional i
Returns a inertia tensor of the link. If c is given, set new intertia tensor.
:joint &rest args
Returns a joint associated with this link. If args is given, args are forward to the joint.
:add-joint j
Set j as joint of this link
:del-joint **
Remove current joint of this link
:parent-link **
Returns parent link
:child-links **
Returns child links
:add-child-links l
Add l to child links
:add-parent-link l
Set l as parent link
:del-child-link l
Delete l from child links
:del-parent-link **
Delete parent link
:default-coords &optional c
:del-parent-link **
Delete parent link
:del-child-link l
Delete l from child links
:add-parent-link l
Set l as parent link
:add-child-links l
Add l to child links
:child-links **
Returns child links
:parent-link **
Returns parent link
:del-joint **
Remove current joint of this link
:add-joint j
Set j as joint of this link
:joint &rest args
Returns a joint associated with this link. If args is given, args are forward to the joint.
:inertia-tensor &optional i
Returns a inertia tensor of the link. If c is given, set new intertia tensor.
:centroid &optional c
Returns a centroid of the link. If c is given, set new centroid.
:weight &optional w
Returns a weight of the link. If w is given, set weight.
:analysis-level &optional v
Change analysis level :coords only changes kinematics level and :body changes geometry too.
:worldcoords &optional (level analysis-level)
Returns a coordinates object which represents this coord in the world by concatenating all the cascoords from the root to this coords.
Create instance of bodyset-link.
:default-coords &optional c
cascaded-link
Create cascaded-link.
:init-ending **
This method is to called finalize the instantiation of the cascaded-link. This update bodies and child-link and parent link from joint-list
:links &rest args
Returns links, or args is passed to links
:joint-list &rest args
Returns joint list, or args is passed to joints
:link name
Return a link with given name.
:joint name
Return a joint with given name.
:end-coords name
Returns end-coords with given name
:bodies &rest args
Return bodies of this object. If args is given it passed to all bodies
:faces **
Return faces of this object.
:angle-vector &optional vec (angle-vector (instantiate float-vector (calc-target-joint-dimension joint-list)))
Returns angle-vector of this object, if vec is given, it updates angles of all joint. If given angle-vector violate min/max range, the value is modified.
:link-list to &optional from
Find link list from to link to from link.
:plot-joint-min-max-table joint0 joint1
Plot joint min max table on Euslisp window.
:calc-jacobian-for-interlocking-joints link-list &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
:calc-vel-for-interlocking-joints link-list &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
Calculate 0 velocity for keeping interlocking joint at the same joint angle.
:set-midpoint-for-interlocking-joints &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
Set interlocking joints at mid point of each joint angle.
:interlocking-joint-pairs **
Check if all interlocking joint pairs are same values.
:update-descendants &rest args
:find-link-route to &optional from
:make-joint-min-max-table l0 l1 joint0 joint1 &key (fat 0) (fat2 nil) (debug nil) (margin 0.0) (overwrite-collision-model nil)
:make-min-max-table-using-collision-check l0 l1 joint0 joint1 joint-range0 joint-range1 min-joint0 min-joint1 fat fat2 debug margin
:plot-joint-min-max-table-common joint0 joint1
:calc-target-axis-dimension rotation-axis translation-axis
:calc-union-link-list link-list
:calc-target-joint-dimension link-list
:calc-inverse-jacobian jacobi &rest args &key ((:manipulability-limit ml) 0.1) ((:manipulability-gain mg) 0.001) weight debug-view ret wmat tmat umat umat2 mat-tmp mat-tmp-rc tmp-mrr tmp-mrr2 &allow-other-keys
:calc-gradh-from-link-list link-list &optional (res (instantiate float-vector (length link-list)))
:calc-joint-angle-speed union-vel &rest args &key angle-speed (angle-speed-blending 0.5) jacobi jacobi# null-space i-j#j debug-view weight wmat tmp-len tmp-len2 fik-len &allow-other-keys
:calc-joint-angle-speed-gain union-link-list dav periodic-time
:collision-avoidance-links &optional l
:collision-avoidance-link-pair-from-link-list link-lists &key obstacles ((:collision-avoidance-links collision-links) collision-avoidance-links) debug
:collision-avoidance-calc-distance &rest args &key union-link-list (warnp t) ((:collision-avoidance-link-pair pair-list)) ((:collision-distance-limit distance-limit) 10) &allow-other-keys
:collision-avoidance-args pair link-list
:collision-avoidance &rest args &key avoid-collision-distance avoid-collision-joint-gain avoid-collision-null-gain ((:collision-avoidance-link-pair pair-list)) (union-link-list) (link-list) (weight) (fik-len (send self :calc-target-joint-dimension union-link-list)) debug-view &allow-other-keys
:move-joints union-vel &rest args &key union-link-list (periodic-time 0.05) (joint-args) (debug-view nil) (move-joints-hook) &allow-other-keys
:find-joint-angle-limit-weight-old-from-union-link-list union-link-list
:reset-joint-angle-limit-weight-old union-link-list
:calc-weight-from-joint-limit avoid-weight-gain fik-len link-list union-link-list debug-view weight tmp-weight tmp-len
:calc-inverse-kinematics-weight-from-link-list link-list &key (avoid-weight-gain 1.0) (union-link-list (send self :calc-union-link-list link-list)) (fik-len (send self :calc-target-joint-dimension union-link-list)) (weight (fill (instantiate float-vector fik-len) 1)) (additional-weight-list) (debug-view) (tmp-weight (instantiate float-vector fik-len)) (tmp-len (instantiate float-vector fik-len))
:calc-nspace-from-joint-limit avoid-nspace-gain union-link-list weight debug-view tmp-nspace
:calc-inverse-kinematics-nspace-from-link-list link-list &key (avoid-nspace-gain 0.01) (union-link-list (send self :calc-union-link-list link-list)) (fik-len (send self :calc-target-joint-dimension union-link-list)) (null-space) (debug-view) (additional-nspace-list) (cog-gain 0.0) (target-centroid-pos) (centroid-offset-func) (cog-translation-axis :z) (cog-null-space nil) (weight (fill (instantiate float-vector fik-len) 1.0)) (update-mass-properties t) (tmp-nspace (instantiate float-vector fik-len))
:inverse-kinematics-args &rest args &key union-link-list rotation-axis translation-axis additional-jacobi-dimension &allow-other-keys
:draw-collision-debug-view **
:ik-convergence-check success dif-pos dif-rot rotation-axis translation-axis thre rthre centroid-thre target-centroid-pos centroid-offset-func cog-translation-axis &key (update-mass-properties t)
:calc-vel-from-pos dif-pos translation-axis &rest args &key (p-limit 100.0) (tmp-v0 (instantiate float-vector 0)) (tmp-v1 (instantiate float-vector 1)) (tmp-v2 (instantiate float-vector 2)) (tmp-v3 (instantiate float-vector 3)) &allow-other-keys
:calc-vel-from-rot dif-rot rotation-axis &rest args &key (r-limit 0.5) (tmp-v0 (instantiate float-vector 0)) (tmp-v1 (instantiate float-vector 1)) (tmp-v2 (instantiate float-vector 2)) (tmp-v3 (instantiate float-vector 3)) &allow-other-keys
:collision-check-pairs &key ((:links ls) (cons (car links) (all-child-links (car links))))
:self-collision-check &key (mode :all) (pairs (send self :collision-check-pairs)) (collision-func ’collision-check)
:plot-joint-min-max-table joint0 joint1
Plot joint min max table on Euslisp window.
:link-list to &optional from
Find link list from to link to from link.
:angle-vector &optional vec (angle-vector (instantiate float-vector (calc-target-joint-dimension joint-list)))
Returns angle-vector of this object, if vec is given, it updates angles of all joint. If given angle-vector violate min/max range, the value is modified.
:faces **
Return faces of this object.
:bodies &rest args
Return bodies of this object. If args is given it passed to all bodies
:end-coords name
Returns end-coords with given name
:joint name
Return a joint with given name.
:link name
Return a link with given name.
:joint-list &rest args
Returns joint list, or args is passed to joints
:links &rest args
Returns links, or args is passed to links
:init-ending **
This method is to called finalize the instantiation of the cascaded-link. This update bodies and child-link and parent link from joint-list
Create cascaded-link.
:plot-joint-min-max-table-common joint0 joint1
:make-min-max-table-using-collision-check l0 l1 joint0 joint1 joint-range0 joint-range1 min-joint0 min-joint1 fat fat2 debug margin
:make-joint-min-max-table l0 l1 joint0 joint1 &key (fat 0) (fat2 nil) (debug nil) (margin 0.0) (overwrite-collision-model nil)
:find-link-route to &optional from
:update-descendants &rest args
Check if all interlocking joint pairs are same values.
:interlocking-joint-pairs **
:set-midpoint-for-interlocking-joints &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
Set interlocking joints at mid point of each joint angle.
:calc-vel-for-interlocking-joints link-list &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
Calculate 0 velocity for keeping interlocking joint at the same joint angle.
:calc-jacobian-for-interlocking-joints link-list &key (interlocking-joint-pairs (send self :interlocking-joint-pairs))
:self-collision-check &key (mode :all) (pairs (send self :collision-check-pairs)) (collision-func ’collision-check)
:collision-check-pairs &key ((:links ls) (cons (car links) (all-child-links (car links))))
:calc-vel-from-rot dif-rot rotation-axis &rest args &key (r-limit 0.5) (tmp-v0 (instantiate float-vector 0)) (tmp-v1 (instantiate float-vector 1)) (tmp-v2 (instantiate float-vector 2)) (tmp-v3 (instantiate float-vector 3)) &allow-other-keys
:calc-vel-from-pos dif-pos translation-axis &rest args &key (p-limit 100.0) (tmp-v0 (instantiate float-vector 0)) (tmp-v1 (instantiate float-vector 1)) (tmp-v2 (instantiate float-vector 2)) (tmp-v3 (instantiate float-vector 3)) &allow-other-keys
:ik-convergence-check success dif-pos dif-rot rotation-axis translation-axis thre rthre centroid-thre target-centroid-pos centroid-offset-func cog-translation-axis &key (update-mass-properties t)
:draw-collision-debug-view **
:inverse-kinematics-args &rest args &key union-link-list rotation-axis translation-axis additional-jacobi-dimension &allow-other-keys
:calc-inverse-kinematics-nspace-from-link-list link-list &key (avoid-nspace-gain 0.01) (union-link-list (send self :calc-union-link-list link-list)) (fik-len (send self :calc-target-joint-dimension union-link-list)) (null-space) (debug-view) (additional-nspace-list) (cog-gain 0.0) (target-centroid-pos) (centroid-offset-func) (cog-translation-axis :z) (cog-null-space nil) (weight (fill (instantiate float-vector fik-len) 1.0)) (update-mass-properties t) (tmp-nspace (instantiate float-vector fik-len))
:calc-nspace-from-joint-limit avoid-nspace-gain union-link-list weight debug-view tmp-nspace
:calc-inverse-kinematics-weight-from-link-list link-list &key (avoid-weight-gain 1.0) (union-link-list (send self :calc-union-link-list link-list)) (fik-len (send self :calc-target-joint-dimension union-link-list)) (weight (fill (instantiate float-vector fik-len) 1)) (additional-weight-list) (debug-view) (tmp-weight (instantiate float-vector fik-len)) (tmp-len (instantiate float-vector fik-len))
:calc-weight-from-joint-limit avoid-weight-gain fik-len link-list union-link-list debug-view weight tmp-weight tmp-len
:reset-joint-angle-limit-weight-old union-link-list
:find-joint-angle-limit-weight-old-from-union-link-list union-link-list
:move-joints union-vel &rest args &key union-link-list (periodic-time 0.05) (joint-args) (debug-view nil) (move-joints-hook) &allow-other-keys
:collision-avoidance &rest args &key avoid-collision-distance avoid-collision-joint-gain avoid-collision-null-gain ((:collision-avoidance-link-pair pair-list)) (union-link-list) (link-list) (weight) (fik-len (send self :calc-target-joint-dimension union-link-list)) debug-view &allow-other-keys
:collision-avoidance-args pair link-list
:collision-avoidance-calc-distance &rest args &key union-link-list (warnp t) ((:collision-avoidance-link-pair pair-list)) ((:collision-distance-limit distance-limit) 10) &allow-other-keys
:collision-avoidance-link-pair-from-link-list link-lists &key obstacles ((:collision-avoidance-links collision-links) collision-avoidance-links) debug
:collision-avoidance-links &optional l
:calc-joint-angle-speed-gain union-link-list dav periodic-time
:calc-joint-angle-speed union-vel &rest args &key angle-speed (angle-speed-blending 0.5) jacobi jacobi# null-space i-j#j debug-view weight wmat tmp-len tmp-len2 fik-len &allow-other-keys
:calc-gradh-from-link-list link-list &optional (res (instantiate float-vector (length link-list)))
:calc-inverse-jacobian jacobi &rest args &key ((:manipulability-limit ml) 0.1) ((:manipulability-gain mg) 0.001) weight debug-view ret wmat tmat umat umat2 mat-tmp mat-tmp-rc tmp-mrr tmp-mrr2 &allow-other-keys
:calc-target-joint-dimension link-list
:calc-union-link-list link-list
:calc-target-axis-dimension rotation-axis translation-axis
eusmodel-validity-check robot
Check if the robot model is validate
calc-jacobian-default-rotate-vector paxis world-default-coords child-reverse transform-coords tmp-v3 tmp-m33
calc-jacobian-rotational fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
calc-jacobian-linear fik row column joint paxis child-link world-default-coords child-reverse move-target transform-coords rotation-axis translation-axis tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33
calc-angle-speed-gain-scalar j dav i periodic-time
calc-angle-speed-gain-vector j dav i periodic-time
all-child-links s &optional (pred #’identity)
calc-dif-with-axis dif axis &optional tmp-v0 tmp-v1 tmp-v2
calc-target-joint-dimension joint-list
calc-joint-angle-min-max-for-limit-calculation j kk jamm
joint-angle-limit-weight j-l &optional (res (instantiate float-vector (calc-target-joint-dimension j-l)))
joint-angle-limit-nspace j-l &optional (res (instantiate float-vector (calc-target-joint-dimension j-l)))
calc-jacobian-from-link-list-including-robot-and-obj-virtual-joint link-list move-target obj-move-target robot &key (rotation-axis ’(t t)) (translation-axis ’(t t)) (fik (make-matrix (send robot :calc-target-axis-dimension rotation-axis translation-axis) (send robot :calc-target-joint-dimension link-list)))
append-obj-virtual-joint link-list target-coords &key (joint-class 6dof-joint) (joint-args) (vplink) (vplink-coords) (vclink-coords)
append-multiple-obj-virtual-joint link-list target-coords &key (joint-class ’(6dof-joint)) (joint-args ’(nil)) (vplink) (vplink-coords) (vclink-coords)
eusmodel-validity-check-one robot
line
:worldcoords **
Return a coordinates on the midpoint of the end points
coordinates
:difference-rotation coords &key (geometry::rotation-axis t)
return difference in rotation of given coords, rotation-axis can take (:x, :y, :z, :xx, :yy, :zz, :xm, :ym, :zm)
:difference-position coords &key (geometry::translation-axis t)
return difference in position of given coords, translation-axis can take (:x, :y, :z, :xy, :yz, :zx).
:axis geometry::axis
coordinates
:move-coords geometry::target geometry::at
fix ’at’ coords on ’self’ to ’target’
:transform geometry::c &optional (geometry::wrt :local)
:transformation geometry::c2 &optional (geometry::wrt :local)
:move-to geometry::c &optional (geometry::wrt :local) &aux geometry::cc
cascaded-coords
coordinates
cascaded-coords
coordinates
cascaded-coords
bodyset
Create bodyset object
:bodies &rest args
:faces **
:worldcoords **
:draw-on &rest args
Create bodyset object
:draw-on &rest args
:worldcoords **
:faces **
:bodies &rest args
midcoords geometry::p geometry::c1 geometry::c2
Returns mid (or p) coordinates of given two cooridnates c1 and c2
orient-coords-to-axis geometry::target-coords geometry::v &optional (geometry::axis :z) (geometry::eps epsilon)
geometry::face-to-triangle-aux geometry::f
triangulate the face.
geometry::face-to-triangle geometry::f
convert face to set of triangles.
geometry::face-to-tessel-triangle geometry::f geometry::num &optional (epsilon1.000000e-10)
return polygon if triangable, return nil if it is not.
body-to-faces geometry::abody
return triangled faces of given body
make-sphere geometry::r &rest args
make sphere of given r
make-ring geometry::ring-radius geometry::pipe-radius &rest args &key (geometry::segments 16)
make ring of given ring and pipe radius
x-of-cube geometry::cub
return x of cube.
y-of-cube geometry::cub
return y of cube.
z-of-cube geometry::cub
return z of cube.
height-of-cylinder geometry::cyl
return height of cylinder.
radius-of-cylinder geometry::cyl
return radius of cylinder.
radius-of-sphere geometry::sp
return radius of shape.
geometry::make-faceset-from-vertices geometry::vs
create faceset from vertices.
matrix-to-euler-angle geometry::m geometry::axis-order
return euler angle from matrix.
geometry::quaternion-from-two-vectors geometry::a geometry::b
Comupute quaternion which rotate vector a into b.
transform-coords geometry::c1 geometry::c2 &optional (geometry::c3 (let ((geometry::dim (send geometry::c1 :dimension))) (instance coordinates :newcoords (unit-matrix geometry::dim) (instantiate float-vector geometry::dim))))
geometry::face-to-triangle-rest-polygon geometry::f geometry::num geometry::edgs
geometry::face-to-triangle-make-simple geometry::f
body-to-triangles geometry::abody &optional (geometry::limit 50)
geometry::triangle-to-triangle geometry::aface &optional (geometry::limit 50)
robot-model
:camera sensor-name
Returns camera with given name
:force-sensor sensor-name
Returns force sensor with given name
:imu-sensor sensor-name
Returns imu sensor of given name
:force-sensors **
Returns force sensors.
:imu-sensors **
Returns imu sensors.
:cameras **
Returns camera sensors.
:look-at-hand l/r
look at hand position, l/r supports :rarm, :larm, :arms, and ’(:rarm :larm)
:look-at-target look-at-target &key (target-coords)
move robot head to look at targets, look-at-target support t/nil float-vector coordinates, center of list of float-vector or list of coordinates
:init-pose **
Set robot to initial posture.
Returns torque vector
Calculates end-effector force and moment from joint torques.
:print-vector-for-robot-limb vec
:foot-midcoords &optional (mid 0.5)
:gen-footstep-parameter &key (ratio 1.0)
Generate footstep parameter
Calculate foot step list from goal x position [mm], goal y position [mm], and goal yaw orientation [deg].
:go-pos-quadruped-params->footstep-list xx yy th &key (type :crawl)
Calculate foot step list for quadruped walking from goal x position [mm], goal y position [mm], and goal yaw orientation [deg].
:support-polygons **
Return support polygons.
:support-polygon name
:make-default-linear-link-joint-between-attach-coords attach-coords-0 attach-coords-1 end-coords-name linear-joint-name
:init-ending **
:rarm-end-coords **
:larm-end-coords **
:rleg-end-coords **
:lleg-end-coords **
:head-end-coords **
:torso-end-coords **
:rarm-root-link **
:larm-root-link **
:rleg-root-link **
:lleg-root-link **
:head-root-link **
:torso-root-link **
:limb limb method &rest args
:inverse-kinematics-loop-for-look-at limb &rest args
:gripper limb &rest args
:get-sensor-method sensor-type sensor-name
:get-sensors-method-by-limb sensors-type limb
:larm &rest args
:rarm &rest args
:lleg &rest args
:rleg &rest args
:head &rest args
:torso &rest args
:arms &rest args
:legs &rest args
:distribute-total-wrench-to-torque-method-default **
:joint-angle-limit-nspace-for-6dof &key (avoid-nspace-gain 0.01) (limbs ’(:rleg :lleg))
:joint-order limb &optional jname-list
:draw-gg-debug-view end-coords-list contact-state rz cog pz czmp dt
:footstep-parameter **
:make-support-polygons **
:make-sole-polygon name
:print-vector-for-robot-limb vec
Calculates end-effector force and moment from joint torques.
Returns torque vector
:init-pose **
Set robot to initial posture.
:look-at-target look-at-target &key (target-coords)
move robot head to look at targets, look-at-target support t/nil float-vector coordinates, center of list of float-vector or list of coordinates
:look-at-hand l/r
look at hand position, l/r supports :rarm, :larm, :arms, and ’(:rarm :larm)
:cameras **
Returns camera sensors.
:imu-sensors **
Returns imu sensors.
:force-sensors **
Returns force sensors.
:imu-sensor sensor-name
Returns imu sensor of given name
:force-sensor sensor-name
Returns force sensor with given name
:camera sensor-name
Returns camera with given name
:joint-order limb &optional jname-list
:joint-angle-limit-nspace-for-6dof &key (avoid-nspace-gain 0.01) (limbs ’(:rleg :lleg))
:distribute-total-wrench-to-torque-method-default **
:legs &rest args
:arms &rest args
:torso &rest args
:head &rest args
:rleg &rest args
:lleg &rest args
:rarm &rest args
:larm &rest args
:get-sensors-method-by-limb sensors-type limb
:get-sensor-method sensor-type sensor-name
:gripper limb &rest args
:inverse-kinematics-loop-for-look-at limb &rest args
:limb limb method &rest args
:torso-root-link **
:head-root-link **
:lleg-root-link **
:rleg-root-link **
:larm-root-link **
:rarm-root-link **
:torso-end-coords **
:head-end-coords **
:lleg-end-coords **
:rleg-end-coords **
:larm-end-coords **
:rarm-end-coords **
:init-ending **
:make-default-linear-link-joint-between-attach-coords attach-coords-0 attach-coords-1 end-coords-name linear-joint-name
:support-polygon name
:support-polygons **
Return support polygons.
:go-pos-quadruped-params->footstep-list xx yy th &key (type :crawl)
Calculate foot step list for quadruped walking from goal x position [mm], goal y position [mm], and goal yaw orientation [deg].
Calculate foot step list from goal x position [mm], goal y position [mm], and goal yaw orientation [deg].
:gen-footstep-parameter &key (ratio 1.0)
Generate footstep parameter
:foot-midcoords &optional (mid 0.5)
:make-sole-polygon name
:make-support-polygons **
:footstep-parameter **
:draw-gg-debug-view end-coords-list contact-state rz cog pz czmp dt
make-default-robot-link len radius axis name &optional extbody
センサモデル¶
sensor-model
:init shape &key name &allow-other-keys
:draw-sensor v
:read **
:simulate model
:signal rawinfo
:profile &optional p
bumper-model
Create bumper model, b is the shape of an object and bt is the threshold in distance[mm].
:simulate objs
Simulate bumper, with given objects, return 1 if the sensor detects an object and 0 if not.
:draw vwer
:draw-sensor vwer
:simulate objs
Simulate bumper, with given objects, return 1 if the sensor detects an object and 0 if not.
Create bumper model, b is the shape of an object and bt is the threshold in distance[mm].
:draw-sensor vwer
:draw vwer
camera-model
Create camera model. b is the shape of an object
:create-viewer &optional cv &key (no-window nil)
Create camera viewer, or set viewer
:width **
Returns width of the camera in pixel.
:height **
Returns height of the camera in pixel.
:fovy **
Returns field of view in degree
:cx **
Returns center x.
:cy **
Returns center y.
:fx **
Returns focal length of x.
:fy **
Returns focal length of y.
:screen-point pos
Returns point in screen corresponds to the given pos.
:3d-point x y d
Returns 3d position
:ray x y
Returns ray vector of given x and y.
Draw camera raw in irtviewer, ex (send cam :draw-on :flush t)
:draw-objects objs
Draw objects in camera viewer, expected type of objs is list of objects
Get image objects you need to call :draw-objects before calling this function
:select-drawmode mode objs
Change drawmode for drawing with :draw-objects methods. mode is symbol of mode, ’hid is symbol for hidden line mode, the other symbols indicate default mode. objs is the same objects using :draw-objects.
:viewing &rest args
:image-viewer &rest args
:draw-sensor vwer &key flush (width 1) (color (float-vector 1 1 1))
:draw-objects-raw vwr objs
:get-image-raw vwr &key (points) (colors)
:select-drawmode mode objs
Change drawmode for drawing with :draw-objects methods. mode is symbol of mode, ’hid is symbol for hidden line mode, the other symbols indicate default mode. objs is the same objects using :draw-objects.
Get image objects you need to call :draw-objects before calling this function
:draw-objects objs
Draw objects in camera viewer, expected type of objs is list of objects
Draw camera raw in irtviewer, ex (send cam :draw-on :flush t)
:ray x y
Returns ray vector of given x and y.
:3d-point x y d
Returns 3d position
:screen-point pos
Returns point in screen corresponds to the given pos.
:fy **
Returns focal length of y.
:fx **
Returns focal length of x.
:cy **
Returns center y.
:cx **
Returns center x.
:fovy **
Returns field of view in degree
:height **
Returns height of the camera in pixel.
:width **
Returns width of the camera in pixel.
:create-viewer &optional cv &key (no-window nil)
Create camera viewer, or set viewer
Create camera model. b is the shape of an object
:get-image-raw vwr &key (points) (colors)
:draw-objects-raw vwr objs
:draw-sensor vwer &key flush (width 1) (color (float-vector 1 1 1))
:image-viewer &rest args
:viewing &rest args
Create camera object from given parameters.
環境モデル¶
scene-model
Create scene model
:objects **
Returns objects in the scene.
:add-objects objects
Add objects to scene with identifiable names. Returns all objects.
:add-object obj
Add object to scene with identifiable name. Returns all objects.
:remove-objects objs-or-names
Remove objects or objects with given names from scene. Returns removed objects.
:remove-object obj-or-name
Remove object or object with given name from scene. Returns removed object.
:find-object name
Returns objects with given name.
:add-spots spots
Add spots to scene with identifiable names. All spots will be :assoc with this scene. Returns T if added spots successfly, otherwise returns NIL.
:add-spot spot
Add spot to scene with identifiable name. The spot will be :assoc with this scene. Returns T if spot is added successfly, otherwise returns NIL.
:remove-spots spots
Remove spots from this scene. All spots will be :dissoc with this scene. Returns removed spots.
:remove-spot spot
Remove spot from scene. the spot will be :dissoc with this scene. Returns removed spot.
:spots **
Return all spots in the scene.
:object name
Return an object of given name.
:spot name
Return a spot of given name.
:bodies **
:spot name
Return a spot of given name.
:object name
Return an object of given name.
:spots **
Return all spots in the scene.
:remove-spot spot
Remove spot from scene. the spot will be :dissoc with this scene. Returns removed spot.
:remove-spots spots
Remove spots from this scene. All spots will be :dissoc with this scene. Returns removed spots.
:add-spot spot
Add spot to scene with identifiable name. The spot will be :assoc with this scene. Returns T if spot is added successfly, otherwise returns NIL.
:add-spots spots
Add spots to scene with identifiable names. All spots will be :assoc with this scene. Returns T if added spots successfly, otherwise returns NIL.
:find-object name
Returns objects with given name.
:remove-object obj-or-name
Remove object or object with given name from scene. Returns removed object.
:remove-objects objs-or-names
Remove objects or objects with given names from scene. Returns removed objects.
:add-object obj
Add object to scene with identifiable name. Returns all objects.
:add-objects objects
Add objects to scene with identifiable names. Returns all objects.
:objects **
Returns objects in the scene.
Create scene model
:bodies **
動力学計算・歩行動作生成¶
歩行動作生成¶
歩行動作は予見制御を用いて生成される。文献 [15] [16] [17]_に述べられている式や文章を引用しつつ、説明する。
歩行動作は以下の手順で生成される。
- 脚の逆運動学が解ける範囲内の歩幅で、ロボットが足をつく位置と時間を計画する。
- 地面についていない足は、次につく位置までサイクロイド補間する。
- ZMPが地面についている足の位置とできる限り一致するような重心軌道を生成する。
- 計画された足と重心の軌道を満たすような関節角度軌道を逆運動学によって逐次求める。
ここでは、3の手順について詳しく説明する。
X方向の運動について、始めに次のような制御系を考える。Y方向の運動についても同様に議論することが可能である。
\(x\)はロボットの重心位置、\(u\)は重心の加速度の時間微分(jerk)、\(p\)はZMPである。
次に、このシステムを次のような拡大系に置き換える。
こののシステムに対して、次のコスト関数を最小化するような制御入力を求める。
まず、十分大きい自然数\(M\)を用いて次のコスト関数を考え、次に\(M \rightarrow \infty\)とすることでを最小化する制御入力を得る。
\(J_k^M\)の最小値を\(J_k^{M\ast}\)とすると、から次の関係が成り立つ。
これを用いて、の右辺を\(\Delta u_k\)で偏微分した値が0であることから、次の式を得る。
境界条件を考えると、は\(k = M\)において\(J_{k+M}^{M\ast} = 0\)であるから、\(k = M\)においてが任意の\(x_{M}^\ast\)で恒等的に成り立つ条件を考えて、\(P_{M}^M = 0\)、\(\theta_{M}^M = 0\)、\(\phi_{M}^M = 0\)である。したがって、十分小さい\(j\)において\(P_{k+j}^M\)はの定常解\(P\)となり、次の式を満たす。
以後、\(M \rightarrow \infty\)として考える。自然数\(N\)を考えて、\(j > N\)において\(p_{k+j}^{ref} = p_{k+N}^{ref}\)と仮定すると、は次のように表せる。(は十分小さい\(j\)における\(P_{k+j}\)でのみ成り立たつが、十分大きな\(j\)では\((\tilde{A} - \tilde{b} K)^{T j} \rightarrow 0\)と仮定し無視した。)(\(K \equiv (\tilde{b}^T P \tilde{b} + R )^{-1} \tilde{b}^T P \tilde{A}\)とおいた。)
となる。ここで\(\tilde{A} = \left[\begin{array}{c c} 1 & cA\\ 0 & A \end{array} \right]\)、\(\tilde{c} = \left[\begin{array}{c c c c} 1 & 0 & 0 & 0 \end{array} \right]\)を利用すると、の第1列目の等式から、
を得る。このをに代入することで、を最小化する最適制御入力\(\Delta u_k\)が得られる。
初期状態\(x_1^\ast\)と目標ZMP軌道\(p_{1}^{ref},~p_{2}^{ref},~\cdots\)が与えられれば、とのシステムによって\(\Delta u_1,~x_2^\ast,~\Delta u_2,~x_3^\ast,~\cdots\)が順次求まる。これによって、ZMPが地面についている足の位置とできる限り一致するような重心軌道を生成することができる。
歩行動作生成の例¶

Example of walk pattern generation
robot-model
クラスには、オフライン歩行動作生成を行い歩行軌道を返す関数:calc-walk-pattern-from-footstep-listが定義されている。この関数は、1歩ごとの足をつく位置のリストを与えると、ZMPがこの位置に出来る限り近くなるような歩行動作を生成する。以下に示すプログラムは、:calc-walk-pattern-from-footstep-listを用いて歩行動作生成を行うものである()。
(load "irteus/demo/sample-robot-model.l")
(setq *robot* (instance sample-robot :init))
(send *robot* :reset-pose)
(send *robot* :fix-leg-to-coords (make-coords))
(objects (list *robot*))
(let ((footstep-list
(list (make-coords :coords (send *robot* :rleg :end-coords :copy-worldcoords) :name :rleg)
(make-coords :coords (send (send *robot* :lleg :end-coords :copy-worldcoords)
:translate #f(100 0 0)) :name :lleg)
(make-coords :coords (send (send *robot* :rleg :end-coords :copy-worldcoords)
:translate #f(200 0 0)) :name :rleg)
(make-coords :coords (send (send *robot* :lleg :end-coords :copy-worldcoords)
:translate #f(300 0 0)) :name :lleg)
(make-coords :coords (send (send *robot* :rleg :end-coords :copy-worldcoords)
:translate #f(400 0 0)) :name :rleg)
(make-coords :coords (send (send *robot* :lleg :end-coords :copy-worldcoords)
:translate #f(400 0 0)) :name :lleg))))
(objects (append (list *robot*) footstep-list))
(send *robot* :calc-walk-pattern-from-footstep-list
footstep-list
:default-step-height 50
:default-step-time 1.0
:dt 0.1
:debug-view t)
)
変数footstep-list
に足をつく位置のリストをセットし、:calc-walk-pattern-from-footstep-listに与えている。footstep-list
の各要素は、:name
にいずれの脚かを指定する必要がある。footstep-list
の最初の要素は初期化のために用いられ、実際にロボットが脚を踏み出すのは次の要素以降の位置に対してである。:default-step-height 50
では遊脚をサイクロイド補間するときの高さを50[mm]に指定している。:default-step-time 1.0
は一歩あたりの時間を1.0[s]に指定している。:dt 0.1
は予見制御のサンプリングタイムと生成される軌道の間隔を0.1[s]に指定している。なお、:default-step-height
、:default-step-time
、:dt
はデフォルト値がこの値となっているため、実際にはこれらの値を設定する必要はない。
次に示すプログラムは、移動したい目的地を与えるとfootstep-list
を自動で生成して歩行動作生成を行うものである。
(load "irteus/demo/sample-robot-model.l")
(setq *robot* (instance sample-robot :init))
(send *robot* :reset-pose)
(send *robot* :fix-leg-to-coords (make-coords))
(objects (list *robot*
(apply #'midcoords 0.5 (send *robot* :legs :end-coords))
(send (send (apply #'midcoords 0.5 (send *robot* :legs :end-coords))
:translate #F(500 150 0)) :rotate (deg2rad 45) :z)))
(send *robot* :calc-walk-pattern-from-footstep-list
(send *robot* :go-pos-params->footstep-list
500 150 45) ;; x[mm] y[mm] th[deg]
:debug-view t
)
footstep-list
として(send *robot* :go-pos-params->footstep-list 500 150 45)
の返り値を与えて、先の例と同様:calc-walk-pattern-from-footstep-list
関数で歩行動作を生成している。
:go-pos-params->footstep-list
関数は、2本足で立ったロボットについて、脚の逆運動学が解ける範囲内で現在の位置から目的地までのfootstep-list
を生成する関数であり、ここでは前に500[mm]、左に150[mm]移動し、左に45[deg]体を回転させるようなfootstep-list
を生成している。
joint
rotational-joint
linear-joint
omniwheel-joint
sphere-joint
6dof-joint
bodyset-link
cascaded-link
joint
rotational-joint
linear-joint
bodyset-link
cascaded-link
:inertia-tensor &optional (update-mass-properties t)
:centroid &optional (update-mass-properties t)
:weight &optional (update-mass-properties t)
:preview-control-dynamics-filter dt avs &key (preview-controller-class preview-controller) (cog-method :move-base-pos) (delay 0.8)
:draw-torque vwer &key flush (width 2) (size 100) (color (float-vector 1 0.3 0)) (warning-color (float-vector 1 0 0)) (torque-threshold nil) (torque-vector (send self :torque-vector)) ((:joint-list jlist) (send self :joint-list))
:calc-contact-wrenches-from-total-wrench target-pos-list &key (total-wrench) (weight (fill (instantiate float-vector (6 (length target-pos-list))) 1))
:wrench-list->wrench-vector wrench-list
:wrench-vector->wrench-list wrench-vector
:calc-cop-from-force-moment force moment sensor-coords cop-coords &key (fz-thre 1) (return-all-values)
:calc-torque-from-ext-wrenches &key (force-list) (moment-list) (target-coords) ((:jacobi tmp-jacobi))
:calc-av-vel-acc-from-pos dt av
:calc-root-coords-vel-acc-from-pos dt root-coords
:calc-torque-from-vel-acc &key (debug-view nil) (jvv (instantiate float-vector (length joint-list))) (jav (instantiate float-vector (length joint-list))) (root-spacial-velocity (float-vector 0 0 0)) (root-angular-velocity (float-vector 0 0 0)) (root-spacial-acceleration (float-vector 0 0 0)) (root-angular-acceleration (float-vector 0 0 0)) (calc-torque-buffer-args (send self :calc-torque-buffer-args))
:calc-torque-without-ext-wrench &key (debug-view nil) (calc-statics-p t) (dt 0.005) (av (send self :angle-vector)) (root-coords (send (car (send self :links)) :copy-worldcoords)) (calc-torque-buffer-args (send self :calc-torque-buffer-args))
:calc-torque &key (debug-view nil) (calc-statics-p t) (dt 0.005) (av (send self :angle-vector)) (root-coords (send (car (send self :links)) :copy-worldcoords)) (force-list) (moment-list) (target-coords) (calc-torque-buffer-args (send self :calc-torque-buffer-args))
:calc-torque-buffer-args **
:torque-ratio-vector &rest args &key (torque (sendself :torque-vector args))
:max-torque-vector **
riccati-equation
:solve **
:init aa bb cc qq rr
preview-controller
:update-xk p &optional (add-data)
:finishedp **
Finished or not.
:last-reference-output-vector **
:current-reference-output-vector **
:current-state-vector **
Current state value (xk).
:current-output-vector **
Current output value (yk).
:current-additional-data **
:pass-preview-controller reference-output-vector-list
Get preview controller results from reference-output-vector-list and returns list.
:calc-f **
:calc-u **
:calc-xk **
:pass-preview-controller reference-output-vector-list
Get preview controller results from reference-output-vector-list and returns list.
:current-additional-data **
:current-output-vector **
Current output value (yk).
:current-state-vector **
Current state value (xk).
:current-reference-output-vector **
:last-reference-output-vector **
:finishedp **
Finished or not.
:update-xk p &optional (add-data)
:calc-xk **
:calc-u **
:calc-f **
extended-preview-controller
:current-output-vector **
:calc-f **
:calc-u **
:calc-xk **
:current-output-vector **
:calc-xk **
:calc-u **
:calc-f **
preview-control-cart-table-cog-trajectory-generator
:refcog **
Reference COG [mm].
:cart-zmp **
Cart-table system ZMP[mm] as an output variable.
:last-refzmp **
Reference zmp at the last of queue.
:current-refzmp **
Current reference zmp at the first of queue.
:update-xk p &optional (add-data)
:finishedp **
Finished or not.
:current-additional-data **
Current additional data value.
:pass-preview-controller reference-output-vector-list
Get preview controller results from reference-output-vector-list and returns list.
:cog-z **
COG Z [mm].
:update-cog-z zc
:cog-z **
COG Z [mm].
:pass-preview-controller reference-output-vector-list
Get preview controller results from reference-output-vector-list and returns list.
:current-additional-data **
Current additional data value.
:finishedp **
Finished or not.
:update-xk p &optional (add-data)
:current-refzmp **
Current reference zmp at the first of queue.
:last-refzmp **
Reference zmp at the last of queue.
:cart-zmp **
Cart-table system ZMP[mm] as an output variable.
:refcog **
Reference COG [mm].
:update-cog-z zc
gait-generator
:cycloid-midcoords ratio start goal height &key (top-ratio 0.5) (rot-ratio ratio)
:cycloid-midpoint ratio start goal height &key (top-ratio 0.5)
:solve-av-by-move-centroid-on-foot support-leg support-leg-coords swing-leg-coords cog robot &rest args &key (cog-gain 3.5) (stop 100) (additional-nspace-list) &allow-other-keys
:solve-angle-vector support-leg support-leg-coords swing-leg-coords cog &key (solve-angle-vector :solve-av-by-move-centroid-on-foot) (solve-angle-vector-args)
:update-current-gait-parameter **
:proc-one-tick &key (type :shuffling) (solve-angle-vector :solve-av-by-move-centroid-on-foot) (solve-angle-vector-args) (debug nil)
:calc-one-tick-gait-parameter type
:calc-current-refzmp prev cur next
:calc-ratio-from-double-support-ratio **
:calc-current-swing-leg-coords ratio src dst &key (type :shuffling) (step-height default-step-height)
:calc-hoffarbib-pos-vel-acc tmp-remain-time tmp-goal old-acc old-vel old-pos
:make-gait-parameter **
:finalize-gait-parameter **
:initialize-gait-parameter fsl time cog &key ((:default-step-height dsh) 50) ((:default-double-support-ratio ddsr) 0.2) (delay 1.6) ((:all-limbs al) ’(:rleg :lleg)) ((:default-zmp-offsets dzo) (mapcan #’(lambda (x) (list x (float-vector 0 0 0))) al)) (q 1.0) (r 1.000000e-06) (thre 1) (rthre (deg2rad 1)) (start-with-double-support t) ((:end-with-double-support ewds) t)
:get-swing-limbs limbs
:get-limbs-zmp limb-coords limb-names
:get-limbs-zmp-list limb-coords limb-names
:get-counter-footstep-limbs fs
:get-footstep-limbs fs
:init rb _dt
calc-inertia-matrix-rotational mat row column paxis m-til c-til i-til axis-for-angular child-link world-default-coords translation-axis rotation-axis tmp-v0 tmp-v1 tmp-v2 tmp-va tmp-vb tmp-vc tmp-vd tmp-m
calc-inertia-matrix-linear mat row column paxis m-til c-til i-til axis-for-angular child-link world-default-coords translation-axis rotation-axis tmp-v0 tmp-v1 tmp-v2 tmp-va tmp-vb tmp-vc tmp-vd tmp-m
[1] | Inverse kinematic solutions with singularity robustness for robot manipulator control: Y.Nakamura and H. Hanafusa, Journal of Dynamic Systems, Measurement, and Control, vol. 108, pp 163-171, 1986 |
[2] | ロボットアームの可操作度, 吉川恒夫, 日本ロボット学会誌, vol. 2, no. 1, pp. 63-67, 1984. |
[3] | Hybrid Position/Force Control: A Correct Formuration, William D. Fisher, M. Shahid Mujtaba, The Internationaltional Journal of Robotics Research, vol. 11, no. 4, pp. 299-311, 1992. |
[4] | A unified approach for motion and force control of robot manipulators: The operational space formulation, O. Khatib, IEEE Journal of Robotics and Automation, vol. 3, no. 1, pp. 43-53, 1987. |
[5] | Exploiting Task Intervals for Whole Body Robot Control, Michael Gienger and Herbert Jansen and Christian Goeric In Proceedings of the 2006 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS’06), pp. 2484 - 2490, 2006 |
[6] | A weighted least-norm solution based scheme for avoiding jointlimits for redundant joint manipulators, Tan Fung Chan and Dubey R.V., Robotics and Automation, IEEE Transactions on, pp. 286-292,1995 |
[7] | Efficient gradient projection optimization for manipulators withmultiple degrees of redundancy, Zghal H., Dubey R.V., Euler J.A., 1990 IEEE International Conference on Robotics and Automation, pp. 1006-1011, 1990. |
[8] | Real-Time Self Collision Avoidance for Humanoids by means of Nullspace Criteria and Task Intervals, H. Sugiura, M. Gienger, H. Janssen, C. Goerick, Proceedings of the 2006 IEEE-RAS International Conference on Humanoid Robots, pp. 575-580, 2006. |
[9] | Real-time collision avoidance with whole body motion control for humanoid robots, Hisashi Sugiura, Michael Gienger, Herbert Janssen, Christian Goerick, In Proceedings of the 2007 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS’07), pp. 2053 - 2068, 2007 |
[10] | Fast distance queries with rectangular swept sphere volumes, Larsen E., Gottschalk S., Lin M.C., Manocha D, Proceedings of The 2000 IEEE International Conference on Robotics and Automation, pp. 3719-3726, 2000. |
[11] | アーム・多指ハンド機構による把握と操り, 永井 清, 吉川 恒夫, 日本ロボット学会誌, vol. 13, no. 7, pp. 994-1005, 1995. |
[12] | 一般化ヤコビ行列を用いた宇宙用ロボットマニピュレータの分解速度制御, 梅谷 陽二, 吉田 和哉, 日本ロボット学会誌, vol. 4, no. 7, pp. 63-73, 1989. |
[13] | Control of Free-Floating Humanoid Robots Through Task Prioritization, Luis Sentis and Oussama Khatib, Proceedings of The 2005 IEEE International Conference on Robotics and Automation, pp. 1718-1723, 2005 |
[14] | Resolved Momentum Control:Humanoid Motion Planning based on the Linear and Angular Momentum, S.Kajita, F.Kanehiro, K.Kaneko, K.Fujiwara, K.Harada, K.Yokoi,H.Hirukawa, In Proceedings of the 2003 IEEE/RSJ International Conference on Intelligent Robots and Systems (IROS’03), pp. 1644-1650, 2003 |
[15] | Humanoid Robot (in Japanese), Shuji Kajita, Ohmsha, 2005, ISBN 4-274-20058-2 |
[16] | Biped Walking Pattern Generation by using Preview Control of Zero-Moment Point, Shuji Kajita and Fumio Kanehiro and Kenji Kaneko and Kiyoshi Fujiwara and Kensuke Harada and Kazuhito Yokoi and Hirohisa Hirukawa, ICRA 2003, p.1620-1626, 2006 |
[17] | 最適予見制御と一般化予測制御, 江上 正 and土谷 武士, 計測と制御, 39 巻, 5 号, p.337-342, 2000 |
ロボットビューワ¶
デフォルトのIrtviewerを作成する().
(make-irtviewer)

Default irtviewer
Irtviewerを作成して,xy平面のグリッドを描画する().
(make-irtviewer)
(send *irtviewer* :draw-floor 100)
(send *irtviewer* :draw-objects)

Irtviewer with floor grid
Irtviewerを作成して,背景を白にして,xy平面のグリッドを黒で描画する().
(make-irtviewer)
(send *irtviewer* :change-background (float-vector 1 1 1))
(send *irtviewer* :draw-floor 100)
(send *irtviewer* :floor-color #f(0 0 0))
(send *irtviewer* :draw-objects)

Irtviewer with white background and floor grid
viewer
x::irtviewer
:draw-origin &optional (x::tmp-draw-origin :null)
get/set draw-origin
:draw-floor &optional (x::tmp-draw-floor :null)
get/set draw-floor
:floor-color &optional (x::tmp-floor-color :null)
get/set floor-color
:logging &optional (x::flag :on)
:save-image x::filename
save curent view to image, supported formats are jpg/png/pnm
:create &rest args &key (x::title IRT viewer) (x::view-name (gensym title)) (x::hither 200.0) (x::yon 50000.0) (x::width 500) (x::height 500) ((:draw-origin do) 150) ((:draw-floor x::df) nil) ((:floor-color x::fc) #f(1.0 1.0 1.0)) (x::call-super t) &allow-other-keys
:viewer &rest args
:redraw **
:expose x:event
:resize x::newwidth x::newheight
:configurenotify x:event
:viewtarget &optional x::p
:viewpoint &optional x::p
:look1 &optional (x::vt x::viewtarget) (x::lra x::left-right-angle) (x::uda x::up-down-angle)
:look-all &optional x::bbox
:move-viewing-around-viewtarget x:event x::x x::y x::dx x::dy x::vwr
:set-cursor-pos-event x:event
:move-coords-event x:event
:draw-event x:event
:draw-objects &rest args
:objects &rest args
:select-drawmode x::mode
:flush **
:change-background x::col
:clear-log **
:push-image **
:clear-image-sequence **
:image-sequence **
:floor-color &optional (x::tmp-floor-color :null)
get/set floor-color
:draw-floor &optional (x::tmp-draw-floor :null)
get/set draw-floor
:draw-origin &optional (x::tmp-draw-origin :null)
get/set draw-origin
:change-background x::col
:flush **
:select-drawmode x::mode
:objects &rest args
:draw-objects &rest args
:draw-event x:event
:move-coords-event x:event
:set-cursor-pos-event x:event
:move-viewing-around-viewtarget x:event x::x x::y x::dx x::dy x::vwr
:look-all &optional x::bbox
:look1 &optional (x::vt x::viewtarget) (x::lra x::left-right-angle) (x::uda x::up-down-angle)
:viewpoint &optional x::p
:viewtarget &optional x::p
:configurenotify x:event
:resize x::newwidth x::newheight
:expose x:event
:redraw **
:viewer &rest args
:create &rest args &key (x::title IRT viewer) (x::view-name (gensym title)) (x::hither 200.0) (x::yon 50000.0) (x::width 500) (x::height 500) ((:draw-origin do) 150) ((:draw-floor x::df) nil) ((:floor-color x::fc) #f(1.0 1.0 1.0)) (x::call-super t) &allow-other-keys
:save-image x::filename
save curent view to image, supported formats are jpg/png/pnm
:logging &optional (x::flag :on)
:image-sequence **
:clear-image-sequence **
:push-image **
:clear-log **
viewing
viewer-dummy
:nomethod &rest args
irtviewer-dummy
:nomethod &rest args
:objects &rest args
irtviewer-no-window
:nomethod &rest args
:resize newwidth newheight
:create &rest args
:init &rest args
make-irtviewer &rest args
x::make-lr-ud-coords x::lra x::uda
x::make-mpeg-from-images x::mpgfile x::images &key (delete t) (x::delay 1)
x::make-animgif-from-images x::giffile x::images &key (delete t) x::transparent (loop t) (x::delay 10) (x::background 000000)
x::draw-things x::objs
objects &optional (objs t) vw
make-irtviewer-dummy &rest args
geometry::default-pixmapsurface &rest args
make-irtviewer-no-window &rest args
干渉計算¶
干渉計算の概要¶
干渉計算は2組の幾何モデルが交差するかを判定しその距離を求める処理である. 主に以下の2つ機能を提供する.
- 2つのモデルが交差するかを判定する衝突検出 (collision-check関数)
- 2つのモデル間の最短距離を算出する距離計算 (collision-distance関数)
irteusでは,他言語インターフェースを介して外部ライブラリを呼び出すことで干渉計算を実行する. 外部ライブラリとして,PQPとBulletの呼び出しが実装されており,デフォルトではPQPが利用される. 以下のように,select-collision-algorithm関数により使用するライブラリを切り替えることができる.
(select-collision-algorithm *collision-algorithm-pqp*) ;; use PQP
(select-collision-algorithm *collision-algorithm-bullet*) ;; use Bullet
個々の外部ライブラリの特徴については以降で詳しく説明する. 他の干渉計算ソフトウェアパッケージについては http://gamma.cs.unc.edu/research/collision/に詳しい.(情報が古い可能性があるので注意.例えばBulletは載っていない.)
cascaded-coords
:make-collisionmodel &rest args &key &allow-other-keys
Make collision model and save pointer.
collision-distance model1 model2 &rest args &key &allow-other-keys
collision-check model1 model2 &rest args
collision-check-objects obj1 obj2 &rest args &key &allow-other-keys
select-collision-algorithm alg
物体形状モデル同士の干渉計算例¶
以下は,collision-checkやcollision-distanceを利用して,2つの立方体の衝突検出と距離計算を行い,最近点どうしを結ぶ線分を描画する例である. 干渉が生じているときにcollision-distance関数で得られる最近点は,PQPとBulletで仕様が異なる.詳しくは以降のBulletに関する説明を参照.
;; Make models
(setq *b0* (make-cube 100 100 100))
(setq *b1* (make-cube 100 100 100))
;; Case 1 : no collision
(send *b0* :newcoords (make-coords :pos #f(100 100 -100)
:rpy (list (deg2rad 10) (deg2rad -20) (deg2rad 30))))
(objects (list *b0* *b1*))
(print (collision-check *b0* *b1*)) ;; Check collision
(let ((ret (collision-distance *b0* *b1*))) ;; Check distance and nearest points
(print (car ret)) ;; distance
(send (cadr ret) :draw-on :flush nil :size 20 :color #f(1 0 0)) ;; nearest point on *b0*
(send (caddr ret) :draw-on :flush nil :size 20 :color #f(1 0 0)) ;; nearest point on *b1*
(send *irtviewer* :viewer :draw-line (cadr ret) (caddr ret))
(send *irtviewer* :viewer :viewsurface :flush))
;; Case 2 : collision
(send *b0* :newcoords (make-coords :pos #f(50 50 -50)
:rpy (list (deg2rad 10) (deg2rad -20) (deg2rad 30))))
(objects (list *b0* *b1*))
(print (collision-check *b0* *b1*)) ;; Check collision
(let ((ret (collision-distance *b0* *b1*))) ;; Check distance and nearest points
(print (car ret)) ;; distance
;; In case of collision, nearest points are insignificant values.
(send (cadr ret) :draw-on :flush nil :size 20 :color #f(1 0 0)) ;; nearest point on *b0*
(send (caddr ret) :draw-on :flush nil :size 20 :color #f(1 0 0)) ;; nearest point on *b1*
(send *irtviewer* :viewer :draw-line (cadr ret) (caddr ret))
(send *irtviewer* :viewer :viewsurface :flush))

Collision detection
ロボット動作と干渉計算¶
ハンドで物体をつかむ,という動作の静的なシミュレーションを行う場合に手(指)のリンクと対象物体の干渉を調べ,これが起こるところで物体をつかむ動作を停止させるということが出来る.
(load "irteus/demo/sample-arm-model.l")
(setq *sarm* (instance sarmclass :init))
(send *sarm* :reset-pose)
(setq a 42)
(send *sarm* :move-fingers a)
(setq *target* (make-cube 30 30 30))
(send *target* :translate #f(350 200 400))
(objects (list *sarm* *target*))
(send *sarm* :inverse-kinematics *target* :move-target (send *sarm* :end-coords) :debug-view t)
(while (> a 0)
(if (collision-check-objects
(list (send *sarm* :joint-fr :child-link)
(send *sarm* :joint-fl :child-link))
(list *target*))
(return))
(decf a 0.1)
(send *irtviewer* :draw-objects)
(send *sarm* :move-fingers a))
(send *sarm* :end-coords :assoc *target*)
(dotimes (i 100)
(send *sarm* :joint0 :joint-angle 1 :relative t)
(send *irtviewer* :draw-objects))
(send *sarm* :end-coords :dissoc *target*)
(dotimes (i 100)
(send *sarm* :joint0 :joint-angle -1 :relative t)
(send *irtviewer* :draw-objects))
同様の機能が,“irteus/demo/sample-arm-model.l”ファイルの:open-hand, :close-handというメソッドで提供されている.
PQPによる干渉計算¶
PQPはノースカロライナ大学のLin氏らのグループにより開発された干渉計算ライブラリである. PQPソフトウェアパッケージの使い方はirteus/PQP/README.txtに 書いてあり,irteus/PQP/src/PQP.hを読むことで理解できるようになっている.
irteusでPQPを使うためのファイルは CPQP.C, euspqp.c, pqp.l からなる. 2つの幾何モデルが衝突してしるか否かを判定するためには,
(defun pqp-collision-check (model1 model2
&optional (flag PQP_FIRST_CONTACT) &key (fat 0) (fat2 nil))
(let ((m1 (get model1 :pqpmodel)) (m2 (get model2 :pqpmodel))
(r1 (send model1 :worldrot)) (t1 (send model1 :worldpos))
(r2 (send model2 :worldrot)) (t2 (send model2 :worldpos)))
(if (null fat2) (setq fat2 fat))
(if (null m1) (setq m1 (send model1 :make-pqpmodel :fat fat)))
(if (null m2) (setq m2 (send model2 :make-pqpmodel :fat fat2)))
(pqpcollide r1 t1 m1 r2 t2 m2 flag)))
を呼び出せば良い. r1,r1,r2,t1はそれぞれの物体の並進ベクトル,回転行列となり, (get model1 :pqpmodel)でPQPの幾何モデルへのポインタを参照する. このポインタは:make-pqpmodelメソッドの中で以下のよう計算される.
(defmethod cascaded-coords
(:make-pqpmodel
(&key (fat 0))
(let ((m (pqpmakemodel))
vs v1 v2 v3 (id 0))
(setf (get self :pqpmodel) m)
(pqpbeginmodel m)
(dolist (f (send self :faces))
(dolist (poly (face-to-triangle-aux f))
(setq vs (send poly :vertices)
v1 (send self :inverse-transform-vector (first vs))
v2 (send self :inverse-transform-vector (second vs))
v3 (send self :inverse-transform-vector (third vs)))
(when (not (= fat 0))
(setq v1 (v+ v1 (scale fat (normalize-vector v1)))
v2 (v+ v2 (scale fat (normalize-vector v2)))
v3 (v+ v3 (scale fat (normalize-vector v3)))))
(pqpaddtri m v1 v2 v3 id)
(incf id)))
(pqpendmodel m)
m)))
ここでは,まず(pqpmakemodel)が呼び出されている. pqpmakemodelの中では,euqpqp.cで定義されている,
pointer PQPMAKEMODEL(register context *ctx, int n, register pointer *argv)
{
int addr = PQP_MakeModel();
return makeint(addr);
}
が呼び出されており,これは,CPQP.Cの
PQP\_Model *PQP_MakeModel()
{
return new PQP_Model();
}
が呼ばれている.PQP_Model()はPQP.hで定義されているものであり, この様にしてeuslisp内の関数が実際のPQPライブラリの関数に渡されてい る以降,(pqpbeginmodel m)でPQPの幾何モデルのインスタンスを作成し, (pqpaddtri m v1 v2 v3 id)として面情報を登録している.
cascaded-coords
pqp-collision-check-objects geometry::obj1 geometry::obj2 &key (geometry::fat 0.2)
return nil or t
Bulletによる干渉計算¶
Bulletは物理演算エンジンであり,その一部として干渉計算機能が提供されている. irteusでBulletを使うためのファイルは CBULLET.cpp, eusbullet.c, bullet.l からなる. 関数内部の呼び出し順序はPQPと同様である.
PQPとBulletの違いとして以下が挙げられる.
- 干渉が生じているときにcollision-distanceを呼ぶと,PQPでは,距離として0が返り,最近点として意味のない点が返される.一方Bulletでは,距離として干渉をなくすために動かすべき最短距離(penetration depthと呼ばれる)が返る.また,最近点としては,干渉をなくすための最短距離の両端の点が返される.
- PQPは非凸のメッシュモデルをそのまま扱うことができるが,Bulletでは非凸のモデルの凸包を内部で計算しそれを扱っている.
cascaded-coords
Make bullet model and save pointer of the bullet model.
Make bullet model from body.
BVHデータ¶
bvh-link
:init name typ offst chs parent children
create link for bvh model
:type **
:offset **
:channels **
:init name typ offst chs parent children
create link for bvh model
:channels **
:offset **
:type **
bvh-sphere-joint
create joint for bvh model
:joint-angle-bvh &optional v
:joint-angle-bvh-offset &optional v
:joint-angle-bvh-impl v bvh-offset
:axis-order **
:bvh-offset-rotation **
create joint for bvh model
:bvh-offset-rotation **
:axis-order **
:joint-angle-bvh-impl v bvh-offset
:joint-angle-bvh-offset &optional v
:joint-angle-bvh &optional v
bvh-6dof-joint
:bvh-offset-rotation **
:axis-order **
:joint-angle-bvh-impl v bvh-offset
:joint-angle-bvh-offset &optional v
:joint-angle-bvh &optional v
:init &rest args &key (order (list :x :y :z :z :x :y)) ((:scale scl)) ((:bvh-offset-rotation bvh-rotation) (unit-matrix 3)) &allow-other-keys
bvh-robot-model
create robot model for bvh model
:make-bvh-link tree &key parent ((:scale scl))
:angle-vector &optional vec (angle-vector (instantiate float-vector (calc-target-joint-dimension joint-list)))
:dump-joints links &key (depth 0) (strm standard-output)
:dump-hierarchy &optional (strm standard-output)
:dump-motion &optional (strm standard-output)
:copy-state-to robot
:fix-joint-angle i limb joint-name joint-order a
:fix-joint-order jo limb
:bvh-offset-rotate name
:init-end-coords **
:init-root-link **
create robot model for bvh model
:bvh-offset-rotate name
:fix-joint-order jo limb
:fix-joint-angle i limb joint-name joint-order a
:copy-state-to robot
:dump-motion &optional (strm standard-output)
:dump-hierarchy &optional (strm standard-output)
:dump-joints links &key (depth 0) (strm standard-output)
:angle-vector &optional vec (angle-vector (instantiate float-vector (calc-target-joint-dimension joint-list)))
:make-bvh-link tree &key parent ((:scale scl))
motion-capture-data
:animate &rest args &key (start 0) (step 1) (end (send self :frame-length)) (interval 20) &allow-other-keys
:frame-length **
:frame &optional f
:animation &rest args
:model &rest args
:init fname &key (coords (make-coords)) ((:scale scl))
:init-root-link **
:init-end-coords **
rikiya-bvh-robot-model
:copy-state-to robot
:copy-joint-to robot limb joint &optional (sign 1)
:head-neck &rest args
:torso-chest &rest args
:rleg-ankle &rest args
:rleg-knee &rest args
:rleg-crotch &rest args
:lleg-ankle &rest args
:lleg-knee &rest args
:lleg-crotch &rest args
:rarm-wrist &rest args
:rarm-elbow &rest args
:rarm-shoulder &rest args
:rarm-collar &rest args
:larm-wrist &rest args
:larm-elbow &rest args
:larm-shoulder &rest args
:larm-collar &rest args
:init &rest args
tum-bvh-robot-model
:init &rest args
cmu-bvh-robot-model
:init &rest args
read-bvh fname &key scale
read bvh file
load motion capture data
rikiya-bvh2eus fname &rest args
cmu-bvh2eus fname &rest args
tum-bvh2eus fname &rest args
parse-bvh-sexp src &key ((:scale scl))
make-bvh-robot-model bvh-data &rest args
rikiya-file &key (num 1) (cls ’a)
tum-kitchen-file &key (num 1) (cls 0)
cmu-mocap-file &key (num 1) (cls 1)
Colladaデータ¶
collada::eusmodel-description collada::model
convert a ‘model’ to eusmodel-description
collada::eusmodel-link-specs collada::links
convert ‘links’ to <link-specs>
collada::eusmodel-joint-specs collada::joints
convert ‘joints’ to <joint-specs>
collada::eusmodel-description->collada name collada::description &key (scale 0.001)
convert eusmodel-descrption to collada sxml
collada::matrix->collada-rotate-vector collada::mat
convert a rotation matrix to axis-angle.
convert-irtmodel-to-collada collada::model-file &optional (collada::output-full-dir (send (truename ./) :namestring)) (collada::model-name) (collada::exit-p t)
convert irtmodel to collada model. (convert-irtmodel-to-collada irtmodel-file-path &optional (output-full-dir (send (truename ”./”) :namestring)) (model-name))
collada::symbol->string collada::sym
collada::->string collada::val
collada::string-append &rest args
collada::make-attr collada::l collada::ac
collada::make-xml collada::x collada::bef collada::aft
collada::sxml->xml collada::sxml
collada::xml-output-to-string-stream collada::ss collada::l
collada::cat-normal collada::l collada::s
collada::cat-clark collada::l collada::s collada::i
collada::verificate-unique-strings names
collada::eusmodel-link-spec collada::link
collada::eusmodel-mesh-spec collada::link collada::rt-cds
collada::eusmodel-joint-spec collada::_joint
collada::eusmodel-limit-spec collada::_joint
collada::eusmodel-endcoords-specs collada::model
collada::eusmodel-link-description collada::description
collada::eusmodel-joint-description collada::description
collada::eusmodel-endcoords-description collada::description
collada::setup-collada-filesystem collada::obj-name collada::base-dir
collada::range2 collada::n
eus2collada collada::obj collada::full-root-dir &key (scale 0.001) (collada::file-suffix .dae)
collada::collada-node-id collada::link-descrption
collada::collada-node-name collada::link-descrption
collada::links-description->collada-library-materials collada::links-desc
collada::link-description->collada-materials collada::link-desc
collada::mesh-description->collada-material collada::mat collada::effect
collada::links-description->collada-library-effects collada::links-desc
collada::link-description->collada-effects collada::link-desc
collada::mesh-description->collada-effect collada::mesh id
collada::matrix->collada-string collada::mat
collada::find-parent-liks-from-link-description collada::target-link collada::desc
collada::eusmodel-description->collada-node-transformations collada::target-link collada::desc
collada::eusmodel-description->collada-node collada::target-link collada::desc
collada::eusmodel-description->collada-library-visual-scenes name collada::desc
collada::mesh-description->instance-material collada::s
collada::link-description->collada-bind-material collada::link
collada::eusmodel-description->collada-library-kinematics-scenes name collada::desc
collada::eusmodel-description->collada-library-kinematics-models name collada::desc
collada::eusmodel-description->collada-kinematics-model name collada::desc
collada::eusmodel-description->collada-library-physics-scenes name collada::desc
collada::eusmodel-description->collada-library-physics-models name collada::desc
collada::find-root-link-from-joints-description collada::joints-description
collada::find-link-from-links-description name collada::links-description
collada::eusmodel-description->collada-links collada::description
collada::find-joint-from-link-description collada::target collada::joints
collada::find-child-link-descriptions collada::parent collada::links collada::joints
collada::eusmodel-description->collada-library-articulated-systems collada::desc name
collada::eusmodel-endcoords-description->openrave-manipulator collada::end-coords collada::description
collada::eusmodel-description->collada-links-tree collada::target collada::links collada::joints
collada::joints-description->collada-instance-joints collada::joints-desc
collada::joint-description->collada-instance-joint collada::joint-desc
collada::eusmodel-description->collada-library-joints collada::description
collada::joints-description->collada-joints collada::joints-description
collada::collada-joint-id collada::joint-description
collada::joint-description->collada-joint collada::joint-description
collada::linear-joint-description->collada-joint collada::joint-description
collada::rotational-joint-description->collada-joint collada::joint-description
collada::eusmodel-description->collada-scene collada::description
collada::eusmodel-description->collada-library-geometries collada::description
collada::collada-geometry-id-base collada::link-descrption
collada::collada-geometry-name-base collada::link-descrption
collada::links-description->collada-geometries collada::links-description
collada::mesh-object->collada-mesh collada::mesh id
collada::link-description->collada-geometry collada::link-description
collada::mesh->collada-indices collada::mesh
collada::mesh-vertices->collada-string collada::mesh
collada::mesh-normals->collada-string collada::mesh
collada::float-vector->collada-string collada::v
collada::enum-integer-list collada::n
collada::search-minimum-rotation-matrix collada::mat
collada::estimate-class-name collada::model-file
collada::remove-directory-name fname
ポイントクラウドデータ¶
pointcloud
Create point cloud object
:size-change &optional wd ht
change width and height, this method does not change points data
:points &optional pts wd ht
replace points, pts should be list of points or n\(times\) matrix
:colors &optional cls
replace colors, cls should be list of points or n\(times\) matrix
:normals &optional nmls
replace normals by, nmls should be list of points or n\(times\)3 matrix
:point-list &optional (remove-nan)
return list of points
:color-list **
return list of colors
:normal-list **
return list of normals
:centroid **
retrun centroid of this point cloud
:append point-list &key (create t)
downsample points with step
:copy-from pc
update object by pc
:transform-points coords &key (create)
:convert-to-world &key (create)
transform points and normals with self coords. converted points data should be at the same position as displayed
:move-origin-to neworigin &key (create)
origin of point cloud is moved to neworigin. moved points data should be at the same position as displayed
:reset-box **
:box **
:vertices **
:size **
:width **
:height **
:view-coords &optional vc
:curvatures &optional curv
:curvature-list **
:set-color col &optional (_transparent)
:point-color &optional pc
:point-size &optional ps
:axis-length &optional al
:axis-width &optional aw
:clear-color **
:clear-normal **
:nfilter &rest args
:viewangle-inlier &key (min-z 0.0) (hangle 44.0) (vangle 35.0)
:image-position-inlier &key (ipkey) (height 144) (width 176) (cy (/ (float (- height 1)) 2)) (cx (/ (float (- width 1)) 2)) negative
:image-circle-filter dist &key (height 144) (width 176) (cy (/ (float (- height 1)) 2)) (cx (/ (float (- width 1)) 2)) create negative
:step-inlier step offx offy
:generate-color-histogram-hs &key (h-step 9) (s-step 7) (hlimits (cons 360.0 0.0)) (vlimits (cons 1.0 0.15)) (slimits (cons 1.0 0.25)) (rotate-hue) (color-scale 255.0) (sizelimits 1)
:set-offset cds &key (create)
:drawnormalmode &optional mode
:transparent &optional trs
:draw vwer
:move-origin-to neworigin &key (create)
origin of point cloud is moved to neworigin. moved points data should be at the same position as displayed
:convert-to-world &key (create)
transform points and normals with self coords. converted points data should be at the same position as displayed
:transform-points coords &key (create)
:copy-from pc
update object by pc
downsample points with step
:append point-list &key (create t)
:centroid **
retrun centroid of this point cloud
:normal-list **
return list of normals
:color-list **
return list of colors
:point-list &optional (remove-nan)
return list of points
:normals &optional nmls
replace normals by, nmls should be list of points or n\(times\)3 matrix
:colors &optional cls
replace colors, cls should be list of points or n\(times\) matrix
:points &optional pts wd ht
replace points, pts should be list of points or n\(times\) matrix
:size-change &optional wd ht
change width and height, this method does not change points data
Create point cloud object
:draw vwer
:transparent &optional trs
:drawnormalmode &optional mode
:set-offset cds &key (create)
:generate-color-histogram-hs &key (h-step 9) (s-step 7) (hlimits (cons 360.0 0.0)) (vlimits (cons 1.0 0.15)) (slimits (cons 1.0 0.25)) (rotate-hue) (color-scale 255.0) (sizelimits 1)
:step-inlier step offx offy
:image-circle-filter dist &key (height 144) (width 176) (cy (/ (float (- height 1)) 2)) (cx (/ (float (- width 1)) 2)) create negative
:image-position-inlier &key (ipkey) (height 144) (width 176) (cy (/ (float (- height 1)) 2)) (cx (/ (float (- width 1)) 2)) negative
:viewangle-inlier &key (min-z 0.0) (hangle 44.0) (vangle 35.0)
:nfilter &rest args
:clear-normal **
:clear-color **
:axis-width &optional aw
:axis-length &optional al
:point-size &optional ps
:point-color &optional pc
:set-color col &optional (_transparent)
:curvature-list **
:curvatures &optional curv
:view-coords &optional vc
:height **
:width **
:size **
:vertices **
:box **
:reset-box **
make-random-pointcloud &key (num 1000) (with-color) (with-normal) (scale 100.0)
グラフ表現¶
node
:image &optional im
:unlink n
:remove-all-arcs **
:remove-arc a
:add-arc a
:successors **
:arc-list **
:init n &optional image
arc
:prin1 &optional (strm t) &rest msgs
:to **
:from **
:init from_ to_
directed-graph
:write-to-dot-stream &optional (strm standard-output) result-path (title output)
:write-to-dot fname &optional result-path (title output)
:write-to-file basename &optional result-path title (type pdf)
:write-to-pdf fname &optional result-path (title (string-right-trim .pdf fname))
:write-to-png fname &optional result-path (title (string-right-trim .png fname))
:original-draw-mode **
change draw-mode to original mode
:current-draw-mode **
change draw-mode to latest mode
:draw-both-arc &optional (bothq :both)
change draw-mode, if true is set, draw bidirectional arc as two arcs
:draw-arc-label &optional (writeq :write)
change draw-mode, if true is set, draw label(name) of arcs
:draw-merged-result &optional (mergeq :merge)
change draw-mode, if true is set, draw result arc as red. if not, draw red arc independently
:init **
:successors node &rest args
:node name
:nodes &optional arg
:add-node n
:remove-node n
:clear-nodes **
:add-arc-from-to from to
:remove-arc arc
:adjacency-matrix **
:adjacency-list **
:adjacency-list **
:adjacency-matrix **
:remove-arc arc
:add-arc-from-to from to
:clear-nodes **
:remove-node n
:add-node n
:nodes &optional arg
:node name
:successors node &rest args
:init **
costed-arc
:cost **
:init from to c
costed-graph
:path-cost from arc to
:add-arc-from-to from to cost &key (both nil)
:add-arc from to cost &key (both nil)
graph
:add-arc-from-to from to &key (both nil)
:add-arc from to &key (both nil)
:goal-state &optional arg
:start-state &optional arg
:path-cost from arc to
:goal-test gs
:draw-merged-result &optional (mergeq :merge)
change draw-mode, if true is set, draw result arc as red. if not, draw red arc independently
:draw-arc-label &optional (writeq :write)
change draw-mode, if true is set, draw label(name) of arcs
:draw-both-arc &optional (bothq :both)
change draw-mode, if true is set, draw bidirectional arc as two arcs
:current-draw-mode **
change draw-mode to latest mode
:original-draw-mode **
change draw-mode to original mode
:write-to-png fname &optional result-path (title (string-right-trim .png fname))
:write-to-pdf fname &optional result-path (title (string-right-trim .pdf fname))
:write-to-file basename &optional result-path title (type pdf)
:write-to-dot fname &optional result-path (title output)
:write-to-dot-stream &optional (strm standard-output) result-path (title output)
:neighbors &optional args
:add-neighbor n &optional a
arced-node
:neighbor-action-alist **
:find-action n
:init &key name
solver-node
:action &optional arg
:parent &optional arg
:cost &optional arg
:state &optional arg
:expand prblm &rest args
:path &optional (prev nil)
:init st &key ((:cost c) 0) ((:parent p) nil) ((:action a) nil)
solver
:solve-by-name prblm s g &key (verbose nil)
:solve prblm
:init **
graph-search-solver
:close-list &optional arg
:open-list &optional arg
:pop-from-open-list &key (debug)
:add-object-to-open-list lst
:add-list-to-open-list lst
:clear-open-list **
:null-open-list? **
:add-to-open-list obj/list
:solve prblm &key (verbose nil)
:find-node-in-close-list n
:solve-init prblm
breadth-first-graph-search-solver
:pop-from-open-list &key (debug)
:add-object-to-open-list obj
:add-list-to-open-list lst
:clear-open-list **
:init **
depth-first-graph-search-solver
:pop-from-open-list &key (debug)
:add-object-to-open-list obj
:add-list-to-open-list lst
:clear-open-list **
:init **
best-first-graph-search-solver
:fn n p
:pop-from-open-list &key (debug nil)
:add-object-to-open-list obj
:add-list-to-open-list lst
:clear-open-list **
:init p
a-graph-search-solver
:hn n p
:gn n p
:fn n p &key (debug nil)
:init p
irteus拡張¶
GL/X表示¶
polygon
line
faceset
:set-color gl::color &optional (gl::transparent)
Set color of given color name, color sample and color name are referenced from http://en.wikipedia.org/wiki/X11_color_names
:paste-texture-to-face gl::aface &key gl::file gl::image (gl::tex-coords (list (float-vector 0 0) (float-vector 0 1) (float-vector 1 1) (float-vector 1 0)))
:draw-on &key ((:viewer gl::vwer) viewer) gl::flush (gl::width 1) (gl::color #f(1.0 1.0 1.0))
coordinates
float-vector
gl::glvertices
:set-color gl::color &optional (gl::transparent)
set color as float vector of 3 elements, and transparent as float, all values are betwenn 0 to 1
:actual-vertices **
return list of vertices(float-vector), it returns all vertices of this object
:calc-bounding-box **
calculate and set bounding box of this object
:vertices **
return list of vertices(float-vector), it returns vertices of bounding box of this object
:reset-offset-from-parent **
move vertices in this object using self transformation, this method change values of vertices. coordinates’s method such as :transform just change view of this object
:expand-vertices **
expand vertices number as same number of indices, it enable to set individual normal to every vertices
:use-flat-shader **
use flat shader mode, use opengl function of glShadeModel(GL_FLAT)
:use-smooth-shader **
use smooth shader mode, use opengl function of glShadeModel(GL_SMOOTH) default
:calc-normals &optional (gl::force nil) (gl::expand t) (gl::flat t)
creating mirror vertices respect to :axis
create list of faces using vertices of this object
:convert-to-faceset &rest args
create faceset using vertices of this object
:set-offset gl::cds &key (gl::create)
move vertices in this object using given coordinates, this method change values of vertices. coordinates’s method such as :transform just change view of this object
:convert-to-world &key (gl::create)
move vertices in this object using self’s coordinates. vertices data should be moved as the same as displayed
:glvertices &optional (name) (gl::test #’string=)
create individual glvertices objects from mesh-list. if name is given, search mesh has the same name
:append-glvertices gl::glv-lst
append list of glvertices to this object
:init gl::mlst &rest args &key ((:filename gl::fn)) &allow-other-keys
:filename &optional gl::nm
:get-meshinfo gl::key &optional (pos -1)
:set-meshinfo gl::key gl::info &optional (pos -1)
:get-material &optional (pos -1)
:set-material gl::mat &optional (pos -1)
:expand-vertices-info gl::minfo
:faces **
:draw-on &key ((:viewer gl::vwer) viewer)
:draw gl::vwr &rest args
:collision-check-objects &rest args
:box **
:make-pqpmodel &key (gl::fat 0)
:append-glvertices gl::glv-lst
append list of glvertices to this object
:glvertices &optional (name) (gl::test #’string=)
create individual glvertices objects from mesh-list. if name is given, search mesh has the same name
:convert-to-world &key (gl::create)
move vertices in this object using self’s coordinates. vertices data should be moved as the same as displayed
:set-offset gl::cds &key (gl::create)
move vertices in this object using given coordinates, this method change values of vertices. coordinates’s method such as :transform just change view of this object
:convert-to-faceset &rest args
create faceset using vertices of this object
create list of faces using vertices of this object
creating mirror vertices respect to :axis
:calc-normals &optional (gl::force nil) (gl::expand t) (gl::flat t)
:use-smooth-shader **
use smooth shader mode, use opengl function of glShadeModel(GL_SMOOTH) default
:use-flat-shader **
use flat shader mode, use opengl function of glShadeModel(GL_FLAT)
:expand-vertices **
expand vertices number as same number of indices, it enable to set individual normal to every vertices
:reset-offset-from-parent **
move vertices in this object using self transformation, this method change values of vertices. coordinates’s method such as :transform just change view of this object
:vertices **
return list of vertices(float-vector), it returns vertices of bounding box of this object
:calc-bounding-box **
calculate and set bounding box of this object
:actual-vertices **
return list of vertices(float-vector), it returns all vertices of this object
:set-color gl::color &optional (gl::transparent)
set color as float vector of 3 elements, and transparent as float, all values are betwenn 0 to 1
:make-pqpmodel &key (gl::fat 0)
:box **
:collision-check-objects &rest args
:draw gl::vwr &rest args
:draw-on &key ((:viewer gl::vwer) viewer)
:faces **
:expand-vertices-info gl::minfo
:set-material gl::mat &optional (pos -1)
:get-material &optional (pos -1)
:set-meshinfo gl::key gl::info &optional (pos -1)
:get-meshinfo gl::key &optional (pos -1)
:filename &optional gl::nm
:init gl::mlst &rest args &key ((:filename gl::fn)) &allow-other-keys
gl::glbody
:set-color &rest args
:draw gl::vwr
:glvertices &rest args
gl::find-color gl::color
returns color vector of given color name, the name is defined in https://github.com/euslisp/jskeus/blob/master/irteus/irtglrgb.l
gl::transparent gl::abody gl::param
Set abody to transparent with param
gl::make-glvertices-from-faceset gl::fs &key (gl::material)
gl::make-glvertices-from-faces gl::flst &key (gl::material)
gl::write-wrl-from-glvertices fname gl::glv &rest args
write .wrl file from instance of glvertices
gl::set-stereo-gl-attribute **
gl::reset-gl-attribute **
gl::delete-displaylist-id gl::dllst
gl::transpose-image-rows gl::img &optional gl::ret
gl::draw-globjects gl::vwr gl::draw-things &key (gl::clear t) (gl::flush t) (gl::draw-origin 150) (gl::draw-floor nil) (gl::floor-color #f(1.0 1.0 1.0))
gl::draw-glbody gl::vwr gl::abody
gl::_dump-wrl-shape gl::strm gl::mesh &key ((:scale gl::scl) 1.0) (gl::use_ambient nil) (gl::use_normal nil) (gl::use_texture nil) &allow-other-keys
x:xwindow
x:panel
x:xscroll-bar
x::tabbed-panel
:resize x::w h
:tabbed-panel name &rest args
:tabbed-button name &rest args
:change-tabbed-panel x::obj
:add-tabbed-panel name
:create &rest args
x::panel-tab-button-item
:draw-label &optional (x::state :up) (x::offset 0)
x::window-main-one &optional fd
x::event-far x::e
x::event-near x::e
ユーティリティ関数¶
mtimer
:init **
Initialize timer object.
:start **
Start timer.
:stop **
Stop timer and returns elapsed time in seconds.
:stop **
Stop timer and returns elapsed time in seconds.
:start **
Start timer.
:init **
Initialize timer object.
interpolator
:init **
Abstract class of interpolator
:position-list **
returns position list
:position **
returns current position
:time-list **
returns time list
:time **
returns current time
:segment-time **
returns time[sec] with in each segment
:segment **
returns index of segment which is currently processing
:segment-num **
returns number of total segment
:interpolatingp **
returns if it is currently processing
:start-interpolation **
start interpolation
:stop-interpolation **
stop interpolation
:pass-time dt
process interpolation for dt[sec]
:pass-time dt
process interpolation for dt[sec]
:stop-interpolation **
stop interpolation
:start-interpolation **
start interpolation
:interpolatingp **
returns if it is currently processing
:segment-num **
returns number of total segment
:segment **
returns index of segment which is currently processing
:segment-time **
returns time[sec] with in each segment
:time **
returns current time
:time-list **
returns time list
:position **
returns current position
:position-list **
returns position list
:init **
Abstract class of interpolator
linear-interpolator
:interpolation **
Linear interpolator
:interpolation **
Linear interpolator
minjerk-interpolator
:velocity **
returns current velocity
:velocity-list **
returns velocity list
:acceleration **
returns current acceleration
:acceleration-list **
returns acceleration list
:interpolation **
:interpolation **
:acceleration-list **
returns acceleration list
:acceleration **
returns current acceleration
:velocity-list **
returns velocity list
:velocity **
returns current velocity
forward-message-to to args
forward _args_ message to _to_ object
forward-message-to-all to args
forward _args_ message to all _to_ object
permutation lst n
Returns permutation of given list
combination lst n
Returns combination of given list
Returns the elements of datum which maximizes key function
eus-server &optional (port 6666) &key (host (unix:gethostname))
Create euslisp interpreter server, data sent to socket is evaluated as lisp expression
Connect euslisp interpreter server until success
format-array arr &optional (header ) (in 7) (fl 3) (strm error-output) (use-line-break t)
print formatted array
his2rgb h &optional (i 1.0) (s 1.0) ret
convert his to rgb (0 <= h <= 360, 0.0 <= i <= 1.0, 0.0 <= s <= 1.0)
hvs2rgb h &optional (i 1.0) (s 1.0) ret
convert hvs to rgb (0 <= h <= 360, 0.0 <= i <= 1.0, 0.0 <= s <= 1.0)
rgb2his r &optional g b ret
convert rgb to his (0 <= r,g,b <= 255)
rgb2hvs r &optional g b ret
convert rt to hvs (0 <= r,g,b <= 255)
color-category10 i
Choose good color from 10 colors
color-category20 i
Choose good color from 20 colors
kbhit **
Checks the console for a keystroke. returns keycode value if a key has been pressed, otherwise it returns nil. Note that this does not work well on Emacs Shell mode, run EusLisp program from terminal shell.
piped-fork-returns-list cmd &optional args
piped fork returning result as list
make-robot-model-from-name name &rest args
make a robot model from string: (make-robot-model ”pr2”)
mapjoin expr seq1 seq2
need-thread n &optional (lsize (512 1024)) (csize lsize)
termios-c_iflag lisp::s
set-termios-c_iflag lisp::s lisp::val
termios-c_oflag lisp::s
set-termios-c_oflag lisp::s lisp::val
termios-c_cflag lisp::s
set-termios-c_cflag lisp::s lisp::val
termios-c_lflag lisp::s
set-termios-c_lflag lisp::s lisp::val
termios-c_line lisp::s
set-termios-c_line lisp::s lisp::val
termios-c_cc lisp::s &optional lisp::i
set-termios-c_cc lisp::s lisp::i &rest lisp::val
termios-c_ispeed lisp::s
set-termios-c_ispeed lisp::s lisp::val
termios-c_ospeed lisp::s
set-termios-c_ospeed lisp::s lisp::val
gnuplot
Initialize gnuplot interface object with given host name
:clear **
Clear graph
:draw &rest vs
:save f &key (type postscript eps color ”Times-Roman” 24)
save graph as eps file
:replot **
:reset **
:command msg
:quit **
:proc-length &optional n
:proc-clear **
:proc-one vs &rest args
:save f &key (type postscript eps color ”Times-Roman” 24)
save graph as eps file
:draw &rest vs
:clear **
Clear graph
Initialize gnuplot interface object with given host name
:proc-one vs &rest args
:proc-clear **
:proc-length &optional n
:quit **
:command msg
:reset **
:replot **
gnuplot &key (host (unix:gethostname))
数学関数¶
inverse-matrix mat
returns inverse matrix of mat
inverse-matrix-complex cmat
returns inverse matrix of complex square matrix
m-complex cmat1 cmat2
returns complex matrix 1 complex matrix 2
diagonal v
make diagonal matrix from given vecgtor, diagonal #f(1 2) ->#2f((1 0)(0 2))
minor-matrix m ic jc
return a matrix removing ic row and jc col elements from m
atan2 y x
returns atan2 of y and x (atan (/ y x))
outer-product-matrix v &optional (ret (unit-matrix 3))
matrix2quaternion m
returns quaternion (w x y z) of given matrix
quaternion2matrix q
returns matrix of given quaternion (w x y z)
matrix-log m
returns matrix log of given m, it returns [-pi, pi]
matrix-exponent omega &optional (p 1.0)
returns exponent of given omega
midrot p r1 r2
returns mid (or p) rotation matrix of given two matrix r1 and r2
pseudo-inverse mat &optional weight-vector ret wmat mat-tmp
returns pseudo inverse of given mat
sr-inverse mat &optional (k 1.0) weight-vector ret wmat tmat umat umat2 mat-tmp mat-tmp-rc mat-tmp-rr mat-tmp-rr2
returns sr-inverse of given mat
manipulability jacobi &optional tmp-mrr tmp-mcr
return manipulability of given matrix
random-gauss &optional (m 0) (s 1)
make random gauss, m:mean s:standard-deviation
gaussian-random dim &optional (m 0) (s 1)
make random gauss vector, replacement for quasi-random defined in matlib.c
eigen-decompose-complex m
returns eigen decomposition from real square matrix
solve-non-zero-vector-from-det0-matrix m
solves non-zero-vector v from real square determinant-zero-matrix mat, when matv=O and det(mat)=0
concatenate-matrix-column &rest args
Concatenate matrix in column direction.
concatenate-matrix-row &rest args
Concatenate matrix in row direction.
concatenate-matrix-diagonal &rest args
Concatenate matrix in diagonal.
vector-variance vector-list
returns vector, each element represents variance of elements in the same index of vector within vector-list
covariance-matrix vector-list
make covariance matrix of given input vector-list
normalize-vector v &optional r (eps 1.000000e-20)
calculate normalize-vector #f(0 0 0)->#f(0 0 0).
pseudo-inverse-org m &optional ret winv mat-tmp-cr
sr-inverse-org mat &optional (k 1) me mat-tmp-cr mat-tmp-rr
eigen-decompose m
lms point-list
lms-estimate res point-
lms-error result point-list
lmeds point-list &key (num 5) (err-rate 0.3) (iteration) (ransac-threshold) (lms-func #’lms) (lmeds-error-func #’lmeds-error) (lms-estimate-func #’lms-estimate)
lmeds-error result point-list &key (lms-estimate-func #’lms-estimate)
lmeds-error-mat result mat &key (lms-estimate-func #’lms-estimate)
画像関数¶
read-image-file fname
read image of given fname. It returns instance of grayscale-image or color-image24.
write-image-file fname image::img
write img to given fname
read-png-file fname
write-png-file fname image::img