/**
*
*/
package org.goko.controller.tinyg.commons.probe;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Executors;
import org.apache.commons.collections.CollectionUtils;
import org.goko.controller.tinyg.commons.AbstractTinyGControllerService;
import org.goko.core.common.exception.GkException;
import org.goko.core.common.measure.quantity.Length;
import org.goko.core.controller.bean.EnumControllerAxis;
import org.goko.core.controller.bean.ProbeRequest;
import org.goko.core.controller.bean.ProbeResult;
import org.goko.core.gcode.element.IGCodeProvider;
import org.goko.core.gcode.rs274ngcv3.IRS274NGCService;
import org.goko.core.gcode.rs274ngcv3.context.EnumDistanceMode;
import org.goko.core.gcode.rs274ngcv3.context.GCodeContext;
import org.goko.core.gcode.rs274ngcv3.element.InstructionProvider;
import org.goko.core.gcode.rs274ngcv3.instruction.SetDistanceModeInstruction;
import org.goko.core.gcode.rs274ngcv3.instruction.SetFeedRateInstruction;
import org.goko.core.gcode.rs274ngcv3.instruction.StraightFeedInstruction;
import org.goko.core.gcode.rs274ngcv3.instruction.StraightProbeInstruction;
import org.goko.core.math.Tuple6b;
/**
* @author Psyko
* @date 22 janv. 2017
*/
public class ProbeUtility {
private List<ProbeCallable> lstProbeCallable;
private AbstractTinyGControllerService<?, ?, ?, ?, ?, ?> controllerService;
private ExecutorCompletionService<ProbeResult> completionService;
private IGCodeProvider probeGCodeProvider;
/**
* @param gcodeService
*/
public ProbeUtility(AbstractTinyGControllerService<?, ?, ?, ?, ?, ?> controllerService) {
super();
this.controllerService = controllerService;
}
private IRS274NGCService getGCodeService(){
return controllerService.getGCodeService();
}
public void prepare(List<ProbeRequest> lstProbeRequest) throws GkException {
Executor executor = Executors.newSingleThreadExecutor();
completionService = new ExecutorCompletionService<ProbeResult>(executor);
this.lstProbeCallable = new ArrayList<>();
for (int i = 0; i < lstProbeRequest.size(); i++) {
ProbeCallable probeCallable = new ProbeCallable();
this.lstProbeCallable.add(probeCallable);
completionService.submit(probeCallable);
}
probeGCodeProvider = getProbingCode(lstProbeRequest, controllerService.getGCodeContext());
probeGCodeProvider.setCode("TinyG probing");
getGCodeService().addGCodeProvider(probeGCodeProvider);
probeGCodeProvider = controllerService.getGCodeService().getGCodeProvider(probeGCodeProvider.getId());// Required since internally the provider is a new one
}
public ExecutorCompletionService<ProbeResult> getExecutorCompletionService(){
return completionService;
}
public boolean isProbingInProgress(){
return CollectionUtils.isNotEmpty(lstProbeCallable);
}
public void handleProbeResult(boolean probed, Tuple6b position) throws GkException{
if(CollectionUtils.isNotEmpty(lstProbeCallable)){
ProbeResult probeResult = new ProbeResult();
probeResult.setProbed(probed);
probeResult.setProbedPosition(position);
ProbeCallable callable = lstProbeCallable.remove(0);
callable.setProbeResult(probeResult);
}
}
public void cancelActiveProbing() throws GkException{
if(CollectionUtils.isNotEmpty(lstProbeCallable)){
for (ProbeCallable probeCallable: lstProbeCallable) {
probeCallable.setProbeResult(null);
}
lstProbeCallable.clear();
}
}
public void clearProbingGCode() throws GkException{
if(probeGCodeProvider != null){
getGCodeService().deleteGCodeProvider(probeGCodeProvider.getId());
probeGCodeProvider = null;
}
}
private IGCodeProvider getProbingCode(List<ProbeRequest> lstProbeRequest, GCodeContext gcodeContext) throws GkException{
InstructionProvider instrProvider = new InstructionProvider();
// Force distance mode to absolute
instrProvider.addInstruction( new SetDistanceModeInstruction(EnumDistanceMode.ABSOLUTE) );
for (ProbeRequest probeRequest : lstProbeRequest) {
Tuple6b clearancePoint = getProbeAxisPosition(probeRequest, probeRequest.getClearance());
Tuple6b probeStartPoint = getProbeAxisPosition(probeRequest, probeRequest.getProbeStart());
Tuple6b probeEndPoint = getProbeAxisPosition(probeRequest, probeRequest.getProbeEnd());
Tuple6b probePoint = getProbePoint(probeRequest);
// Move to clearance coordinate
instrProvider.addInstruction( new SetFeedRateInstruction(probeRequest.getMotionFeedrate()) );
instrProvider.addInstruction( new StraightFeedInstruction(clearancePoint.getX(), clearancePoint.getY(), clearancePoint.getZ(), null, null, null) );
// Move to probe position
instrProvider.addInstruction( new StraightFeedInstruction(probePoint.getX(), probePoint.getY(), probePoint.getZ(), null, null, null) );
// Move to probe start position
instrProvider.addInstruction( new StraightFeedInstruction(probeStartPoint.getX(), probeStartPoint.getY(), probeStartPoint.getZ(), null, null, null) );
// Actual probe command
instrProvider.addInstruction( new SetFeedRateInstruction(probeRequest.getProbeFeedrate()) );
instrProvider.addInstruction( new StraightProbeInstruction(probeEndPoint.getX(), probeEndPoint.getY(), probeEndPoint.getZ(), null, null, null) );
// Move to clearance coordinate
instrProvider.addInstruction( new SetFeedRateInstruction(probeRequest.getMotionFeedrate()) );
instrProvider.addInstruction( new StraightFeedInstruction(clearancePoint.getX(), clearancePoint.getY(), clearancePoint.getZ(), null, null, null) );
}
return getGCodeService().getGCodeProvider(gcodeContext, instrProvider);
}
/**
* Generates a position along the probing axis
* @param request the probe request
* @param position the position
* @return Tuple6b
*/
private Tuple6b getProbeAxisPosition(ProbeRequest request, Length position){
Tuple6b clearance = new Tuple6b().setNull();
if(request.getAxis() == EnumControllerAxis.X_POSITIVE
|| request.getAxis() == EnumControllerAxis.X_NEGATIVE){
clearance.setX(position);
}else if(request.getAxis() == EnumControllerAxis.Y_POSITIVE
|| request.getAxis() == EnumControllerAxis.Y_NEGATIVE){
clearance.setY(position);
}else if(request.getAxis() == EnumControllerAxis.Z_POSITIVE
|| request.getAxis() == EnumControllerAxis.Z_NEGATIVE){
clearance.setZ(position);
}
return clearance;
}
/**
* Generates a position in the plane whose normal is the probe axis
* @param request the probe request
* @param position the position
* @return Tuple6b
*/
private Tuple6b getProbePoint(ProbeRequest request){
Tuple6b probePoint = new Tuple6b().setNull();
if(request.getAxis() == EnumControllerAxis.X_POSITIVE
|| request.getAxis() == EnumControllerAxis.X_NEGATIVE){
probePoint.setY(request.getProbeCoordinate().getY());
probePoint.setZ(request.getProbeCoordinate().getZ());
}else if(request.getAxis() == EnumControllerAxis.Y_POSITIVE
|| request.getAxis() == EnumControllerAxis.Y_NEGATIVE){
probePoint.setX(request.getProbeCoordinate().getX());
probePoint.setZ(request.getProbeCoordinate().getZ());
}else if(request.getAxis() == EnumControllerAxis.Z_POSITIVE
|| request.getAxis() == EnumControllerAxis.Z_NEGATIVE){
probePoint.setX(request.getProbeCoordinate().getX());
probePoint.setY(request.getProbeCoordinate().getY());
}
return probePoint;
}
/**
* @return the probeGCodeProvider
*/
public IGCodeProvider getProbeGCodeProvider() {
return probeGCodeProvider;
}
}