/*
* 作成日: 2009/03/20
*/
package jp.ac.fit.asura.nao.naoji;
import java.io.IOException;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import jp.ac.fit.asura.nao.Effector;
import jp.ac.fit.asura.nao.Joint;
import jp.ac.fit.asura.nao.Sensor;
import jp.ac.fit.asura.nao.SensorContext;
import jp.ac.fit.asura.nao.Switch;
import jp.ac.fit.asura.nao.misc.MathUtils;
import jp.ac.fit.asura.nao.misc.AverageFilter;
import jp.ac.fit.asura.nao.misc.Filter.BooleanFilter;
import jp.ac.fit.asura.naoji.NaojiContext;
import jp.ac.fit.asura.naoji.jal.JALBroker;
import jp.ac.fit.asura.naoji.jal.JALMemory;
import jp.ac.fit.asura.naoji.jal.JALMotion;
import jp.ac.fit.asura.naoji.jal.JALTextToSpeech;
import jp.ac.fit.asura.naoji.jal.JDCM;
import jp.ac.fit.asura.naoji.jal.JALMemory.FloatQuery;
import jp.ac.fit.asura.naoji.jal.JDCM.MergeType;
import jp.ac.fit.asura.naoji.robots.NaoV3R;
import jp.ac.fit.asura.naoji.robots.NaoV3R.InterpolationType;
import org.apache.log4j.Logger;
/**
* @author $Author: sey $
*
* @version $Id: $
*
*/
public class NaojiDriver {
private static final Logger log = Logger.getLogger(NaojiDriver.class);
protected JALMemory memory;
protected JALMotion motion;
protected JDCM dcm;
protected JALTextToSpeech tts;
private int bodyAliasId;
private int headAliasId;
private boolean eHasHeadCommand;
private float[] eHeadAngles;
private int[] eHeadDurations;
private boolean eHasBodyCommand;
private float[] eBodyAngles;
private int[] eBodyDurations;
public NaojiDriver(NaojiContext context) {
JALBroker broker = context.getParentBroker();
memory = broker.createJALMemory();
motion = broker.createJALMotion();
dcm = broker.createJDCM();
tts = broker.createJALTextToSpeech();
String[] names = motion.getBodyJointNames();
Joint[] joints = Joint.values();
eHeadAngles = new float[2];
eHeadDurations = new int[2];
eBodyAngles = new float[joints.length - 2];
eBodyDurations = new int[joints.length - 2];
List<String> bodyJoints = new ArrayList<String>();
log.debug("Joint names:" + Arrays.toString(names));
for (int i = 0; i < joints.length; i++) {
Joint j = joints[i];
if (j != Joint.HeadPitch && j != Joint.HeadYaw)
bodyJoints.add(j.name() + "/Position/Actuator/Value");
assert j != null;
assert j.name().equals(names[i]) : "Invalid order of joint:" + j;
}
bodyAliasId = dcm.createAlias(bodyJoints.toArray(new String[0]));
headAliasId = dcm.createAlias(new String[] {
"HeadYaw/Position/Actuator/Value",
"HeadPitch/Position/Actuator/Value" });
// timeKey = memory.defineKey("DCM/Time");
}
public class NaojiSensor implements Sensor {
FloatQuery floatQuery;
BooleanFilter resetFilterR;
BooleanFilter resetFilterL;
BooleanFilter resetFilterC;
public NaojiSensor() {
resetFilterR = new AverageFilter.Boolean(200);
resetFilterL = new AverageFilter.Boolean(200);
resetFilterC = new AverageFilter.Boolean(200);
}
@Override
public void init() {
log.info("init NaojiSensor.");
List<String> fKeys = new ArrayList<String>();
fKeys.add("Device/SubDeviceList/InertialSensor/AccX/Sensor/Value");
fKeys.add("Device/SubDeviceList/InertialSensor/AccY/Sensor/Value");
fKeys.add("Device/SubDeviceList/InertialSensor/AccZ/Sensor/Value");
fKeys.add("Device/SubDeviceList/InertialSensor/GyrX/Sensor/Value");
fKeys.add("Device/SubDeviceList/InertialSensor/GyrY/Sensor/Value");
fKeys
.add("Device/SubDeviceList/InertialSensor/AngleX/Sensor/Value");
fKeys
.add("Device/SubDeviceList/InertialSensor/AngleY/Sensor/Value");
// FSRもfloatらしい.
fKeys.add("Device/SubDeviceList/LFoot/FSR/FrontLeft/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/FSR/FrontRight/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/FSR/RearLeft/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/FSR/RearRight/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/FSR/FrontLeft/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/FSR/FrontRight/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/FSR/RearLeft/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/FSR/RearRight/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/CenterOfForceX/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/CenterOfForceY/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/CenterOfForceX/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/CenterOfForceY/Sensor/Value");
fKeys.add("Device/SubDeviceList/ChestBoard/Button/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/Bumper/Left/Sensor/Value");
fKeys.add("Device/SubDeviceList/LFoot/Bumper/Right/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/Bumper/Left/Sensor/Value");
fKeys.add("Device/SubDeviceList/RFoot/Bumper/Right/Sensor/Value");
for (Joint j : Joint.values()) {
fKeys.add("Device/SubDeviceList/" + j.name()
+ "/Position/Sensor/Value");
}
floatQuery = memory.createFloatQuery(fKeys);
}
@Override
public SensorContext create() {
return new NaojiSensorContext();
}
@Override
public void update(SensorContext sensorContext) {
NaojiSensorContext context = (NaojiSensorContext) sensorContext;
floatQuery.update();
FloatBuffer fb = floatQuery.getBuffer();
fb.get(context.accels);
fb.get(context.gyros);
fb.get(context.inertialAngles);
fb.get(context.forces);
fb.get(context.cofPositions);
fb.get(context.witches);
fb.get(context.angles);
assert !fb.hasRemaining() : fb;
fb.position(0);
if (log.isTraceEnabled()) {
log.trace("Accels data:" + Arrays.toString(context.accels));
log.trace("Gyros data:" + Arrays.toString(context.gyros));
log.trace("InertialAngles data:"
+ Arrays.toString(context.inertialAngles));
log.trace("Forces data:" + Arrays.toString(context.forces));
log.trace("CofPositions data:"
+ Arrays.toString(context.cofPositions));
log.trace("Switches data:" + Arrays.toString(context.witches));
log.trace("Joints data:" + Arrays.toString(context.angles));
}
context.time = System.currentTimeMillis();
boolean leftPressed = context.getSwitch(Switch.LFootLeft)
&& context.getSwitch(Switch.LFootRight);
boolean rightPressed = context.getSwitch(Switch.RFootLeft)
&& context.getSwitch(Switch.RFootRight);
boolean chestPressed = context.getSwitch(Switch.Chest);
boolean doReset = (resetFilterL.eval(leftPressed) || resetFilterR
.eval(rightPressed))
&& resetFilterC.eval(chestPressed);
if (doReset && resetFilterL.isFilled() && resetFilterR.isFilled()
&& resetFilterC.isFilled()) {
log.warn("Manual reset called. restart naoqi.");
try {
Runtime.getRuntime().exec("/etc/init.d/naoqi restart");
// Runtime.getRuntime().exec("sh /etc/init.d/naoqi restart");
} catch (IOException e) {
log.error("", e);
}
resetFilterL.clear();
resetFilterR.clear();
resetFilterC.clear();
}
}
@Override
public void poll() {
memory.waitNextCycle();
}
@Override
public boolean isSupported(Function func) {
switch (func) {
case ACCEL:
case GYRO:
case FORCE:
case INERTIAL:
case JOINT_ANGLE:
case SWITCH:
return true;
default:
return false;
}
}
@Override
public void after() {
log.trace("after NaojiSensor.");
}
@Override
public void before() {
log.trace("before NaojiSensor.");
}
}
public class NaojiEffector implements Effector {
private int headYawTaskId;
private int headPitchTaskId;
@Override
public void init() {
log.trace("init NaojiEffector.");
}
@Override
public void after() {
log.trace("after NaojiEffector.");
if (motion.walkIsActive()) {
if (eHasHeadCommand)
doHeadCommandALMotion();
} else {
if (eHasHeadCommand)
doHeadCommandDCM();
if (eHasBodyCommand) {
motion.setJointStiffness(NaoV3R.Joint.RHipPitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipPitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.RHipYawPitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipYawPitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.RHipRoll.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipRoll.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.RAnkleRoll.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LAnkleRoll.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.RKneePitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LKneePitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.RAnklePitch.getId(),
1.0f);
motion.setJointStiffness(NaoV3R.Joint.LAnklePitch.getId(),
1.0f);
// FIXME setTimeMixedにして個別に実行時間を指定する.
dcm.setTimeSeparate(bodyAliasId, MergeType.ClearAll,
eBodyAngles, new int[] { 200 });
}
}
eHasHeadCommand = false;
eHasBodyCommand = false;
}
private void doHeadCommandDCM() {
// FIXME setTimeMixedにして個別に実行時間を指定する.
int duration = eHeadDurations[Joint.HeadPitch.ordinal()];
dcm.setTimeSeparate(headAliasId, MergeType.ClearAll, eHeadAngles,
new int[] { duration });
}
private void doHeadCommandALMotion() {
float ms1 = eHeadDurations[Joint.HeadPitch.ordinal()] / 1e3f;
motion.stop(headYawTaskId);
motion.stop(headPitchTaskId);
headPitchTaskId = motion.gotoAngle(Joint.HeadPitch.ordinal(),
eHeadAngles[Joint.HeadPitch.ordinal()], ms1,
InterpolationType.LINEAR.getId());
float ms2 = eHeadDurations[Joint.HeadYaw.ordinal()] / 1e3f;
headYawTaskId = motion.gotoAngle(Joint.HeadYaw.ordinal(),
eHeadAngles[Joint.HeadYaw.ordinal()], ms2,
InterpolationType.LINEAR.getId());
}
@Override
public void before() {
log.trace("before NaojiEffector.");
}
@Override
public void setForce(Joint joint, float valueTorque) {
// Not implemented.
}
@Override
public void setJoint(Joint joint, float valueInRad) {
setJoint(joint, valueInRad, 250);
}
@Override
public void setJoint(Joint joint, float valueInRad, int durationInMills) {
if (log.isTraceEnabled())
log.trace("setJoint " + joint + " to "
+ MathUtils.toDegrees(valueInRad) + "[deg] in "
+ durationInMills + "[ms]");
switch (joint) {
case HeadYaw:
case HeadPitch:
eHeadAngles[joint.ordinal()] = valueInRad;
eHeadDurations[joint.ordinal()] = durationInMills;
eHasHeadCommand = true;
return;
default:
eBodyAngles[joint.ordinal() - 2] = valueInRad;
eBodyDurations[joint.ordinal() - 2] = durationInMills;
eHasBodyCommand = true;
return;
}
}
@Override
public void setJoint(Joint joint, float[] angleValues,
int[] durationInMills) {
dcm.set(joint.name() + "/Position/Actuator/Value",
MergeType.ClearAll, angleValues, durationInMills);
}
@Override
public void setJointDegree(Joint joint, float valueInDeg) {
setJoint(joint, (float) Math.toRadians(valueInDeg));
}
@Override
public void setJointMicro(Joint joint, int valueInMicroRad) {
setJoint(joint, valueInMicroRad / 1e6f);
}
@Override
public void setBodyJoints(float[] angleMatrix, int[] durationInMills) {
motion.setJointStiffness(NaoV3R.Joint.RHipPitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipPitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.RHipYawPitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipYawPitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.RHipRoll.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LHipRoll.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.RAnkleRoll.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LAnkleRoll.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.RKneePitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LKneePitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.RAnklePitch.getId(), 1.0f);
motion.setJointStiffness(NaoV3R.Joint.LAnklePitch.getId(), 1.0f);
motion.setTimeSeparate(angleMatrix, durationInMills,
InterpolationType.LINEAR.getId());
// dcm.setTimeSeparate(bodyAliasId, MergeType.ClearAll, angleMatrix,
// durationInMills);
}
@Override
public void setLed(String ledName, float luminance) {
assert luminance >= 0 && luminance <= 1 : luminance;
dcm.set(ledName + "/Actuator/Value", MergeType.ClearAll,
new float[] { luminance }, new int[] { 0 });
}
@Override
public void setPower(float power) {
assert power >= 0 && power <= 1 : power;
// Set stiffness
int taskId = motion.gotoBodyStiffness(power, 0.5f,
InterpolationType.LINEAR.getId());
motion.wait(taskId, 0);
}
@Override
public void setPower(Joint joint, float power) {
assert power >= 0 && power <= 1 : power;
int taskId = motion.gotoJointStiffness(joint.ordinal(), power,
0.125f, InterpolationType.LINEAR.getId());
motion.wait(taskId, 0);
}
@Override
public void say(String text) {
tts.say(text);
}
}
}