visose / Robots

Create and simulate ABB, KUKA, UR, and Staubli robot programs.
MIT License
301 stars 125 forks source link

Log feedback from Robot #19

Closed JonasWard closed 4 years ago

JonasWard commented 5 years ago

Dear visose

I'm trying to get some tcp locations from an UR5, connected through TCP, returned in the log of the RemoteUR component to use for a realtime feedback loop in grasshopper. Even though sending the get_actual_tcp_pose() and printing in the log on the UR itself works fine, there is no data being fed back to grasshopper. Has a feature been implemented that I'm overlooking to get this to work? If not, do you have any suggestions by any chance on how to get this to work in gh?

Kind Regards Jonas

piter123 commented 5 years ago

On the same topic, it looks like the Log property in RemoteUR.cs is never assigned (unlike in RemoteABB.cs)

visose commented 5 years ago

Someone ask me this recently so I sent them this:

Although it's not exposed as a Grasshopper component, there is a class called URRealTime for this that you can use, if you know a bit of scripting. You can use it in a scripting component.

You would have to do the following: place a (for example) C# scripting component in the canvas, right click on it and add as an assembly reference 'Robots.dll'. In the code, add a using statement to 'Robots': using Robots; Create a new object of this class: var urData = URRealTime(string IP); This will connect to the controller, you can use this object to start reading data from it. 'urData' has a property with a list of all the feedback you can read on the UR realtime interface (urData.FeedbackData). Each element in this list has the following public properties: string Meaning string Notes double[] Value

Use Meaning and Notes to see what the data type really is, and then the values array will have the actual values you want to use. For example, if "Meaning" is "joint positions" the values array will be 6 numbers that correspond to the joint positions in radians. Call the method ' UpdateFeedback();' to update this list with new data from the controller. If you want this data to be continuously updated, you have to call this method in a loop (a simple way would be to use a grasshopper timer). But make sure the object initialization only happens once.

You can also use the method ' Send(string message)' to send commands to the controller using the real time interface.

visose commented 5 years ago

On the same topic, it looks like the Log property in RemoteUR.cs is never assigned (unlike in RemoteABB.cs)

What do you mean exactly with Log not being assigned? The log output does not mirror the UR controller's log, it's just messages regarding what the Remote component is doing or issues with it. But the ABB one is the same.

visose commented 4 years ago

I assume this issue was confusion regarding the Log property and can be considered resolved.

robin-gdwl commented 3 years ago

For Reference: I wrote a script for realtime logging from UR with the Robots-plugin. It's based on the comment above. I am new to C# so it might be done badly with the Multithreading procedure and Expiration call. Use at your own risk. Find more in this repository: https://github.com/robin-gdwl/GH_Robots_URRealtimeFeedback

using System;
using System.Collections;
using System.Collections.Generic;

using Rhino;
using Rhino.Geometry;

using Grasshopper;
using Grasshopper.Kernel;
using Grasshopper.Kernel.Data;
using Grasshopper.Kernel.Types;
using Grasshopper.Kernel.Special;
using Robots;

/// <summary>
/// This class will be instantiated on demand by the Script component.
/// </summary>
public class Script_Instance : GH_ScriptInstance
{
#region Utility functions
  /// <summary>Print a String to the [Out] Parameter of the Script component.</summary>
  /// <param name="text">String to print.</param>
  private void Print(string text) { /* Implementation hidden. */ }
  /// <summary>Print a formatted String to the [Out] Parameter of the Script component.</summary>
  /// <param name="format">String format.</param>
  /// <param name="args">Formatting parameters.</param>
  private void Print(string format, params object[] args) { /* Implementation hidden. */ }
  /// <summary>Print useful information about an object instance to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj) { /* Implementation hidden. */ }
  /// <summary>Print the signatures of all the overloads of a specific method to the [Out] Parameter of the Script component. </summary>
  /// <param name="obj">Object instance to parse.</param>
  private void Reflect(object obj, string method_name) { /* Implementation hidden. */ }
#endregion

#region Members
  /// <summary>Gets the current Rhino document.</summary>
  private readonly RhinoDoc RhinoDocument;
  /// <summary>Gets the Grasshopper document that owns this script.</summary>
  private readonly GH_Document GrasshopperDocument;
  /// <summary>Gets the Grasshopper script component that owns this script.</summary>
  private readonly IGH_Component Component;
  /// <summary>
  /// Gets the current iteration count. The first call to RunScript() is associated with Iteration==0.
  /// Any subsequent call within the same solution will increment the Iteration count.
  /// </summary>
  private readonly int Iteration;
#endregion

  /// <summary>
  /// This procedure contains the user code. Input parameters are provided as regular arguments,
  /// Output parameters as ref arguments. You don't have to assign output parameters,
  /// they will have a default value.
  /// </summary>
  private void RunScript(bool AutoUpdate, string IP, ref object RobotData)
  {
    datapack = new List<double>();

    if (RobotConnection == null)
    {
      RobotAddress = IP;
      RobotConnection = new URRealTime(RobotAddress);
      Feedbackdata = RobotConnection.FeedbackData;
    }
    if (DataAsTree == null)
    {
      DataAsTree = new DataTree<double>();
    }
    if (task == null || task.IsCompleted)
    {
      task = System.Threading.Tasks.Task.Run(() => getDataFromRobot());
    }
    RobotData = DataAsTree;

    if (AutoUpdate == true)
    {
      Component.ExpireSolution(true);
    }

  }
  // <Custom additional code> 
  System.Threading.Tasks.Task task = null;
  URRealTime RobotConnection;
  String RobotAddress;
  DataTree<double> DataAsTree;
  List<double> datapack;
  List<FeedbackType> Feedbackdata;
  GH_Path path;

  void getDataFromRobot()
  {
    RobotConnection.UpdateFeedback();
    Feedbackdata = RobotConnection.FeedbackData;

    for (var j = 0; j < Feedbackdata.Count; j++)
    {
      datapack = new List<double>();
      for (var k = 0; k < Feedbackdata[j].Value.Length; k++)
      {
        datapack.Add(Feedbackdata[j].Value[k]);
      }
      path = new GH_Path(j);
      DataAsTree.RemovePath(j);
      DataAsTree.AddRange(datapack, path);
      DataAsTree.TrimExcess();
    }
  }

  // </Custom additional code> 
}