Closed petrasvestartas closed 4 years ago
I assume this issue is because you are using some tool that has 5 degrees of freedom (the rotation around the normal of the tool doesn't matter), and you're trying to search for solutions that are reachable given the same normal direction and position.
You can do this in a number of ways, depending on how the tool is mounted. Assuming the normal is perpendicular to the flange, rotate the tool around the normal depending on it position so that the 5th is extended (use the arm orientation as a vector guide to align the plane).
You could also use iterative approaches, incrementally rotating until you don't get an error. To do this faster, if its only on certain parts, use the kinematics component rather than the full create program component. If you use this be careful not to select solutions as soon as they don't give an error, have some margin, as the real robot might not not be exactly the same. You might want to make some small calibration adjustments without having to create a new program, also things like absolute accuracy will have slightly different joint positions as in the simulation.
Regarding the ABB library, you can find it here: https://developercenter.robotstudio.com/pc-sdk
Yes It is exactly this, because I am just milling and using saw-blade for cutting process.
Do you have examples what are explaining considering rotations?
I use Robots plugin for simulation, for real movement I need to export .txt file to our ABB robot, because the company installed specific software package considering robot controller. But the simulation is almost the same, and without robots it would be really painful to do anything.
I am somehow stuck in this grasshopper interface and seeking for your help to setup iterative approach for plane rotation. It would be a huge help, because each tool-path takes a day to setup.
Not that I can quickly post here, but it's not complicated and you are pretty good and Grasshopper and C#, I'm sure you will figure it out.
A really simple variation of option 1 is, assuming the robot base is in the world origin, connect an align plane component after the target planes and use the position of the target as the alignment vector (the X axis), you might have to rotate the tool 90/-90/180 degrees after this.
It is not a hurry, but do you think that you could help to set it up correctly?
Also I do not know how to reference ABB .dll correctly, it seems the project is a bit different that I use for grasshopper components:
Right click where it says 'dependencies' then 'add project reference' then 'browse'.
What I am missing:
Did you try removing it and adding it again?
I am trying to write this iterative solver after painful 2 weeks milling and saw-blading with the robot, I realized that I cannot rotate planes manually...
I would like to ask how can I create targets in C# ?
I see that input of the program component takes Targets as input list, but then it is somehow casted to toolpath. How can I manually write the target and append to GH_Toolpath list?
I am not very familiar with abstract classes.
var toolpathsA = new List<GH_Toolpath>(toolpathsA_.DataCount);
for (int i = 0; i < toolpathsA_.Branches.Count; i++)
{
// I would like to create Target here but do not know how
GH_Toolpath defaultToolpath = new GH_Toolpath(new IToolpath());
}
I tried this but also does not work
var toolpathsA = new List<GH_Toolpath>(toolpathsA_.DataCount);
for (int i = 0; i < toolpathsA_.Branches.Count; i++)
{
GH_Target sourceTarget = null;
sourceTarget.Value = new JointTarget(new double[] { 0,Math.PI*0.5,0,0,0,0 }, tool.Value);
//GH_Toolpath defaultToolpath = new GH_Toolpath(new IToolpath());
}
I found one way, but I do not know if it is right why targets have to be casted to a toolpath?
var toolpathsA = new List<GH_Toolpath>(toolpathsA_.DataCount);
for (int i = 0; i < toolpathsA_.Branches.Count; i++)
{
JointTarget jointTarget = new JointTarget(new double[] { 0, Math.PI * 0.5, 0, 0, 0, 0 }, tool.Value);
SimpleToolpath itoolpath = new SimpleToolpath();
itoolpath.Add(jointTarget);
GH_Toolpath toolpath = new GH_Toolpath(itoolpath);// (jointTargetGH.Value);
toolpathsA.Add(toolpath);
}
See here for a minimal robot program written in C#: https://github.com/visose/Robots/blob/master/RobotsStandalone/TestProgram.cs
The Grasshopper component "Create Program" accepts a list of objects that implement IToolpath.
This interface requires the implementing type to return a list of targets (an IEnumerable
You can connect a list of targets directly to Create Program because the Target class implements IToolpath. Each target returns an IEnumerable
Hi,
I think I got it, thank you, what might take some much time to compute these simple planes? I am running this code 2 times and it takes one second. There are 30 planes at one iteration.
Currently the code is just this:
protected override void SolveInstance(IGH_DataAccess DA)
{
//https://github.com/visose/Robots/blob/master/RobotsStandalone/TestProgram.cs
string name = null;
GH_RobotSystem robotSystem = null;
var initCommandsGH = new List<GH_Command>();
var toolpathsA_ = new GH_Structure<GH_Plane>();
var toolpathsB = new List<GH_Toolpath>();
var multiFileIndices = new List<int>();
double stepSize = 1;
GH_Tool tool = null;
var toolpathsA_Type = new GH_Structure<GH_String>();
if (!DA.GetData(0, ref name)) { return; }
if (!DA.GetData(1, ref robotSystem)) { robotSystem = new GH_RobotSystem(RobotSystem.Load("IBOIS-IRB6400B", new Rhino.Geometry.Plane(new Point3d(0, 0, 517), Vector3d.XAxis, Vector3d.YAxis))); }
if (!DA.GetDataTree(2, out toolpathsA_)) { return; }
DA.GetDataList(3, toolpathsB);
DA.GetDataList(4, initCommandsGH);
DA.GetDataList(5, multiFileIndices);
if (!DA.GetData(6, ref stepSize)) { return; }
if (!DA.GetData(8, ref tool)) { return; }
if (!DA.GetDataTree(7, out toolpathsA_Type)) { return; }
if (toolpathsA_.DataCount == 0 || toolpathsA_.DataCount != toolpathsA_Type.DataCount) return;
RobotConfigurations? configuration = null;
///////////////////////////////////////////
//Cast planes to targets
//Simple Tool Path contains targets, and toolpaths contains many toolpaths
///////////////////////////////////////////
var oneToolPath = new SimpleToolpath();
for (int i = 0; i < toolpathsA_.Branches.Count; i++) {
var oneToolPathCurrent = new SimpleToolpath();
////////////////////////////////////////////////////////////////////////
//Default plane that goes to 0
JointTarget jointTarget = new JointTarget(new double[] { 0, Math.PI * 0.5, 0, 0, 0, 0 }, tool.Value);
oneToolPathCurrent.Add(jointTarget);
////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//Plane Target
for (int j = 0; j < toolpathsA_.get_Branch(i).Count; j++) {
//Input planes
var JointType = toolpathsA_Type[i][j].Value == "Joint" ? Motions.Joint : Motions.Linear;
CartesianTarget cartesianTarget = new CartesianTarget(toolpathsA_[i][j].Value, configuration, JointType, tool.Value, Speed.Default, Zone.Default);
oneToolPathCurrent.Add(cartesianTarget);
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//Run Current Branch program
var allToolPathCurrent = new List<IToolpath>() { oneToolPathCurrent };
var programCurrent = new Program(name, robotSystem.Value, allToolPathCurrent, null, multiFileIndices, stepSize);
//////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//If there are no errors add them to final target list
if (programCurrent.Errors.Count == 0)
foreach (var t in oneToolPathCurrent)
oneToolPath.Add(t);
else
{
}
////////////////////////////////////////////////////////////////////////
}//for i
var allToolpaths = new List<IToolpath>() { oneToolPath };
var program = new Program(name, robotSystem.Value, allToolpaths, null, multiFileIndices, stepSize);
DA.SetData(0, new GH_Program(program));
///////////////////////////////////////////////////////////////////////////////
//Create Errors
///////////////////////////////////////////////////////////////////////////////
if (program.Errors.Count > 0)
{
DA.SetDataList(4, program.Errors);
this.AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Errors in program");
}
}
}
The plugin is not really optimized for performance, if I ever was to rewrite it I would make it considerably faster.
But I don't think that's the issue. If you have many long linear motions, you could increase the 'stepsize' variable to 100 mm or so. As you have it right now it will compute the robot position every 1 mm to check for errors, but this might not be necessary.
Thank you, as long as it produces good results it is worth waiting.
I would like to ask about axes limitations. Why the program stops at -92 rotations in axes 5, if the limit is -180? In the XML I constrain rotations like this.
<RobotSystems>
<RobotCell name="IBOIS-IRB6400B" manufacturer="ABB">
<Mechanisms>
<RobotArm model="IRB6400" manufacturer="ABB" payload="100">
<Base x="0.000" y="0.000" z="0.000" q1="1.000" q2="0.000" q3="0.000" q4="0.000"/>
<Joints>
<Revolute number="1" a ="240" d ="800" minrange = "-110" maxrange ="110" maxspeed ="110"/>
<Revolute number="2" a ="1050" d ="0" minrange = "-360" maxrange ="360" maxspeed ="110"/>
<Revolute number="3" a ="225" d ="0" minrange = "-360" maxrange ="360" maxspeed ="110"/>
<Revolute number="4" a ="0" d ="1520" minrange = "-360" maxrange ="360" maxspeed ="190"/>
<Revolute number="5" a ="0" d ="0" minrange = "-180" maxrange ="90" maxspeed ="150"/>
<Revolute number="6" a ="0" d ="200" minrange = "-180" maxrange ="180" maxspeed ="210"/>
</Joints>
</RobotArm>
</Mechanisms>
<IO>
<DO names="DO10_1,DO10_2,DO10_3,DO10_4,DO10_5,DO10_6,DO10_7,DO10_8,DO10_9,DO10_10,DO10_11,DO10_12,DO10_13,DO10_14,DO10_15,DO10_16"/>
<DI names="DI10_1,DI10_2,DI10_3,DI10_4,DI10_5,DI10_6,DI10_7,DI10_8,DI10_9,DI10_10,DI10_11,DI10_12,DI10_13,DI10_14,DI10_15,DO10_16"/>
</IO>
</RobotCell>
</RobotSystems>
The plugin rotation values in radians don't translate directly to degrees. More info here: https://github.com/visose/Robots/issues/8 Probably also discussed in another issue or the wiki.
Also see here: https://github.com/visose/Robots/issues/10
Sorry to ask too many questions but is this a right conversion?
No, that component is to convert from degrees to radians and not the other way around. I haven't exposed radians to degrees as a Grasshopper component since I haven't found the need to do this.
If you want to know if the axis in in the limit, plug the axis limit in degrees into that component to get the limit in radians and compare to the values in radians that you're getting.
I think I am lost.
Would it be possible to give an example to convert axes degrees correctly?
You almost have it. You mentioned the limit of axis 5 is -180 degrees. You just have to connect a panel with the value -180 to the D input of degrees component from the plugin. This will return a value in radians. This is the value you should compare to the J output of the simulation component. Don't transform the values from the J output to anything.
Sorry I still do not understand it:
Which part you don't understand? That grasshopper file seems good. Axis 5 is at an angle of 0 radians, which not close to its limit of -3.14159 radians.
Hi,
I have an issue, when trying to create a valid tool-path, I need to rotate manually planes 90 degrees until I reach a good rotation that is reachable. I would like to automate this process, because manually guessing is very slow.
Is there any ready-made examples for C Sharp I could use to mimic similar workflow to this?
If yes where can I get ABB library?