/*
* 作成日: 2008/10/26
*/
package jp.ac.fit.asura.nao.motion.motions;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.Leg.LEFT;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.Leg.RIGHT;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.READY;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.START;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.STOP;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.SWING;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.SWING_BEGIN;
import static jp.ac.fit.asura.nao.motion.motions.BasicWalk.WalkState.SWING_END;
import java.awt.Polygon;
import java.io.IOException;
import java.io.PrintWriter;
import javax.vecmath.Matrix3f;
import javax.vecmath.Point2f;
import javax.vecmath.Vector3f;
import jp.ac.fit.asura.nao.Effector;
import jp.ac.fit.asura.nao.Joint;
import jp.ac.fit.asura.nao.RobotContext;
import jp.ac.fit.asura.nao.Sensor;
import jp.ac.fit.asura.nao.SensorContext;
import jp.ac.fit.asura.nao.event.MotionEventListener;
import jp.ac.fit.asura.nao.localization.self.GPSLocalization;
import jp.ac.fit.asura.nao.misc.Coordinates;
import jp.ac.fit.asura.nao.misc.Kinematics;
import jp.ac.fit.asura.nao.misc.MathUtils;
import jp.ac.fit.asura.nao.misc.MatrixUtils;
import jp.ac.fit.asura.nao.misc.SingularPostureException;
import jp.ac.fit.asura.nao.motion.Motion;
import jp.ac.fit.asura.nao.motion.MotionParam;
import jp.ac.fit.asura.nao.motion.MotionParam.WalkParam;
import jp.ac.fit.asura.nao.physical.Robot.Frames;
import jp.ac.fit.asura.nao.sensation.FrameState;
import jp.ac.fit.asura.nao.sensation.SomaticContext;
import jp.ac.fit.asura.vecmathx.GfVector;
import org.apache.log4j.Logger;
/**
* @author $Author: sey $
*
* @version $Id: TestWalkMotion.java 721 2009-02-18 03:40:44Z sey $
*
*/
public class BasicWalk extends Motion {
private static final Logger log = Logger.getLogger(BasicWalk.class);
enum WalkState {
START, READY, SWING_BEGIN, SWING, SWING_END, SWING_RIGHT_END, STOP
}
enum Leg {
LEFT, RIGHT
}
private Effector effector;
// 歩行の状態
private WalkState state;
// フレームカウント. 歩行状態切替ごとにリセットされる
int stateCount;
// 歩数計, 何歩歩いたか. 人間でいう半歩で一歩とカウント
int pedometer;
// 現在の遊脚. LEFT or RIGHT
private Leg swingLeg;
// 現在の支持脚. LEFT or RIGHT
private Leg supportLeg;
// モーション停止要求があったか
private boolean stopRequested;
// モーションを継続できるか(停止できるか)
private boolean hasNextStep;
// 一歩あたりの歩幅(mm), パラメータによるが70ぐらいが限界.
float maxStride = 65;
float maxTurn = MathUtils.toRadians(-15);
// 基本となる腰の高さ(mm). 高すぎても低すぎてもダメ
float baseHeight = 265;
// 基本となる足の横幅(mm). 着地時の腰からの位置.
float baseWidth = 75;
// どれぐらい足を上げるか(mm)
float footHeight = 15;
// 一歩にかかる時間(フレーム)
float walkCycle = 15;
// 体重移動するときの速度の限界. 大きいと不安定になる?
float leanLimit = 20;
// 体重移動するときの重心位置オフセット.
float comOffsetX = 5;
float targetHeight;
GPSLocalization gps = new GPSLocalization();
Sensor sensor;
// オドメトリデータ(x: forward, y:left, z:turnCCW)
Vector3f odometer = new Vector3f();
WalkParam param;
public BasicWalk() {
setName("BasicWalk");
param = new WalkParam();
}
@Override
public void init(RobotContext context) {
sensor = context.getSensor();
effector = context.getEffector();
gps.init(context);
}
/**
* モーションの開始・初期化
*/
@Override
public void start(MotionParam param) {
log.debug("start testwalk");
changeState(START);
hasNextStep = true;
stopRequested = false;
pedometer = 0;
odometer.set(0, 0, 0);
if (param != null) {
assert param instanceof MotionParam.WalkParam;
WalkParam walkp = (WalkParam) param;
// TODO 歩行量のパラメータを使ってなんかする
this.param.set(walkp);
float f = walkp.getForward();
float l = walkp.getLeft();
float t = walkp.getTurn();
setName("BasikWalk f:" + f + " l:" + l + " t:" + t);
}
}
/**
* 歩行のメインループ
*/
@Override
public void step() {
log.debug(currentStep + " step state:" + state);
SomaticContext sc = context.getSomaticContext();
// デバッグ時は関節値やCOMのログをとる
if (log.isDebugEnabled())
archive(sc);
try {
SWITCH: do {
switch (state) {
case START:
// はじめ
changeState(READY);
// 右足から振り始める
supportLeg = LEFT;
swingLeg = RIGHT;
continue SWITCH;
case READY:
if (stopRequested)
changeState(STOP);
// 歩行姿勢に移る
if (setReadyPosition()) {
changeState(SWING_BEGIN);
continue SWITCH;
}
break;
case SWING_BEGIN:
// 歩行のはじめ 支持脚に重心を移す
targetHeight = -baseHeight;
if (stopRequested)
changeState(STOP);
// 重心が移ったら足を振る
if (canSwingLeg()) {
changeState(SWING);
continue SWITCH;
}
// 支持脚に重心を移す
leanSupportLeg();
break;
case SWING:
// 遊足を前へ
if (!forwardSwingLeg()) {
// if (!turnSwingLeg()) {
changeState(SWING_END);
continue SWITCH;
}
break;
case SWING_END:
// 歩行の終わり
pedometer++;
if (!stopRequested && pedometer < param.getPedometer()) {
// 歩行を続ける
changeSupportLeg();
changeState(SWING_BEGIN);
} else {
// やめる
changeState(STOP);
}
continue SWITCH;
}
} while (false);
} catch (SingularPostureException spe) {
// 歩行を継続できそうにない
log.error("", spe);
changeState(STOP);
}
if (state == STOP)
hasNextStep = false;
stateCount++;
currentStep++;
}
private void changeSupportLeg() {
// 支持脚を交換する
Leg t = supportLeg;
supportLeg = swingLeg;
swingLeg = t;
}
/**
* 遊脚をあげることができるか?
*
* 支持脚に重心が移っているかをチェック
*
* @return
*/
private boolean canSwingLeg() {
SomaticContext sc = context.getSomaticContext();
// 支持脚の凸多角形内に重心があるか?
// 別にロボット座標系で計算する必要はない気がする
Vector3f com = new Vector3f(sc.getCenterOfMass());
Coordinates.body2robotCoord(sc, com, com);
Polygon polygon = new Polygon();
if (supportLeg == LEFT) {
addSolePoint(polygon, Frames.LFsrFL);
addSolePoint(polygon, Frames.LFsrFR);
addSolePoint(polygon, Frames.LFsrBR);
addSolePoint(polygon, Frames.LFsrBL);
com.x -= comOffsetX;
} else {
addSolePoint(polygon, Frames.RFsrFL);
addSolePoint(polygon, Frames.RFsrFR);
addSolePoint(polygon, Frames.RFsrBR);
addSolePoint(polygon, Frames.RFsrBL);
com.x += comOffsetX;
}
log.trace("canSwingLeg com:" + com + " poly:" + polygon);
return polygon.contains(com.x, com.z);
}
private void addSolePoint(Polygon poly, Frames sole) {
SomaticContext sc = context.getSomaticContext();
Vector3f vec = new Vector3f(sc.get(sole).getBodyPosition());
Coordinates.body2robotCoord(sc, vec, vec);
poly.addPoint((int) vec.x, (int) vec.z);
}
private boolean setReadyPosition() {
SomaticContext sc = new SomaticContext(context.getSomaticContext());
FrameState lar = sc.get(Frames.LAnkleRoll).clone();
FrameState rar = sc.get(Frames.RAnkleRoll).clone();
boolean getReady = true;
Vector3f lPos = lar.getBodyPosition();
Vector3f rPos = rar.getBodyPosition();
float baseWidth = sc.get(Frames.LHipYawPitch).getPosition().x;
if (Math.abs(lPos.x - baseWidth) > 1.0f)
getReady = false;
if (Math.abs(rPos.x + baseWidth) > 1.0f)
getReady = false;
if (Math.abs(lPos.y + baseHeight) <= 1.0f)
getReady = false;
if (Math.abs(rPos.y + baseHeight) <= 1.0f)
getReady = false;
if (getReady)
return true;
float ldy = -baseHeight - lPos.y;
float rdy = -baseHeight - rPos.y;
lPos.z -= MathUtils.clipAbs(lPos.z, 10.0f);
rPos.z -= MathUtils.clipAbs(rPos.z, 10.0f);
lar.getBodyRotation().setIdentity();
rar.getBodyRotation().setIdentity();
lPos.x += MathUtils.clipAbs(-lPos.x + baseWidth, 10.0f);
rPos.x += MathUtils.clipAbs(-rPos.x + -baseWidth, 10.0f);
lPos.y += MathUtils.clipAbs(ldy, 12.0f);
rPos.y += MathUtils.clipAbs(rdy, 12.0f);
Kinematics.calculateInverse(sc, lar);
Kinematics.calculateInverse(sc, rar);
copyToOut(sc, effector);
return false;
}
private void leanSupportLeg() {
log.trace("leanSupportLeg " + supportLeg);
SomaticContext sc = new SomaticContext(context.getSomaticContext());
FrameState lar = sc.get(Frames.LAnkleRoll).clone();
FrameState rar = sc.get(Frames.RAnkleRoll).clone();
// 現在の重心位置
Vector3f com = new Vector3f();
Coordinates.body2robotCoord(sc, sc.getCenterOfMass(), com);
// 足のx座標をずらす。ボディからみた位置なので、傾けたい方向とは逆になる。
Vector3f sole;
if (supportLeg == Leg.LEFT) {
Vector3f robotLar = new Vector3f();
Coordinates.body2robotCoord(sc, lar.getBodyPosition(), robotLar);
sole = robotLar;
com.x -= comOffsetX;
} else {
Vector3f robotRar = new Vector3f();
Coordinates.body2robotCoord(sc, rar.getBodyPosition(), robotRar);
sole = robotRar;
com.x += comOffsetX;
}
Vector3f dx = new Vector3f(com.x - sole.x, 0, Math.min(com.z - sole.z,
0));
dx.scale(0.5f);
if (dx.length() > leanLimit) {
dx.scale(leanLimit / dx.length());
}
Coordinates.robot2bodyCoord(sc, dx, dx);
dx.y = 0;
lar.getBodyPosition().add(dx);
rar.getBodyPosition().add(dx);
lar.getBodyPosition().y = targetHeight;
rar.getBodyPosition().y = targetHeight;
// 最初に取得した値を目標に逆運動学計算
Kinematics.calculateInverse(sc, lar);
Kinematics.calculateInverse(sc, rar);
copyToOut(sc, effector);
}
private boolean forwardSwingLeg() {
log.trace("forwardSwingLeg " + swingLeg);
SomaticContext sc = new SomaticContext(context.getSomaticContext());
FrameState lar = sc.get(Frames.LAnkleRoll).clone();
FrameState rar = sc.get(Frames.RAnkleRoll).clone();
FrameState support;
FrameState swing;
if (swingLeg == Leg.LEFT) {
swing = lar;
support = rar;
} else {
swing = rar;
support = lar;
}
double theta1 = stateCount * Math.PI / (walkCycle);
double theta2 = (stateCount - 1) * Math.PI / (walkCycle);
if (theta1 > Math.PI) {
return false;
}
if (stopRequested && stateCount < 3) {
// 3ステップ未満ならキャンセル可能?
return false;
}
float dx = (float) (maxStride * (-Math.cos(theta1) + Math.cos(theta2)));
float dy = (float) (footHeight * (Math.sin(theta1) - Math.sin(theta2)));
log.debug("dx:" + dx + " dy:" + dy + " pedometer:" + pedometer);
if (pedometer >= 1 && !stopRequested) {
// 二歩目以降
swing.getBodyPosition().z += dx;
support.getBodyPosition().z -= dx;
odometer.x += dx;
} else {
swing.getBodyPosition().z += dx / 2;
support.getBodyPosition().z -= dx / 2;
odometer.x += dx / 2;
}
targetHeight += dy;
swing.getBodyPosition().y = targetHeight;
if (swingLeg == Leg.LEFT)
swing.getBodyPosition().x = baseWidth;
else
swing.getBodyPosition().x = -baseWidth;
lar.getBodyRotation().setIdentity();
rar.getBodyRotation().setIdentity();
// 最初に取得した値を目標に逆運動学計算
Kinematics.calculateInverse(sc, lar);
Kinematics.calculateInverse(sc, rar);
copyToOut(sc, effector);
return true;
}
private boolean turnSwingLeg() {
log.trace("forwardSwingLeg " + swingLeg);
SomaticContext sc = new SomaticContext(context.getSomaticContext());
FrameState lar = sc.get(Frames.LAnkleRoll).clone();
FrameState rar = sc.get(Frames.RAnkleRoll).clone();
FrameState support;
FrameState swing;
if (swingLeg == Leg.LEFT) {
swing = lar;
support = rar;
} else {
swing = rar;
support = lar;
}
double theta1 = stateCount * Math.PI / (walkCycle);
double theta2 = (stateCount - 1) * Math.PI / (walkCycle);
if (theta1 > Math.PI) {
return false;
}
float dw = (float) (maxTurn * (-Math.cos(theta1) + Math.cos(theta2)));
float dy = (float) (footHeight * (Math.sin(theta1) - Math.sin(theta2)));
log.debug("dw:" + dw + " dy:" + dy + " pedometer:" + pedometer);
if (pedometer % 2 == 0) {
Matrix3f rot = new Matrix3f();
MatrixUtils.pyr2rot(new Vector3f(0, dw, 0), rot);
swing.getBodyRotation().mul(rot);
MatrixUtils.pyr2rot(new Vector3f(0, -dw / 2, 0), rot);
support.getBodyRotation().mul(rot);
} else {
Matrix3f rot = new Matrix3f();
MatrixUtils.pyr2rot(new Vector3f(0, -dw, 0), rot);
support.getBodyRotation().mul(rot);
}
targetHeight += dy;
swing.getBodyPosition().y = targetHeight;
// if (swingLeg == Leg.LEFT)
// swing.getBodyPosition().x = targetWidth;
// else
// swing.getBodyPosition().x = -targetWidth;
// support.getBodyRotation().setIdentity();
// 最初に取得した値を目標に逆運動学計算
// Kinematics.calculateInverse(sc, support);
Kinematics.calculateInverse(sc, swing);
// if (swingLeg == Leg.LEFT)
// Kinematics.calculateInverse(sc, Frames.LAnkleRoll, swing);
// else
// Kinematics.calculateInverse(sc, Frames.RAnkleRoll, swing);
GfVector w = new GfVector(new float[] { 1, 1, 1, 1, 1, 1 });
if (swingLeg == Leg.LEFT)
Kinematics.calculateInverse(sc, Frames.RAnkleRoll, support, w);
else
Kinematics.calculateInverse(sc, Frames.LAnkleRoll, support, w);
copyToOut(sc, effector);
return true;
}
private void changeState(WalkState s) {
log.debug(currentStep + " change state to " + s);
state = s;
stateCount = 0;
}
private void copyToOut(SomaticContext sc, Effector effector) {
// 実機にあわせてYawPitchは共通に
float yp;
if (supportLeg == RIGHT)
yp = sc.get(Frames.LHipYawPitch).getAngle();
else
yp = sc.get(Frames.RHipYawPitch).getAngle();
effector.setJoint(Joint.RHipYawPitch, yp);
effector.setJoint(Joint.LHipYawPitch, yp);
effector.setJoint(Joint.LHipPitch, sc.get(Frames.LHipPitch).getAngle());
effector.setJoint(Joint.LHipRoll, sc.get(Frames.LHipRoll).getAngle());
effector.setJoint(Joint.LKneePitch, sc.get(Frames.LKneePitch)
.getAngle());
effector.setJoint(Joint.LAnklePitch, sc.get(Frames.LAnklePitch)
.getAngle());
effector.setJoint(Joint.LAnkleRoll, sc.get(Frames.LAnkleRoll)
.getAngle());
effector.setJoint(Joint.RHipPitch, sc.get(Frames.RHipPitch).getAngle());
effector.setJoint(Joint.RHipRoll, sc.get(Frames.RHipRoll).getAngle());
effector.setJoint(Joint.RKneePitch, sc.get(Frames.RKneePitch)
.getAngle());
effector.setJoint(Joint.RAnklePitch, sc.get(Frames.RAnklePitch)
.getAngle());
effector.setJoint(Joint.RAnkleRoll, sc.get(Frames.RAnkleRoll)
.getAngle());
}
@Override
public void requestStop() {
// TODO 歩行の軌道を動的に修正する
stopRequested = true;
}
@Override
public boolean canStop() {
return !hasNextStep;
}
@Override
public boolean hasNextStep() {
return hasNextStep;
}
@Override
public boolean hasOdometer() {
return true;
}
@Override
public void updateOdometry(MotionEventListener listener) {
listener.updateOdometry(odometer.x, odometer.y, odometer.z);
odometer.set(0, 0, 0);
}
PrintWriter jointLog = null;
PrintWriter torqueLog = null;
PrintWriter comLog = null;
PrintWriter gpsLog = null;
PrintWriter posLog = null;
/**
* 動作ログの記録
*
* @param sc
*/
private void archive(SomaticContext sc) {
SensorContext sensor = context.getSensorContext();
try {
if (jointLog == null)
jointLog = new PrintWriter("joint.log");
if (torqueLog == null)
torqueLog = new PrintWriter("torque.log");
if (comLog == null)
comLog = new PrintWriter("com.log");
if (gpsLog == null)
gpsLog = new PrintWriter("gps.log");
if (posLog == null)
posLog = new PrintWriter("pos.log");
} catch (IOException e) {
log.error("", e);
}
// 間接角度を記録
jointLog.print(currentStep);
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LHipYawPitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LHipPitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LHipRoll).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LKneePitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LAnklePitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.LAnkleRoll).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RHipYawPitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RHipPitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RHipRoll).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RKneePitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RAnklePitch).getAngle()));
jointLog.print(" ");
jointLog.print(Math.toDegrees(sc.get(Frames.RAnkleRoll).getAngle()));
jointLog.println();
torqueLog.print(currentStep);
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LHipYawPitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LHipPitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LHipRoll));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LKneePitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LAnklePitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.LAnkleRoll));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RHipYawPitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RHipPitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RHipRoll));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RKneePitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RAnklePitch));
torqueLog.print(" ");
torqueLog.print(sensor.getForce(Joint.RAnkleRoll));
torqueLog.println();
Vector3f com = sc.getCenterOfMass();
comLog.print(currentStep); // 1
comLog.print(" ");
comLog.print(com.x - gps.getX()); // 2
comLog.print(" ");
comLog.print(com.z + gps.getY()); // 3
Point2f cop = sc.getCenterOfPressure();
comLog.print(" ");
comLog.print(cop.x - gps.getX()); // 4
comLog.print(" ");
comLog.print(cop.y + gps.getY()); // 5
Point2f comMax = new Point2f();
Point2f comMin = new Point2f();
Point2f copMax = new Point2f();
Point2f copMin = new Point2f();
// 支持多角形を求める Convex hullのアルゴリズムを使ったほうがいいが、数が少ないので直接.
Vector3f lfl = new Vector3f(sc.get(Frames.LFsrFL).getBodyPosition());
Vector3f lfr = new Vector3f(sc.get(Frames.LFsrFR).getBodyPosition());
Vector3f lbl = new Vector3f(sc.get(Frames.LFsrBL).getBodyPosition());
Vector3f lbr = new Vector3f(sc.get(Frames.LFsrBR).getBodyPosition());
Vector3f rfl = new Vector3f(sc.get(Frames.RFsrFL).getBodyPosition());
Vector3f rfr = new Vector3f(sc.get(Frames.RFsrFR).getBodyPosition());
Vector3f rbl = new Vector3f(sc.get(Frames.RFsrBL).getBodyPosition());
Vector3f rbr = new Vector3f(sc.get(Frames.RFsrBR).getBodyPosition());
Coordinates.body2robotCoord(sc, lfl, lfl);
Coordinates.body2robotCoord(sc, lfr, lfr);
Coordinates.body2robotCoord(sc, lbl, lbl);
Coordinates.body2robotCoord(sc, lbr, lbr);
Coordinates.body2robotCoord(sc, rfl, rfl);
Coordinates.body2robotCoord(sc, rfr, rfr);
Coordinates.body2robotCoord(sc, rbl, rbl);
Coordinates.body2robotCoord(sc, rbr, rbr);
if (sc.isLeftOnGround() && sc.isRightOnGround() || state == SWING_BEGIN) {
if (rfl.z > lfl.z) {
copMax.y = comMax.y = rfl.z;
copMin.y = comMin.y = lbr.z;
} else {
copMax.y = comMax.y = lfl.z;
copMin.y = comMin.y = rbr.z;
}
copMax.x = comMax.x = lfl.x;
copMin.x = comMin.x = rbr.x;
} else if (sc.isLeftOnGround()) {
copMax.x = comMax.x = lfl.x;
copMax.y = comMax.y = lfl.z;
copMin.x = comMin.x = lbr.x;
copMin.y = comMin.y = lbr.z;
} else if (sc.isRightOnGround()) {
copMax.x = comMax.x = rfl.x;
copMax.y = comMax.y = rfl.z;
copMin.x = comMin.x = rbr.x;
copMin.y = comMin.y = rbr.z;
}
comLog.print(" ");
comLog.print(comMax.x - gps.getX()); // 6
// comLog.print(comMax.x ); // 6
comLog.print(" ");
comLog.print(comMin.x - gps.getX()); // 7
// comLog.print(comMin.x); // 7
comLog.print(" ");
comLog.print(comMax.y + gps.getY()); // 8
comLog.print(" ");
comLog.print(comMin.y + gps.getY()); // 9
comLog.print(" ");
comLog.print(copMax.x + gps.getX()); // 10
comLog.print(" ");
comLog.print(copMin.x + gps.getX()); // 11
comLog.print(" ");
comLog.print(copMax.y + gps.getY()); // 12
comLog.print(" ");
comLog.print(copMin.y + gps.getY()); // 13
comLog.println();
gpsLog.print(currentStep);
gpsLog.print(" ");
gpsLog.print(gps.getX());
gpsLog.print(" ");
gpsLog.print(gps.getY());
gpsLog.print(" ");
gpsLog.print(gps.getZ());
gpsLog.println();
posLog.print(currentStep);
posLog.print(" ");
posLog.print(sc.get(Frames.LAnkleRoll).getBodyPosition().x);
posLog.print(" ");
posLog.print(sc.get(Frames.LAnkleRoll).getBodyPosition().y);
posLog.print(" ");
posLog.print(sc.get(Frames.LAnkleRoll).getBodyPosition().z);
posLog.print(" ");
posLog.print(sc.get(Frames.RAnkleRoll).getBodyPosition().x);
posLog.print(" ");
posLog.print(sc.get(Frames.RAnkleRoll).getBodyPosition().y);
posLog.print(" ");
posLog.print(sc.get(Frames.RAnkleRoll).getBodyPosition().z);
posLog.println();
jointLog.flush();
torqueLog.flush();
comLog.flush();
gpsLog.flush();
posLog.flush();
}
}