Skip to content

Commit

Permalink
Add KDL
Browse files Browse the repository at this point in the history
  • Loading branch information
visose committed Apr 8, 2023
1 parent 4f0035d commit ba4f900
Show file tree
Hide file tree
Showing 17 changed files with 307 additions and 66 deletions.
7 changes: 5 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<Product>Robots</Product>
<Version>1.6.4</Version>
<Version>1.6.5</Version>
<Authors>Robots Authors</Authors>
<Description>Create and simulate ABB, KUKA, UR, and Staubli robot programs.</Description>
<PackageTags>Robots;ABB;KUKA;UR;Staubli;Robotics</PackageTags>
Expand All @@ -21,7 +21,10 @@
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ArtifactsDir>$(MSBuildThisFileDirectory)artifacts\</ArtifactsDir>
<!--<AnalysisLevel>latest</AnalysisLevel>-->
<NoWarn>MSB3270</NoWarn>
<RootDir>$(MSBuildThisFileDirectory)</RootDir>
<ArtifactsDir>$(RootDir)artifacts\</ArtifactsDir>
<OutputPath>$(ArtifactsDir)bin\$(MSBuildProjectName)</OutputPath>
<BaseIntermediateOutputPath>$(ArtifactsDir)obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
</PropertyGroup>
Expand Down
12 changes: 12 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ distributed under licenses different than the Robots software.
In the event that we accidentally failed to list a required notice, please
bring it to our attention.

Kdl.NetStandard (MIT)
* Copyright (c) 2020 Doug Slater
* https://github.com/slater1/Kdl.NetStandard/blob/master/LICENSE

Orocos KDL (LGPL-v2)
* Copyright (с) Orocos
* https://www.orocos.org/content/orocos-licenses

Math.NET (MIT)
* Copyright (с) 2002-2022 Math.NET
* https://github.com/mathnet/mathnet-numerics/blob/master/LICENSE-MKL.md

OPW Kinematics (Apache-2.0)
* Copyright (с) Jonathan Meyer
* https://github.com/Jmeyer1292/opw_kinematics/blob/master/LICENSE
Expand Down
4 changes: 4 additions & 0 deletions RELEASE
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
- version: 1.6.5
changes:
- Added Orocos KDL solver for Franka Emika (Windows only)

- version: 1.6.4
changes:
- Fixes Franka Emika inverse kinematics
Expand Down
20 changes: 15 additions & 5 deletions build/Robots.Build/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@
using RhinoPackager.Commands;

var app = App.Create(args);
var github = new Github("visose", "Robots");
Props props = new("Directory.Build.props");
Github github = new("visose", "Robots");

app.Add(new ICommand[]
{
new Test
(
testProject: "tests/Robots.Tests/Robots.Tests.csproj"
),
new CheckVersion(github),
new CheckVersion
(
props: props,
github: github
),
new Build
(
buildProject: "src/Robots.Grasshopper/Robots.Grasshopper.csproj"
),
new Yak
(
propsFile: "Directory.Build.props",
props: props,
sourceFolder: "artifacts/bin/Robots.Grasshopper/net48",
files: new []
{
Expand All @@ -27,7 +32,9 @@
"RobotStudio.Services.RobApi.Desktop.dll",
"RobotStudio.Services.RobApi.dll",
"Renci.SshNet.dll",
"MathNet.Numerics.dll"
"MathNet.Numerics.dll",
"Kdl.NetStandard.dll",
"kdl_wrap.dll"
},
tags: new []
{
Expand All @@ -37,18 +44,21 @@
),
new Nuget
(
props: props,
project: "src/Robots/Robots.csproj",
targets: "netstandard2.0"
),
new Nuget
(
props: props,
project: "src/Robots.Grasshopper/Robots.Grasshopper.csproj",
targets: "net48"
),
new Release
(
props: props,
github: github,
file: "RELEASE",
notesFile: "RELEASE",
message: "> This **release** can only be installed through the package manager in **Rhino 7** using the `_PackageManager` command.\n> Check the [readme](../../blob/master/.github/README.md) for more details."
)
});
Expand Down
9 changes: 0 additions & 9 deletions build/Robots.Build/Properties/launchSettings.json

This file was deleted.

6 changes: 4 additions & 2 deletions build/Robots.Build/Robots.Build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net7.0</TargetFramework>
<StartWorkingDirectory>$(RootDir)</StartWorkingDirectory>
<StartArguments>debug</StartArguments>
<NoWarn>CA1852</NoWarn>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="RhinoPackager" Version="1.0.7" />
<PackageReference Include="RhinoPackager" Version="1.3.0" />
</ItemGroup>

</Project>
6 changes: 2 additions & 4 deletions src/Robots/IO/FileIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,8 @@ static Mesh GetToolMesh(string name)
const ElementType type = ElementType.Tool;
var doc = GetRhinoDoc(name, type);
var layerName = $"{type}.{name}";
var layer = doc.AllLayers.FirstOrDefault(x => x.Name.EqualsIgnoreCase(layerName));

if (layer is null)
throw new ArgumentException($" \"{name}\" is not in the 3dm file.");
var layer = doc.AllLayers.FirstOrDefault(x => x.Name.EqualsIgnoreCase(layerName))
?? throw new ArgumentException($" \"{name}\" is not in the 3dm file.");

var objects = doc.Objects.Where(x => x.Attributes.LayerIndex == layer.Index);
var meshes = objects.Select(o => o.Geometry).OfType<Mesh>();
Expand Down
10 changes: 4 additions & 6 deletions src/Robots/IO/OnlineLibrary.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Security.Cryptography;
using System.Security.Cryptography;
using Newtonsoft.Json;

namespace Robots;
Expand Down Expand Up @@ -82,10 +82,8 @@ async Task AddOnlineLibrariesAsync()
{
var uri = new Uri("https://api.github.com/repos/visose/robots/contents?ref=libraries");
var json = await _http.GetStringAsync(uri);
var files = JsonConvert.DeserializeObject<List<FileDto>>(json);

if (files is null)
throw new ArgumentNullException(" Could not list libraries.");
var files = JsonConvert.DeserializeObject<List<FileDto>>(json)
?? throw new ArgumentNullException(" Could not list libraries.");

foreach (var file in files)
{
Expand Down Expand Up @@ -189,4 +187,4 @@ async Task DownloadFileAsync(string fileName)
var bytes = await _http.GetByteArrayAsync(uri);
File.WriteAllBytes(downloadPath, bytes);
}
}
}
183 changes: 183 additions & 0 deletions src/Robots/Kinematics/FrankaKdlKinematics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
using Rhino.Geometry;
using K = Kdl;
using static Kdl.Joint;

namespace Robots;

class FrankaKdlKinematics : RobotKinematics, IDisposable
{
const int _redundant = 2;

readonly List<string> _empty = new(0);
readonly double[] _midJoints;
readonly K.JntArray _qMin;
readonly K.JntArray _qMax;
readonly K.Chain _chain;
readonly K.ChainIkSolverVel_pinv _velSolver;
readonly K.ChainFkSolverPos_recursive _fkSolver;
readonly K.ChainIkSolverPos_NR_JL _ikSolver;

public FrankaKdlKinematics(RobotArm robot)
: base(robot)
{
var joints = _mechanism.Joints;
_midJoints = joints.Map(j => j.Range.Mid);
_qMin = ToJntArray(joints.Map(j => double.MinValue));
_qMax = ToJntArray(joints.Map(j => double.MaxValue));

_chain = CreateChain();

_velSolver = new(_chain, 1e-5, 150);
_fkSolver = new(_chain);
_ikSolver = new(_chain, _qMin, _qMax, _fkSolver, _velSolver, 100, 1e-4);
}

K.Chain CreateChain()
{
var j = _mechanism.Joints;
K.Chain chain = new();

AddSegment(JointType._None, j[0].A, j[0].Alpha, j[0].D, 0);
AddSegment(JointType.RotZ, j[1].A, j[1].Alpha, j[1].D, 0);
AddSegment(JointType.RotZ, j[2].A, j[2].Alpha, j[2].D, 0);
AddSegment(JointType.RotZ, j[3].A, j[3].Alpha, j[3].D, 0);
AddSegment(JointType.RotZ, j[4].A, j[4].Alpha, j[4].D, 0);
AddSegment(JointType.RotZ, j[5].A, j[5].Alpha, j[5].D, 0);
AddSegment(JointType.RotZ, j[6].A, j[6].Alpha, 0, 0);
AddSegment(JointType.RotZ, 0, 0, j[6].D, 0);
return chain;

void AddSegment(JointType jointType, double a, double z, double d, double t)
{
using K.Joint joint = new(jointType);
using var frame = K.Frame.DH_Craig1989(a, z, d, t);
using K.Segment segment = new(joint, frame);
chain.addSegment(segment);
}
}

protected override int SolutionCount => 1;

protected override double[] InverseKinematics(Transform transform, RobotConfigurations configuration, double[] external, double[]? prevJoints, out List<string> errors)
{
errors = _empty;

var current = prevJoints ?? _midJoints;

double? redundantValue =
external.Length > 0 ? external[0] : prevJoints?[_redundant];

if (redundantValue is not null)
{
_qMin.set(_redundant, redundantValue ?? double.MinValue);
_qMax.set(_redundant, redundantValue ?? double.MaxValue);
}

_ikSolver.setJointLimits(_qMin, _qMax);

using var q_init = ToJntArray(current);
using K.Frame pos_goal = ToFrame(transform);
using K.JntArray q_sol = new(7);
var retVal = _ikSolver.CartToJnt(q_init, pos_goal, q_sol);

if (retVal != 0)
{
var text = _ikSolver.strError(retVal);

errors = new List<string>(1)
{
$"Warning: Target unreachable ({text})"
};
}

var vals = FromJntArray(q_sol);
return vals;
}

protected override Transform[] ForwardKinematics(double[] joints)
{
using var ja = ToJntArray(joints);

var _ts = new Transform[joints.Length];
using K.FrameVector frames = new(joints.Length + 1);

for (int i = 0; i < frames.Capacity; i++)
frames.Add(new());

var kinematics_status = _fkSolver.JntToCart(ja, frames);

for (int i = 0; i < joints.Length; i++)
{
using var frame = frames[i + 1];
using var p = frame.p;
using var r = frame.M;
using var vx = r.UnitX();
using var vy = r.UnitY();

Plane plane = new((Point3d)ToVector3d(p), ToVector3d(vx), ToVector3d(vy));
_ts[i] = plane.ToTransform();
}

return _ts;
}

Vector3d ToVector3d(K.Vector v) => new(v.x(), v.y(), v.z());

K.Frame ToFrame(Transform t)
{
using K.Rotation rotation = new(
t.M00, t.M01, t.M02,
t.M10, t.M11, t.M12,
t.M20, t.M21, t.M22
);

using K.Vector vector = new(t.M03, t.M13, t.M23);
return new(rotation, vector);
}

double[] FromJntArray(K.JntArray ja)
{
int count = (int)ja.rows();
var vals = new double[count];

for (int i = 0; i < count; i++)
vals[i] = ja.get(i);

return vals;
}

K.JntArray ToJntArray(double[] joints)
{
var ja = new K.JntArray((uint)joints.Length);

for (int i = 0; i < joints.Length; i++)
ja.set(i, joints[i]);

return ja;
}

bool _isDisposed;

~FrankaKdlKinematics() => Dispose(false);

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

void Dispose(bool disposing)
{
if (_isDisposed)
return;

_isDisposed = disposing;

_qMin.Dispose();
_qMax.Dispose();
_chain.Dispose();
_velSolver.Dispose();
_fkSolver.Dispose();
_ikSolver.Dispose();
}
}
Loading

0 comments on commit ba4f900

Please sign in to comment.