1 package com.neuronrobotics.bowlerstudio.creature;
4 import java.io.IOException;
5 import java.nio.file.Files;
6 import java.nio.file.Paths;
7 import java.nio.file.WatchEvent;
8 import java.text.DecimalFormat;
9 import java.util.ArrayList;
10 import java.util.Collection;
11 import java.util.Comparator;
12 import java.util.HashMap;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.List;
17 import java.util.stream.Collectors;
19 import org.eclipse.jgit.api.errors.GitAPIException;
20 import org.eclipse.jgit.api.errors.InvalidRemoteException;
21 import org.eclipse.jgit.api.errors.TransportException;
23 import com.neuronrobotics.bowlerstudio.IssueReportingExceptionHandler;
24 import com.neuronrobotics.bowlerstudio.physics.TransformFactory;
25 import com.neuronrobotics.bowlerstudio.printbed.PrintBedManager;
26 import com.neuronrobotics.bowlerstudio.scripting.ScriptingEngine;
27 import com.neuronrobotics.bowlerstudio.util.FileChangeWatcher;
28 import com.neuronrobotics.bowlerstudio.util.FileWatchDeviceWrapper;
29 import com.neuronrobotics.bowlerstudio.util.IFileChangeListener;
30 import com.neuronrobotics.bowlerstudio.vitamins.VitaminBomManager;
31 import com.neuronrobotics.bowlerstudio.vitamins.Vitamins;
32 import com.neuronrobotics.sdk.addons.kinematics.AbstractKinematicsNR;
33 import com.neuronrobotics.sdk.addons.kinematics.AbstractLink;
34 import com.neuronrobotics.sdk.addons.kinematics.DHLink;
35 import com.neuronrobotics.sdk.addons.kinematics.DHParameterKinematics;
36 import com.neuronrobotics.sdk.addons.kinematics.ILinkConfigurationChangeListener;
37 import com.neuronrobotics.sdk.addons.kinematics.ILinkListener;
38 import com.neuronrobotics.sdk.addons.kinematics.IOnMobileBaseRenderChange;
39 import com.neuronrobotics.sdk.addons.kinematics.IRegistrationListenerNR;
40 import com.neuronrobotics.sdk.addons.kinematics.ITaskSpaceUpdateListenerNR;
41 import com.neuronrobotics.sdk.addons.kinematics.LinkConfiguration;
42 import com.neuronrobotics.sdk.addons.kinematics.MobileBase;
43 import com.neuronrobotics.sdk.addons.kinematics.math.TransformNR;
44 import com.neuronrobotics.sdk.addons.kinematics.parallel.ParallelGroup;
45 import com.neuronrobotics.sdk.common.BowlerAbstractDevice;
46 import com.neuronrobotics.sdk.common.IDeviceConnectionEventListener;
47 import com.neuronrobotics.sdk.pid.PIDLimitEvent;
48 import com.neuronrobotics.sdk.util.ThreadUtil;
49 import eu.mihosoft.vrl.v3d.CSG;
50 import eu.mihosoft.vrl.v3d.FileUtil;
51 import eu.mihosoft.vrl.v3d.parametrics.CSGDatabase;
52 import javafx.beans.property.*;
53 import javafx.scene.transform.Affine;
54 import javafx.application.Platform;
59 private static HashMap<MobileBase, MobileBaseCadManager>
cadmap =
new HashMap<>();
63 private ArrayList<MobileBaseCadManager>
slaves =
new ArrayList<MobileBaseCadManager>();
67 private HashMap<DHParameterKinematics, ArrayList<CSG>>
DHtoCadMap =
new HashMap<>();
68 private HashMap<LinkConfiguration, ArrayList<CSG>>
LinktoCadMap =
new HashMap<>();
69 private HashMap<MobileBase, ArrayList<CSG>>
BasetoCadMap =
new HashMap<>();
73 private ArrayList<CSG>
allCad =
new ArrayList<>();
75 private boolean bail =
false;
80 private DoubleProperty
pi =
new SimpleDoubleProperty(0);
85 private static ArrayList<Runnable>
toRun =
new ArrayList<Runnable>();
86 private ArrayList<IRenderSynchronizationEvent>
rendersync=
new ArrayList<>();
101 }
catch(Exception e) {
121 ArrayList<CSG> arrayList =
DHtoCadMap.get(key);
122 if (arrayList !=
null)
129 if (arrayList !=
null)
135 if (arrayList !=
null)
148 private static class IMobileBaseUIlocal
implements IMobileBaseUI {
150 public ArrayList<CSG> list =
new ArrayList<>();
153 public void highlightException(File fileEngineRunByName, Throwable ex) {
154 new Exception(
"Caught here:").printStackTrace();
155 ex.printStackTrace();
159 public void setAllCSG(Collection<CSG> toAdd, File source) {
167 public void addCSG(Collection<CSG> toAdd, File source) {
174 public Set<CSG> getVisibleCSGs() {
176 return new HashSet<CSG>(list);
180 public void setSelectedCsg(Collection<CSG> selectedCsg) {
186 public void setSelected(Affine rootListener) {
194 throw new NullPointerException();
204 HashMap<DHParameterKinematics, double[]> jointPoses =
new HashMap<>();
205 HashMap<Affine, TransformNR> tmp =
new HashMap<>();
206 boolean rendering =
false;
207 boolean changed =
false;
211 public void onIOnMobileBaseRenderChange() {
212 synchronized (jointPoses) {
246 kin.addRegistrationListener(r);
249 addConfL(
base,confL);
255 }
while (rendering || changed ==
false);
256 }
catch (InterruptedException e) {
278 HashMap<DHParameterKinematics, double[]> jointPosesTmp;
279 synchronized (jointPoses) {
280 jointPosesTmp = jointPoses;
281 jointPoses =
new HashMap<>();
285 jointPosesTmp.clear();
286 jointPosesTmp =
null;
288 Affine[] iterator = tmp.keySet().stream().toArray(size->new Affine[size]);
291 if (iterator.length > 0) {
292 Platform.runLater(() -> {
294 for (
int i = 0; i < iterator.length; i++) {
295 Affine af = iterator[i];
298 }
catch (Throwable t) {
310 if (
toRun.size() > 0) {
311 ArrayList<Runnable> t =
toRun;
312 toRun =
new ArrayList<Runnable>();
313 Platform.runLater(() -> {
315 for (
int i = 0; i < t.size(); i++) {
316 Runnable runnable = t.get(i);
317 if (runnable !=
null)
321 }
catch (Throwable tr) {
322 tr.printStackTrace();
327 }
catch (Throwable t) {
333 }
catch (InterruptedException e) {
345 for(
int i=0;i<k.getNumberOfLinks();i++) {
346 k.getAbstractLink(i).addChangeListener(confL2);
347 addConfL(k.getSlaveMobileBase(i),confL2);
362 jointPoses.put(k, k.getCurrentJointSpaceVector());
365 for (
int i = 0; i < k.getNumberOfLinks(); i++) {
390 for (
int i = 0; i < ll.size(); i++) {
399 }
catch (java.lang.ClassCastException ex) {
410 if (nr !=
null && af !=
null)
426 }
catch (Exception e) {
435 if (forwardOffset !=
null )
438 if (k.getRootListener() ==
null) {
439 k.setRootListener(
new Affine());
443 map2.put((Affine) k.getRootListener(), fo);
446 return forwardOffset;
466 String key = args[0] +
":" + args[1];
474 }
catch (Throwable e) {
479 Exception ex =
new Exception(
"CAD script declared here and regenerated");
483 public void onFileChange(File fileThatChanged, WatchEvent event) {
487 System.err.println(
"Clearing the compiled CAD script for " + key);
489 ex.printStackTrace();
491 }
catch (Exception e) {
497 public void onFileDelete(File fileThatIsDeleted) {
517 }
catch (GitAPIException | IOException e) {
521 throw new RuntimeException(
"File Missing!");
526 String key = args[0] +
":" + args[1];
532 }
catch (InvalidRemoteException e) {
535 }
catch (TransportException e) {
538 }
catch (GitAPIException e) {
541 }
catch (IOException e) {
551 Object cadForBodyEngine =
scriptFromFileInfo(b.getScriptingName(),b.getGitCadEngine(), () -> {
564 Object cadForBodyEngine =
scriptFromFileInfo(dh.getScriptingName(),dh.getGitCadEngine(), () -> {
587 "https://github.com/CommonWealthRobotics/DHParametersCadDisplay.git",
"dhcad.groovy" }, () -> {
591 mobileBaseCadManager =
cadmap.get(manager);
596 }
catch (Exception e) {
597 if (mobileBaseCadManager !=
null)
613 throw new RuntimeException(
"Device " +
base.
getScriptingName() +
" is not connected, can not generate cad");
637 ArrayList<CSG> newcad =
null;
640 }
catch (Throwable t) {
643 if (newcad ==
null) {
644 newcad =
new ArrayList<CSG>();
646 if (newcad.size() == 0) {
650 for (
CSG c : newcad) {
672 }
catch (Throwable e) {
675 System.out.println(
"Displaying Body");
679 System.out.println(
"Rendering limbs");
682 double numLimbs = limbs.size();
692 for (
CSG csg : arrayList) {
695 set(
base, (int) i, (
int) j);
705 for (
CSG csg : linksCad) {
720 getAllCad().addAll(m.generateBody(m.base,
false));
736 }
catch (Exception e) {
746 }
catch (Exception e) {
755 int numLimbs = limbs.size();
756 if (limb >= numLimbs) {
761 double progress = ((double) ((limb * dh.
getNumberOfLinks()) + link)) / partsTotal;
771 if (cadTest == cad) {
787 if (bed ==
null || kinematic) {
791 System.out.println(
"Found arrangeBed API in CAD engine");
800 if(bomCSV.exists()) {
802 File file =
new File(baseDirForFiles.getAbsolutePath()+
"/bom.csv");
805 Files.copy(bomCSV.toPath(),file.toPath());
809 File file =
new File(baseDirForFiles.getAbsolutePath()+
"/bom.json");
812 Files.copy(bom.toPath(),file.toPath());
816 }
catch(Throwable T) {
817 throw new RuntimeException(T.getMessage());
820 File printArrangment =
new File(baseWorkspaceFile.getAbsolutePath()+
"/"+
PrintBedManager.
file);
821 if(printArrangment.exists()) {
829 ArrayList<File> allCadStl =
new ArrayList<>();
831 double numLimbs = limbs.size();
834 ArrayList<CSG> totalAssembly =
new ArrayList<>();
836 for (i = 0; i < limbs.size(); i += 1) {
838 double progress = (1.0 - ((numLimbs - i) / numLimbs)) / 2;
843 for (
int j = 0; j < parts.size(); j++) {
844 CSG csg = parts.get(j);
856 if (totalAssembly.size() > 0 && !kinematic)
857 totalAssembly.add(tmp.
movey(.5 + totalAssembly.get(totalAssembly.size() - 1).getMaxY()
860 totalAssembly.add(tmp);
871 dir.getAbsolutePath() +
"/" + linkNum + name +
"_limb_" + i +
"_Part_" + j +
".stl");
872 System.out.println(
"Writing STL for " + name+
" to "+stl.getAbsolutePath());
879 System.err.println(
"ERROR "+parts.get(j).getName()+
" has no link associated ");
882 }
catch (Exception ex) {
900 String name = csg.getName();
903 csg = csg.prepForManufacturing();
906 csg = csg.toYMin().movex(-2 - csg.getMaxX() + offset);
911 File stl =
new File(dir.getAbsolutePath() +
"/" + name +
"_Body_part_" + link +
".stl");
912 FileUtil.
write(Paths.get(stl.getAbsolutePath()), csg.toStlString());
914 totalAssembly.add(csg);
918 }
catch (Exception ex) {
938 throw new RuntimeException(
"Can not duplicat mobile base");
940 for (
int i = 0; i < dh.getNumberOfLinks(); i++) {
941 if (dh.getSlaveMobileBase(i) == b)
942 throw new RuntimeException(
"Can not duplicat mobile base!!");
952 k.setRenderWrangler(
this);
963 new Exception(
"This listener called from the wrong device!! " + arg0.
getScriptingName())
969 k.setRenderWrangler(
null);
993 ArrayList<CSG> dhLinks =
new ArrayList<>();
1009 set(
base, (int) j, (
int) i);
1012 ArrayList<CSG> newcad =
null;
1015 }
catch (Throwable t) {
1018 if (newcad ==
null) {
1019 newcad =
new ArrayList<CSG>();
1021 if (newcad.size() == 0) {
1030 for (
CSG c : newcad) {
1041 public void onLinkPositionUpdate(
AbstractLink arg0,
double arg1) {
1056 dhLinks.addAll(slParts);
1062 }
catch (Throwable e) {
1063 e.printStackTrace();
1074 }
catch (Exception ex) {
1076 System.err.println(
"Base not loaded yet");
1087 }
catch (Exception ex) {
1089 System.err.println(
"Limb not loaded yet");
1098 }
catch (Exception ex) {
1099 System.err.println(
"Limb not loaded yet");
1115 System.out.print(
"\r\nGenerating CAD...\r\n");
1116 setName(
"MobileBaseCadManager Generating cad Thread ");
1119 for (
int i = 0; i <
allCad.size(); i++)
1127 }
catch (Exception e) {
1133 for (
int i = 0; i <
allCad.size(); i++)
1139 System.out.print(
"\r\nDone Generating CAD! num parts: " +
allCad.size() +
"\r\n");
1142 }
catch (InterruptedException e) {
1144 e.printStackTrace();
1157 throws InvalidRemoteException, TransportException, GitAPIException, IOException {
1159 dh.setGitCadEngine(
new String[] { gitsId, file });
1163 throws InvalidRemoteException, TransportException, GitAPIException, IOException {
1165 device.setGitCadEngine(
new String[] { gitsId, file });
1174 for (String p : part.getParameters()) {
1180 if (this.allCad !=
null && this.allCad !=
allCad)
1181 this.allCad.clear();
1186 if (
cadmap.get(device) ==
null) {
1193 if (!IMobileBaseUIlocal.class.isInstance(
ui)
1194 && IMobileBaseUIlocal.class.isInstance(mobileBaseCadManager.
getUi()))
1195 mobileBaseCadManager.
setUi(
ui);
1197 return mobileBaseCadManager;
1205 if (
cadmap.get(device) ==
null) {
1208 for (
int i = 0; i < kin.getNumberOfLinks(); i++) {
1209 MobileBase m = kin.getDhLink(i).getSlaveMobileBase();
1216 IMobileBaseUIlocal ui2 =
new IMobileBaseUIlocal();
1233 return get(device, ui2);
1235 return cadmap.get(device);
1303 System.out.println(
"Setting config mode " + b);
1306 m.setConfigurationViewerMode(b);
ArrayList< File > generateManufacturingParts(List< CSG > totalAssembly, File baseDirForFiles)
ArrayList< File > generateStls(MobileBase base, File baseDirForFiles, boolean kinematic)
static ICadGenerator cadEngineConfiguration
ArrayList< CSG > localGetBaseCad(MobileBase device)
void selectCsgByMobileBase(MobileBase base)
void setMaster(MobileBaseCadManager master)
ICadGenerator getConfigurationDisplay()
ArrayList< CSG > getAllCad()
static ArrayList< CSG > getBaseCad(MobileBase device)
MobileBaseCadManager master
void addIRenderSynchronizationEvent(IRenderSynchronizationEvent ev)
void removeIRenderSynchronizationEvent(IRenderSynchronizationEvent ev)
ArrayList< CSG > generateCad(DHParameterKinematics dh)
void invalidateModelCache()
MobileBase getMobileBase()
HashMap< String, Object > cadScriptCache
MobileBaseCadManager(MobileBase base, IMobileBaseUI myUI)
HashMap< LinkConfiguration, ArrayList< CSG > > LinktoCadMap
void setAllCad(ArrayList< CSG > allCad)
int getCADProgressPercent()
void setProcesIndictor(DoubleProperty pi)
LinkConfiguration getLinkConfiguration(CSG cad)
HashMap< DHParameterKinematics, ArrayList< CSG > > DHtoCadMap
void setDHtoCadMap(HashMap< DHParameterKinematics, ArrayList< CSG >> dHtoCadMap)
void setBasetoCadMap(HashMap< MobileBase, ArrayList< CSG >> basetoCadMap)
void loadJointPose(MobileBase base, HashMap< DHParameterKinematics, double[]> jointPoses)
static MobileBaseCadManager get(MobileBase device, IMobileBaseUI ui)
HashMap< LinkConfiguration, ArrayList< CSG > > getLinktoCadMap()
File getCadScriptFromMobileBase(MobileBase device)
ArrayList< CSG > generateBody()
TransformNR updateBase(MobileBase base, TransformNR baseLoc, HashMap< Affine, TransformNR > map2)
void selectCsgByLimb(MobileBase base, DHParameterKinematics limb)
void setConfigurationViewerMode(boolean b)
IgenerateCad getIgenerateCad(DHParameterKinematics dh)
ArrayList< CSG > generateBody(MobileBase base, boolean clear)
File getCadScriptFromLimnb(DHParameterKinematics l)
ArrayList< IRenderSynchronizationEvent > rendersync
static ArrayList< Runnable > toRun
ArrayList< File > _generateStls(MobileBase base, File baseDirForFiles, boolean kinematic)
static void runLater(Runnable r)
void setGitCadEngine(String gitsId, String file, DHParameterKinematics dh)
ArrayList< MobileBaseCadManager > slaves
void updateMobileBase(MobileBase b, TransformNR baseLoc, HashMap< Affine, TransformNR > map2, HashMap< DHParameterKinematics, double[]> jointPoses)
static HashMap< LinkConfiguration, ArrayList< CSG > > getSimplecad(MobileBase device)
void setGitCadEngine(String gitsId, String file, MobileBase device)
HashMap< DHParameterKinematics, ArrayList< CSG > > getDHtoCadMap()
void selectCsgByLink(MobileBase base, LinkConfiguration limb)
DoubleProperty getProcesIndictor()
IgenerateBody getIgenerateBody(MobileBase b)
void updateLimb(DHParameterKinematics k, TransformNR baseLoc, HashMap< Affine, TransformNR > map2, HashMap< DHParameterKinematics, double[]> jointPoses)
void setMobileBase(MobileBase b)
void fireIRenderSynchronizationEvent()
void setUi(IMobileBaseUI ui)
IgenerateBed getIgenerateBed()
IgenerateBed getPrintBed(File baseDirForFiles, IgenerateBed bed, File baseWorkspaceFile)
void setLinktoCadMap(HashMap< LinkConfiguration, ArrayList< CSG >> linktoCadMap)
void closeScriptFromFileInfo(String[] args)
HashMap< MobileBase, ArrayList< CSG > > BasetoCadMap
Object scriptFromFileInfo(String name, String[] args, Runnable r)
HashMap< MobileBase, ArrayList< CSG > > getBasetoCadMap()
static HashMap< MobileBase, MobileBaseCadManager > cadmap
void setAutoRegen(boolean autoRegen)
static MobileBaseLoader get(MobileBase base)
static Object inlineFileScriptRun(File f, ArrayList< Object > args)
static File fileFromGit(String remoteURI, String fileInRepo)
static File getRepositoryCloneDirectory(String remoteURI)
static void close(File fileToWatch)
void removeIFileChangeListener(IFileChangeListener l)
void addIFileChangeListener(IFileChangeListener l)
static FileChangeWatcher watch(File fileToWatch)
static final String MANUFACTURING_BOM_JSON
static final String MANUFACTURING_BOM_CSV
AbstractLink getAbstractLink(int index)
TransformNR getFiducialToGlobalTransform()
LinkConfiguration getLinkConfiguration(int linkIndex)
void addRegistrationListener(IRegistrationListenerNR l)
void setGlobalToFiducialTransform(TransformNR frameToBase, boolean fireUpdate)
void setRenderWrangler(Runnable renderWrangler)
void setRootListener(Object listener)
String[] getGitCadEngine()
TransformNR forwardOffset(TransformNR t)
void setGlobalPositionListener(Object Object)
void addLinkListener(ILinkListener l)
Object getGlobalPositionListener()
ArrayList< TransformNR > getChain(double[] jointSpaceVector)
ArrayList< DHLink > getLinks()
void setListener(Object listener)
MobileBase getSlaveMobileBase()
MobileBase getSlaveMobileBase(int index)
void setGlobalToFiducialTransform(TransformNR frameToBase)
AbstractLink getLink(String name)
String[] getGitSelfSource()
void addIOnMobileBaseRenderChange(IOnMobileBaseRenderChange l)
ArrayList< DHParameterKinematics > getAllDHChains()
String getScriptingName()
void addConnectionEventListener(final IDeviceConnectionEventListener l)
CSG prepForManufacturing()
CSG movey(Number howFarToMove)
static void write(Path p, String s)
static void addParameterListener(String key, IParameterChanged l)
default void setCsg(CSG toAdd, File source)
void setSelectedCsg(Collection< CSG > selectedCsg)
void setAllCSG(Collection< CSG > toAdd, File source)
void addCSG(Collection< CSG > toAdd, File source)
void setSelected(Affine rootListener)
default void addCsg(CSG toAdd, File source)
void highlightException(File fileEngineRunByName, Throwable ex)
ArrayList< CSG > arrangeBed(MobileBase base)
ArrayList< CSG > generateBody(MobileBase base)
ArrayList< CSG > generateCad(DHParameterKinematics dh, int linkIndex)
void onIOnMobileBaseRenderChange()