/*
* 作成日: 2008/09/03
*/
package jp.ac.fit.asura.nao.physical;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import jp.ac.fit.asura.nao.Joint;
import jp.ac.fit.asura.nao.PressureSensor;
import jp.ac.fit.asura.nao.misc.CPair;
/**
* Naoの関節定義. 右手直交座標系. すなわち、右手でx軸を親指、y軸を人差し指とするとz軸は中指の方向.
*
* @author sey
*
* @version $Id: Robot.java 717 2008-12-31 18:16:20Z sey $
*
*/
public class Robot {
public enum Frames {
Body, HeadYaw, HeadPitch, CameraSelect, NaoCam, LShoulderPitch, LShoulderRoll, LElbowYaw, LElbowRoll, LHipYawPitch, LHipRoll, LHipPitch, LKneePitch, LAnklePitch, LAnkleRoll, LSole, LFsrFL, LFsrFR, LFsrBL, LFsrBR, RHipYawPitch, RHipRoll, RHipPitch, RKneePitch, RAnklePitch, RAnkleRoll, RSole, RFsrFL, RFsrFR, RFsrBL, RFsrBR, RShoulderPitch, RShoulderRoll, RElbowYaw, RElbowRoll;
private static final EnumMap<Frames, Joint> f2j = new EnumMap<Frames, Joint>(
Frames.class);
private static final EnumMap<Joint, Frames> j2f = new EnumMap<Joint, Frames>(
Joint.class);
private static final EnumMap<Frames, PressureSensor> f2p = new EnumMap<Frames, PressureSensor>(
Frames.class);
private static final EnumMap<PressureSensor, Frames> p2f = new EnumMap<PressureSensor, Frames>(
PressureSensor.class);
static {
for (Joint j : Joint.values()) {
try {
assert Frames.valueOf(j.name()) != null;
f2j.put(Frames.valueOf(j.name()), j);
j2f.put(j, Frames.valueOf(j.name()));
} catch (IllegalArgumentException e) {
}
}
for (PressureSensor p : PressureSensor.values()) {
try {
assert Frames.valueOf(p.name()) != null;
f2p.put(Frames.valueOf(p.name()), p);
p2f.put(p, Frames.valueOf(p.name()));
} catch (IllegalArgumentException e) {
}
}
}
/**
* 与えられたJointに対応するFramesの列挙体を返します.
*
* @param id
* @return
*/
public static Frames valueOf(Joint j) {
return j2f.get(j);
}
public static Frames valueOf(PressureSensor p) {
return p2f.get(p);
}
public Joint toJoint() {
assert f2j.containsKey(this);
return f2j.get(this);
}
public PressureSensor toPressureSensor() {
assert f2p.containsKey(this);
return f2p.get(this);
}
public boolean isJoint() {
return f2j.containsKey(this);
}
public boolean isPressureSensor() {
return f2p.containsKey(this);
}
}
private EnumMap<Frames, RobotFrame> frames;
private EnumMap<Frames, EnumMap<Frames, Frames[]>> routeCache;
private EnumMap<Frames, EnumMap<Frames, Frames[]>> jointCache;
public Robot(RobotFrame body) {
frames = new EnumMap<Frames, RobotFrame>(Frames.class);
constructRecur(body);
routeCache = new EnumMap<Frames, EnumMap<Frames, Frames[]>>(
Frames.class);
jointCache = new EnumMap<Frames, EnumMap<Frames, Frames[]>>(
Frames.class);
}
private void constructRecur(RobotFrame frame) {
frames.put(frame.getId(), frame);
for (RobotFrame child : frame.getChildren())
constructRecur(child);
}
/**
* Naoのロボット定義. translateは(親フレーム座標系での)親フレームからの移動量を示す.
* axisはこの関節の回転軸(オイラー軸)を示す. massはこの関節の重量を示す.
*
* <pre>
* 図的な意味はこんな感じ.
* translate vector[mm] axis and angle[rad]
* parent ----------------------->@------------------ child
* ˆ
* mass[kg]
* </pre>
*/
public RobotFrame get(Frames key) {
return frames.get(key);
}
/**
* @return the frames
*/
public Set<Frames> getFrames() {
return frames.keySet();
}
/**
* フレームfromからフレームtoまでの経路を探索し、fromからtoまでの最短経路を返します.
*
* @param from
* @param to
* @return
*/
public Frames[] findRoute(Frames from, Frames to) {
if (routeCache.containsKey(from)
&& routeCache.get(from).containsKey(to)) {
return routeCache.get(from).get(to);
}
RobotFrame fromObj = get(from);
RobotFrame toObj = get(to);
Queue<CPair<RobotFrame>> q = new LinkedList<CPair<RobotFrame>>();
q.add(new CPair<RobotFrame>(fromObj, null));
while (true) {
// 閉路を考慮しない探索,Dijkstraのほうが良い
CPair<RobotFrame> p = q.peek();
if (p.first() == toObj)
break;
q.remove();
if (p.first().getParent() != null)
q.add(new CPair<RobotFrame>(p.first().getParent(), p));
for (RobotFrame rf : p.first().getChildren())
q.add(new CPair<RobotFrame>(rf, p));
}
// 結果の出力
if (q.isEmpty())
return null;
CPair<RobotFrame> p = q.peek();
LinkedList<Frames> list = new LinkedList<Frames>();
do {
list.addFirst(p.first().getId());
} while ((p = p.second()) != null);
Frames[] array = list.toArray(new Frames[0]);
if (!routeCache.containsKey(from))
routeCache.put(from, new EnumMap<Frames, Frames[]>(Frames.class));
routeCache.get(from).put(to, array);
return array;
}
/**
* フレームfromからフレームtoまでの最短経路のうち、可動関節のみを返します.
*
* @param from
* @param to
* @return
*/
public Frames[] findJointRoute(Frames from, Frames to) {
if (jointCache.containsKey(from)
&& jointCache.get(from).containsKey(to)) {
return jointCache.get(from).get(to);
}
Frames[] original = findRoute(from, to);
List<Frames> list = new ArrayList<Frames>();
for (Frames f : original)
if (f.isJoint())
list.add(f);
Frames[] result = list.toArray(new Frames[0]);
if (!jointCache.containsKey(from))
jointCache.put(from, new EnumMap<Frames, Frames[]>(Frames.class));
jointCache.get(from).put(to, result);
return result;
}
}