package org.jactr.modules.pm.motor.command.translators;
/*
* default logging
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.commonreality.agents.IAgent;
import org.commonreality.efferent.ICompoundCommand;
import org.commonreality.efferent.IEfferentCommand;
import org.commonreality.modalities.motor.MotorUtilities;
import org.commonreality.modalities.motor.TranslateCommand;
import org.commonreality.object.IEfferentObject;
import org.commonreality.sensors.keyboard.PressCommand;
import org.commonreality.sensors.keyboard.ReleaseCommand;
import org.jactr.core.chunktype.IChunkType;
import org.jactr.core.model.IModel;
import org.jactr.core.production.request.ChunkTypeRequest;
import org.jactr.core.runtime.ACTRRuntime;
import org.jactr.core.slot.ISlot;
import org.jactr.modules.pm.motor.IMotorModule;
public class PeckTranslator extends AbstractManualTranslator
{
/**
* Logger definition
*/
static final transient Log LOGGER = LogFactory.getLog(PeckTranslator.class);
public boolean handles(ChunkTypeRequest request)
{
try
{
IChunkType actual = request.getChunkType();
IChunkType punch = actual.getModel().getDeclarativeModule().getChunkType(
"peck").get();
// return actual.isA(punch);
return actual.equals(punch);
}
catch (Exception e)
{
/**
* Error :
*/
LOGGER.error("Failed to get peck chunk type ", e);
return false;
}
}
protected double[] getTarget(ChunkTypeRequest request, IEfferentObject muscle)
{
double[] origin = MotorUtilities.getPosition(muscle);
double distance = Double.NaN;
double theta = Double.NaN;
for (ISlot slot : request.getSlots())
if (slot.getName().equalsIgnoreCase("r"))
distance = (Double) slot.getValue();
else if (slot.getName().equalsIgnoreCase("theta"))
theta = (Double) slot.getValue();
if (Double.isNaN(distance) || Double.isNaN(theta))
throw new IllegalArgumentException(
"Both theta and r must be defined when computing finger trajectories");
double dX = Math.cos(theta) * distance;
double dY = Math.sin(theta) * distance;
double[] target = new double[origin.length];
target[0] = origin[0] + dX;
target[1] = origin[1] + dY;
return target;
}
protected double computeDistance(double[] origin, double[] target)
{
double rtn = 0;
for(int i=0;i<origin.length;i++)
rtn += Math.abs(origin[i]-target[i])*Math.abs(origin[i]-target[i]);
return Math.sqrt(rtn);
}
public IEfferentCommand translate(ChunkTypeRequest request,
IEfferentObject muscle, IModel model) throws IllegalArgumentException
{
try
{
IAgent agent = ACTRRuntime.getRuntime().getConnector().getAgent(model);
IMotorModule motor = (IMotorModule) model.getModule(IMotorModule.class);
/*
* we need a compound, a press and a release
*/
ICompoundCommand compound = (ICompoundCommand) getTemplateNamed(
"compound", muscle).instantiate(agent, muscle);
TranslateCommand translate = (TranslateCommand) getTemplateNamed("translate", muscle)
.instantiate(agent, muscle);
double[] origin = MotorUtilities.getPosition(muscle);
double[] target = getTarget(request, muscle);
double[] peckRate = computeRate(origin, target, computeFitts(
getPeckFittsCoefficient(motor), computeDistance(origin, target), 1));
translate.translate(origin, target, peckRate);
double[] punchTarget = new double[] { target[0], target[1], 0 };
/*
* all the time for a peck is eaten up by the movement, not the punch..
* silly, but this is ACT-R cannonical
*/
double[] punchRate = computeRate(target, punchTarget, 0.000001);
PressCommand press = (PressCommand) getTemplateNamed("press", muscle)
.instantiate(agent, muscle);
press.press(target, punchTarget, punchRate);
ReleaseCommand release = (ReleaseCommand) getTemplateNamed("release",
muscle).instantiate(agent, muscle);
release.release(punchTarget, target, punchRate);
compound.add(translate);
compound.add(press);
compound.add(release);
return compound;
}
catch(IllegalArgumentException iae)
{
throw iae;
}
catch (Exception e)
{
throw new IllegalArgumentException("Could not create command for "+request+" ",e);
}
}
}