Grasshopper

algorithmic modeling for Rhino

How to refresh output data or execute solve Instance many times

Hello community,

My name is Ernesto, I started developping components for Grasshopper two weeks ago. Developing componets as the SDK help style was quite fine. But now, I'm facing a new approach, I need to develop a component that reads data from a Tracking Server we have built here in our lab, on top of VRPN Server. We developed a client library to communicate with this server and to read data from different devices through the server, making our life easier. The fact is that I need to update data received from a wiimote for example (at a regular time interval) and output this data to feed other components. Our first approach was to test the inclussion of that library into the context of Grasshopper and it worked, but just and only for the first time the component is created of course. Now the problem is to call this update function inside grasshopper multiple times and update the output. I'm new to grasshopper component coding so, it would be nice if I can get some response of an expereinced developer or at least somebody that have developed something like the example I'm exposing here. Some code is posted below to clarify what I'm saying.

 

...

 

using VRPNClassLib; //This is our class lib.


namespace MyComp
{
    public class MyComp : GH_Component
    {       
        private VRPNController controllerWiimote = new VRPNClassLib.VRPNController("WiiMote0@localhost");
        private Wiimote wii = new Wiimote();

        ...       

        private double rotX, rotY, rotZ;

        public MyComp() : base("Al required params ok")
        {
            try
            {
                controllerWiimote.addDevice(wii);
            }
            catch (Exception e)
            {
                throw new Exception("No wii controller attached to the PC:  -->" + e.Message);
            }
        }


        ...


        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.Register_DoubleParam("Pos X", "X", "Wiimote X");
            pManager.Register_DoubleParam("Pos Y", "Y", "Wiimote Y");
            pManager.Register_DoubleParam("Pos Z", "Z", "Wiimote Z");
        }

        protected override void SolveInstance(IGH_DataAccess DA)
        {       

              // If execute MainLoop() here for the first time it works of course, but I need  to continuously read data from wiimote, how do I do that

               MainLoop();
               DA.SetData(0,rotX);
               DA.SetData(1,rotY);
               DA.SetData(2,rotZ);          
        }


        protected void MainLoop()
        {
            controllerWiimote.UpdateData();  //this is the function that updates device data
            rotX = Math.Round(wii.getSensorRot1(),2);
            rotY = Math.Round(wii.getSensorRot2(),2);
            rotZ = Math.Round(wii.getSensorRot3(),2);
        }


        public override Guid ComponentGuid
        {
            //Genere el GUID del componente
            get { return new Guid("8F9858D8-F18E-45f2-90EC-CC23523ACC4F"); }
        }
         ...
    }
}

 

 

So any sugestions are welcome.

 

Cheers  :)

Views: 1747

Replies to This Discussion

 

Hi Ernesto,

 

there's two approaches that make sense here.

  1. If you get data from your server based on a timer or events, you can call the ExpireSolution() method on your component. This will expire your object and anyone downstream of your object. Then when the next solution happens you can read the data in and assign it.
  2. You can use the in-build solution scheduling if your data comes in a consistent rate. From within SolveInstance(), call the ScheduleSolution() method on GH_Document and provide a callback delegate so you can expire and reload your data before the next solution kicks off.

 

I'd start with [1] as it seems easier.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Hi David, I have played around with those solutions you gave me in the above post and all was almost perfect, until Grasshopper crashed with a bunch of display errors. In first place I thought that was my code, so I decided to write a new simple component refreshing all time at 300 ms interval and the problem came up again. The code provoking the display exceptions and images with the erros are listed below.

 

----------------------------------------------------------------------------------------------

using System;
using System.Drawing;
using Grasshopper.Kernel;
using FirstComp.Properties;
using System.Timers;

namespace FirstComp
{
    public class FirstCompGH : GH_Component
    {

        private Timer myTimer = new Timer(300); //3 veces por segundo
        private Random rand   = new Random(DateTime.Now.Millisecond);

        public FirstCompGH()
            : base("Nombre", "Abreviado", "Descripcion", "Categoría", "SubCat")
        {
            myTimer.Elapsed += new ElapsedEventHandler(MainLoop);
            myTimer.Start();
        }
        protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
        {
            pManager.Register_DoubleParam("Op A", "A", "Primer parámetro de la operación",0.0);
            pManager.Register_DoubleParam("Op B", "B", "Segundo parámetro de la operación",0.0);
        }

        protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
        {
            pManager.Register_DoubleParam("Suma", "S", "Resultado de la suma");
            pManager.Register_DoubleParam("Resta", "R", "Resultado de la resta");
            pManager.Register_DoubleParam("Mult", "M", "Resultado de la multiplicación");
            pManager.Register_DoubleParam("Div", "D", "Resultado de la división");
        }

        protected override void SolveInstance(IGH_DataAccess DA)
        {
            // Variables para contener los datos de entrada
            // Le podemos asignar algunos valores iniciales.
            double opA = double.NaN,
                   opB = double.NaN;           

            // El objeto DA recupera los datos de la entrada.
            // Si no hay datos de entrada abortamos.
            if (!DA.GetData(0, ref opA)) { return; }
            if (!DA.GetData(1, ref opB)) { return; }

            opA += rand.Next(1,10);
            opB += rand.Next(1,10);
           

           
            // Ahora realizamos las operaciones matemáticas           
            DA.SetData(0, (opA + opB));
            DA.SetData(1, (opA - opB));
            DA.SetData(2, (opA * opB));



            if (opB != 0) //Rhino.RhinoMath.ZeroTolerance
                DA.SetData(3, (opA/opB));
            else
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Error de división por cero");
                return;
            }
        }

        public override Guid ComponentGuid
        {
            get { return new Guid("44BEA3FE-7CB8-42fe-AEC9-BE5F6EE424E8");}
        }
        protected void MainLoop(object source, ElapsedEventArgs e)
        {
            this.ExpireSolution(true);
        }
        protected override Bitmap Internal_Icon_24x24
        {
            get
            {
                return Resources.icono;
            }
        }
    }
}

 -------------------------------------------------------------------------------------------------

Images showing errors.

I can't figure out what is causing these errors.

 

Best Regards

Ernesto

 

Nevertheless Grasshopper crashes and stop showing visual components because it is in ultra-paranoid mode, it's still working. The images below show a continuously random generated point at 300 ms time interval and Rhino is refreshing ok.

Cheers

Ernesto

 

System.Timers.Timer is a threaded timer, it will fire when it's not supposed to. You cannot access graphics code from another thread, usually it means instant crash although in this case it seems I handle it for you by going into ultra-paranoid mode.

 

Do not use threading unless you are an expert at it. You'll need to either invoke a thread-safe method on your component from the timer event or use the ScheduleSolution approach which I made sure is threadsafe.

 

--

David Rutten

david@mcneel.com

Poprad, Slovakia

Thaks a lot David I've tried with ScheduleSolution and it worked just fine. Here is my code

...

//Begin SoslveInstance Implementation

...

GH_Document d = this.OnPingDocument();
if (d == null)
  return;
d.ScheduleSolution(30, MainLoop);

...

//End solveInstance Implementation

 

protected void MainLoop(GH_Document doc)
{           
    this.ExpireSolution(false);
}

...

 

Cheers

Ernesto

RSS

About

Translate

Search

Photos

  • Add Photos
  • View All

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service