/*
* 作成日: 2009/05/03
*/
package jp.ac.fit.asura.nao.motion;
import javax.vecmath.Matrix3f;
import javax.vecmath.Vector3f;
import jp.ac.fit.asura.nao.event.MotionEventListener;
import jp.ac.fit.asura.nao.misc.Coordinates;
import jp.ac.fit.asura.nao.misc.MathUtils;
import jp.ac.fit.asura.nao.misc.MatrixUtils;
import jp.ac.fit.asura.nao.misc.AverageFilter;
import jp.ac.fit.asura.nao.misc.Filter.BooleanFilter;
import jp.ac.fit.asura.nao.physical.Robot.Frames;
import jp.ac.fit.asura.nao.sensation.SomaticContext;
import org.apache.log4j.Logger;
/**
* 運動学によるオドメトリの計算.
*
* @author sey
*
* @version $Id: $
*
*/
public class KinematicOdometer {
private static final Logger log = Logger.getLogger(KinematicOdometer.class);
private BooleanFilter leftFilter;
private Vector3f lastLeftPosition;
private Matrix3f lastLeftRotation;
private BooleanFilter rightFilter;
private Vector3f lastRightPosition;
private Matrix3f lastRightRotation;
private Vector3f dx;
private Matrix3f dr;
private Vector3f dpyr;
public KinematicOdometer() {
leftFilter = new AverageFilter.Boolean(5);
rightFilter = new AverageFilter.Boolean(5);
lastLeftPosition = new Vector3f();
lastLeftRotation = new Matrix3f();
lastRightPosition = new Vector3f();
lastRightRotation = new Matrix3f();
dx = new Vector3f();
dr = new Matrix3f();
dpyr = new Vector3f();
}
public void step(SomaticContext sc) {
boolean isLeftTouched = leftFilter.eval(sc.isLeftOnGround());
boolean isRightTouched = rightFilter.eval(sc.isRightOnGround());
// 変位の計算に使う支持脚を決定する
// FIXME 支持脚の選択が不安定で誤差が大きい.
boolean useLeft;
if (isLeftTouched && isRightTouched) {
// 両方接地 > 圧力の高い方
float leftp = sc.getLeftPressure();
float rightp = sc.getRightPressure();
if (leftp > rightp) {
useLeft = true;
log.trace("use left" + leftp + " (" + rightp + ")");
} else {
useLeft = false;
log.trace("use right" + rightp + " (" + leftp + ")");
}
} else if (isLeftTouched) {
useLeft = true;
log.trace("use left");
} else if (isRightTouched) {
useLeft = false;
log.trace("use right");
} else {
// 両足ともついていない
dx.set(0, 0, 0);
dr.setIdentity();
dpyr.set(0, 0, 0);
return;
}
Frames support = useLeft ? Frames.LSole : Frames.RSole;
Vector3f supportPos = useLeft ? lastLeftPosition : lastRightPosition;
Matrix3f supportRot = useLeft ? lastLeftRotation : lastRightRotation;
Frames swing = !useLeft ? Frames.LSole : Frames.RSole;
Vector3f swingPos = !useLeft ? lastLeftPosition : lastRightPosition;
Matrix3f swingRot = !useLeft ? lastLeftRotation : lastRightRotation;
Vector3f pos = sc.get(support).getBodyPosition();
Matrix3f rot = sc.get(support).getBodyRotation();
// 支持脚の位置の変化を計算
dx.set(supportPos);
Coordinates.body2robotCoord(sc, pos, supportPos);
dx.sub(supportPos);
// 支持脚の姿勢の変化を計算
// pyr2.sub(pyr1)でもよさそう?
dr.set(supportRot);
supportRot.mul(sc.getBodyPosture(), rot);
dr.mulTransposeRight(dr, supportRot);
// ロールピッチヨー表現に直す
MatrixUtils.rot2pyr(dr, dpyr);
// 次の実行のために遊脚も計算(なくてもいい?)
Coordinates.body2robotCoord(sc, sc.get(swing).getBodyPosition(),
swingPos);
swingRot.mul(sc.getBodyPosture(), sc.get(swing).getBodyRotation());
}
public void updateOdometry(MotionEventListener listener) {
float f = dx.z;
float l = dx.x;
float t = dpyr.y;
assert Math.abs(f) < 1e3f : f;
assert Math.abs(l) < 1e3f : l;
assert Math.abs(t) < MathUtils.PIf / 2 : t;
listener.updateOdometry(f, l, t);
}
}