• matthew@hierthinking.com
Control Systems
It’s Time To Focas: CNC Router Programming Tutorial – Part 3

It’s Time To Focas: CNC Router Programming Tutorial – Part 3

View Code On GitHub

ATTENTION!!!!!

We now offer Consulting, Contract, and Training services for Focas. Check it out here!

If you have a question with something in this series, check out our new forum here!

*** NOTE ***

Resources for this post are located at the bottom. All methods covered in this post are linked there.

This is the third installment of our Focas series. If you have not yet checked out the first two installments, I would suggest checking them out. The first and second posts cover some basic knowledge needed to be able to connect to the Fanuc controller.

In this installment, we are going to cover obtaining some basic information from the controller. We are going to look at functions to read the mode and status information, as well as various axis information.

These are things that I believe most people will be able to use and will allow you to see some results from your application relatively quickly. In the future, we will move onto some more advanced functions that allow you to obtain parameters and information from pmc addresses.

Get in the Mode!

The first thing we are going to do is read the mode from the machine. Doing this is relatively simple. In the last post, we covered connecting to the Fanuc and obtaining a handle. We will now make use of that handle to obtain the information we want from the controller.

The one thing we have not had to cover so far that is important to note is that most Focas calls require you to pass in a structure that will store the information returned from the control. Each call has a specific structure that must be passed in. These structures can be viewed in the FwLib32.cs file.

You will need to check each function to see what structure is required for it. Once you have found which structure you will need you can create an instance of it by calling Focas1 followed by a “.” and the structure name. the structure we will need to get the mode will be the ODBST structure. I will call it with Focas1.ODBST.

public string GetMode()
{
        short _ ret = 0;

	// Check we have a valid handle
	if (_handle == 0)
		return "UNAVAILABLE";

	// Create an instance of our structure
	Focas1.ODBST mode = new Focas1.ODBST();

	// Ask Fanuc for the status information
	_ret = Focas1.cnc_statinfo(_handle, mode);

	// Check to make sure the call was successfull
	// and convert the mode to a string and return it.
	if (_ret == Focas1.EW_OK)
		return GetModeString(mode.aut);
	return "UNAVAILABLE";
}

The first thing we are going to do in our GetMode function is to check to see if the handle we obtained is 0. If it is, we know that the connection was not successful, so we will not be able to get any information from the control and we will return the string “UNAVAILABLE”.

Next, we create an instance of the structure that the control will fill out and send back to us. You can take a look at what is in the structure by going to the documentation page or by locating it in the FwLib32.cs file. The structure contains 12 different items, but we will only be working with two of them today.

We can now call the method to obtain the mode. The function we are going to is the cnc_statinfo function. This function takes only two arguments. First, it will take our handle. The second argument is the instance of our ODBST structure. The function will return a short that indicates the success or failure of the call.

Unfortunately, Fanuc will not return a string that just tells us what the mode is. It will only return a short. We must convert that short into a string. The important thing to note here is that these values will be different for different controllers. I have created a sample method that shows how this can be done for the 30i/31i/32i/0i-D/F controllers. You will need to check the documentation if you have a different model controller and create one that matches your control type.

// I used a switch function to demonstrate, but
// there are better methods out there. 
private string GetModeString(short mode)
{
	switch (mode)
	{
		case 0:
			{
				return "MDI";
			}
		case 1:
			{
				return "MEM";
			}
		case 2:
			{
				return "****";
			}
		case 3:
			{
				return "EDIT";
			}
		case 4:
			{
				return "HND";
			}
		case 5:
			{
				return "JOG";
			}
		case 6:
			{
				return "T-JOG";
			}
		case 7:
			{
				return "T-HND";
			}
		case 8:
			{
				return "INC";
			}
		case 9:
			{
				return "REF";
			}
		case 10:
			{
				return "RMT";
			}
		default:
			{
				return "UNAVAILABLE";
			}
	}
}

After we make the call, we will want to check the return to make sure that it succeeded. If it was successful, we will return 0. Otherwise, it will return a short that can be looked up in the documentation.

What About The Status?

Whew… that wasn’t so difficult, was it? The good news is that we can now move on to getting the status. Lucky for you, we just need to make a couple of small changes to get the status!

To get the status, we will use the same exact function call. In fact, there is no point in calling it twice. The information that was returned contains the status information as well.

When we read the mode information, we read information from aut in the ODBST structure. To get the status we will read run from the structure.

public string GetStatus()
{
	if (_handle == 0)
		return "UNAVAILABLE";

	Focas1.ODBST status = new Focas1.ODBST();

	_ret = Focas1.cnc_statinfo(_handle, status);

	if (_ret == Focas1.EW_OK)
		return GetStatusString(status.run);
	return "UNAVAILABLE";
}

Just like we did with the mode, we will need to convert the number that was returned to a string. Again, this information is going to vary based on the controller type, so you are going to need to create whatever method you use to do that.

An Axis Dangerous

The last thing I want to cover in this post is how to read axis positions. There are three different axis positions that I am going to go over. The code for reading each of the axis positions is very similar, so I will only go over one of them in detail. I will post the code for all three so you can see the slight differences in each.

public double AbsolutePosition()
{
	// Scale for inches
	var _scale = 10000;
	
	if (_handle == 0)
		return 0;

	Focas1.ODBAXIS _axisPositionAbsolute = new Focas1.ODBAXIS();
	_ret = Focas1.cnc_absolute2(_handle, 88, 8, _axisPositionAbsolute);

	if (_ret != Focas1.EW_OK)
		return _ret;

	return _axisPositionAbsolute.data[0] / _scale;
}

Most of this code should look familiar. We check to make sure we have a valid handle. Once we know we have a valid handle, we will create an instance of the structure required by the Focas call. In this instance, we need to pass in the ODBAXIS structure.

Now we come to the actual API call. You will notice, just like when we read the mode and status, the first argument is the handle. This is going to be the case for almost every Focas call.

The second argument is going to be the numerical representation of the axis. If you are not familiar with this, look at an ASCII chart. I am using the number 88 in this example which is going to the capital letter X. So, we will be reading the X-axis. The numbering will be sequential, so the Y-axis will by 89, and the Z-axis will be 90.

The third parameter is a little trickier. They want you to specify the block size. They have a description in the documentation, but I found it confusing at first. Essentially it boils down to this: if you are reading a single axis, use 8, otherwise, you will use 4 plus 4 for each axis. So, if you wanted to read information from three axes, you would use 4 plus 4 for each of the three axes which would be 12. So you would put 16 as the third parameter.

Now, I have not had much luck reading multiple axes, so I will just be reading a single axis. If you want to read all the axes on the machine, you can put -1 in the second argument and then do the calculation for the third argument.

The final parameter for our API call is going to be the ODBAXIS structure we created above. We will check the return code of the function and move on to the last bit.

Notice, that we are reading the position from an array. That is because you have the option of reading more than one axis at a time. Since we are only reading one axis, we are always going to read the first element of the array.

Also notice that we have a scaling factor. Fanuc will not return a decimal to you. You need to know where the decimal should go. I’ve figured out that if you are using inches, you can use 10000 as a scaling factor, and if you are using millimeters you can use 1000 as the scaling factor. This will ensure that the decimal place is right.

In the above code, we obtained the absolute position of the machine. However, you can also obtain relative and machine positions. To do this, you will use cnc_relative2 or cnc_machine instead of cnc_absolute2. All the parameters will be the same, and you will still need to use a scaling factor to get the decimal place.

        public double RelativePosition()
        {
            if (_handle == 0)
                return 0;

            Focas1.ODBAXIS _axisPositionRelative = new Focas1.ODBAXIS();
            _ret = Focas1.cnc_relative2(_handle, 88, 8, _axisPositionRelative);

            if (_ret != Focas1.EW_OK)
                return _ret;

            return _axisPositionRelative.data[0] / _scale;
        }

        public double MachinePosition()
        {
            if (_handle == 0)
                return 0;

            Focas1.ODBAXIS _axisPositionMachine = new Focas1.ODBAXIS();
            _ret = Focas1.cnc_machine(_handle, 88, 8, _axisPositionMachine);

            if (_ret != Focas1.EW_OK)
                return _ret;

            return _axisPositionMachine.data[0] / _scale;
        }

Resources

This is a list of resources for this post.

Mode / Status: https://www.inventcom.net/fanuc-focas-library/misc/cnc_statinfo

Axis Pos. Absolute: https://www.inventcom.net/fanuc-focas-library/position/cnc_absolute2

Axis Pos. Machine: https://www.inventcom.net/fanuc-focas-library/position/cnc_machine

Axis Pos. Relative: https://www.inventcom.net/fanuc-focas-library/position/cnc_relative2

ASCII Chart: http://www.asciitable.com/

Final Thoughts

I know we covered a lot in this post, but the basic usage we covered here will work for a lot of the available Focas calls. By now you should be seeing a pattern that we follow when making these calls. We are always going to check to make sure we have a valid handle, then we will create an instance of our structure, and make our call to the controller. Then we will check to make sure the return code is good, and finally perform whatever action we need to on the result and return it.

In the next post, I hope to get a bit deeper into reading information from the control. I want to get into reading pmc addresses, macro variables, and parameters. These will probably span multiple posts, but I think a lot of people will get something out of it.

As always, if you have questions, concerns, gripes, or just want to give suggestions, feel free to leave a comment below or email me. See you in the next post!

<– Part 2

80 thoughts on “It’s Time To Focas: CNC Router Programming Tutorial – Part 3

    • […] Previous postNext post […]

    • Author gravatar

      Very helpful, Thanks

      • Matthew Hier

        Thanks for checking it out. If you don’t mind, where did you come across this? If you have any suggestions or something that you would like to see a post about let me know!

        • Author gravatar

          I just googled Fanuc Focas tutorial and this is the only hit VS reading the inventcom documentation and falling asleep. Not op.

          • Author gravatar

            Same as TomM. Thanks for putting this together. I’m hoping I don’t actually have to get to the point of writing our own code (trying to get Kepware to support more Focas calls). But good to know of this guide in case we do.

            • Matthew Hier

              Hi Ted,

              Thank you for the comment. If you do find the need to write your own code, there are resources here to help you. If you have any questions, feel free to email me, post in the forum, or leave another comment!

    • Author gravatar

      Are you able to post the syntax for the Fanuc vbnet cnc_statinfo?
      Maybe post an example for the layman out there?
      Just simple and concise so my small mind can take it apart and then go to more complex functions.

      • Matthew Hier

        Hi Rococo,

        Thanks for reading my posts. In VB it that function should look something like this:

        Dim mode As Integer = 0
        Dim status As Integer = 0
        Dim modeAndStatusInfo As New Focas1.ODBST

        ret1 = Focas1.cnc_statinfo(handle, modeAndStatusInfo)
        mode = modeAndStatusInfo.aut
        run = modeAndStatusInfo.run

        I Hope this helps. Let me know if there is anything else you need help with.

    • Author gravatar

      Hello,
      this was very helpfull,
      can you please give a wxample to read all Parameters to a File?
      There is a small example in the FOCAS CD, but it will not work.
      Best regards
      Thomas

      • Matthew Hier

        Hi Thomas,

        I am unaware of a method to do this. I know that it is possible because the CNC Screen Display software is able to do it. If I can get you to send me the sample that you have, I will more than happy to test some stuff out to see if I can get it work. My email is matthew@hierthinking.com

      • Matthew Hier

        Hi Thomas,

        I got your email and I did some testing. So I ran the example you sent, with a few changes but there are some things I noticed about the code you sent that I would like to clarify.

        The Focas1.MAX_AXIS variable defaults to 8 if they type of device is not specified. If you look at the top of the fwlib32.cs file you will see this:

        #if FS30D
        public const short MAX_AXIS = 32;
        #elif M_AXIS2
        public const short MAX_AXIS = 24;
        #elif FS15D
        public const short MAX_AXIS = 10;
        #else
        public const short MAX_AXIS = 8;
        #endif

        So this means when you use that variable in the Focas1.cnc_rdparam() call you are only allocating enough space to hold 8 axes. If, as I suspect it is hitting the else statement, I would just change the 8 to 12 so that it allocates enough space for all of your axes.

        Below is the code that I ended up running. I had to actually change some of the stuff because the fwlib32.cs file was slightly different from the example.

        public static void sample()
        {
        Focas1.ODBSYS info = new Focas1.ODBSYS();

        Focas1.IODBPSD_3 param = new Focas1.IODBPSD_3();

        short ret, idx, axno;

        Focas1.cnc_sysinfo(h, info);

        axno = short.Parse(new string(info.axes));

        ret = Focas1.cnc_rdparam(h, 1020, -1, 4 + 1 * Focas1.MAX_AXIS, param);

        for (idx = 0; idx < axno; idx++) { Console.Write("#{0}", idx); Console.WriteLine("{0}", (char)param.cdatas[idx]); } }

    • Author gravatar

      Hello.

      Excellent tutorial. I was able to create and use functions for retrieving execution modes and machine status, but I fail when trying to get the control override signals. What am I doing wrong? The code for rapid override signal is this, but I always get 0 as result. Any help would be appreciated.

      public static int GetRpdOverride()
      {
      // Check we have a valid handle
      if (_handle == 0)
      return -1;

      Focas1.IODBSGNL signal = new Focas1.IODBSGNL();

      _ret = Focas1.cnc_rdopnlsgnl(_handle, 0x8, signal);

      if (_ret == Focas1.EW_OK)
      return signal.rpd_ovrd;

      return -1;
      }

      • Matthew Hier

        Hi Antonio!

        I am glad that you found my tutorials helpful. So when I am reading the overrides I am actually not using that function call. Overrides can be accessed by reading PMC addresses. The feed rate override is G12, the rapid override is G14, and the spindle override is G30. So I use Focas1.pmc_rdpmcrng() to get the overrides. This is an example of what I am doing to get the rapid override.

        Focas1.IODBPMC0 m = new Focas1.IODBPMC0();
        ret = Focas1.pmc_rdpmcrng(Fanuc.Handle, 0, 0, (ushort)14, (ushort)14, 16, m);

        if (ret != Focas1.EW_OK)
        return ret.ToString();

        if (m.cdata[0] == 0)
        return “100”;
        if (m.cdata[0] == 1)
        return “50”;
        if (m.cdata[0] == 2)
        return “25”;
        if (m.cdata[0] == 3)
        return “5”;
        else return “0”;

        Now when you are reading the feed rate overrides it is going to take some work. The reason is that I have found different controls will do it slightly differently. You will use the pmc_rdpmcrng as you do for the rapid override, but when you check the value that is returned, you will need to have a switch statement or a dictionary or something that maps the value that is returned to the override value. For instance, on one of the controls that we have, the value returned from fanuc might be 255. But 255 is what is returned when the feed override is set to 120. Then when the override is set to 100 the value returned might be 235. So really you will need to make those associations for the control you are working on. Basically, just set the value to each override setting and see what value is returned and then create a switch statement for the corresponding values.

        I hope this has been helpful. Let me know if you need further assistance and I will do my best to help.

        • Author gravatar

          Hello,

          Thank you very very much. You solved my problem. In the case of our fanuc controlled machines, the feed rate override behaves as starting in 255 for 0% and decreasing value in 10 per each 10% increase.

          I am doing a Python script for capturing main signals (according to our requirements) and for Heindeinhain it is as easy as pie (using TNCRemo) but for fanuc it was a pain in the ass (until now).

          Again, thak you.

          Regards.

          P.S. In line with this, what would you recommend me for doing the same with Siemens controls? (in this simple line of work, nothing fancy or expensive).

          • Matthew Hier

            Hi Antonio,

            I am really happy that I was able to be of assistance. As for whether or not to do this with Siemens, I am not sure. I have never actually worked with a Seimens control so I am not sure what it takes. From what I understand Siemens has their own API to connect to the PLC, but I have never worked with it so I cannot tell you how easy or difficult it might be. May I ask, how did you find my blog? I am curious to know how people end up finding this.

            • Author gravatar

              Hello,

              In my case, Google, after a “combo” search so to speak:
              Matsuura (our main Fanuc CNCs, we have also a SNK) -> Fanuc -> Focas -> Inventcom –> your blog.

              Ironically I found your blog after Inventcom, not the opposite way.

              It has been a rough journey, although a good one at the end 🙂

              Regards.

            • Matthew Hier

              Well, awesome! I wasn’t sure if anyone was really finding my site from google. I am new to the whole SEO thing and so I don’t think I am very high on the list. But I am glad you found the site and if you need help with anything else, don’t be afraid to ask!

          • Author gravatar

            Hi Antonia,
            I am working on project to extract machine information (mode, spindle speed, actual cutting time for each NC program etc.) from Heindeinhain controllers as well. Would you mind sharing more detail on the way to extract these information in real time (around 1 min interval) using TNCremo? Any suggestion from others would be appreciated as well.

        • Author gravatar

          This was a real life saver for me. Attempting to do this exact thing without documentation other than the API and getting back unusable data from the same api call that Antonio was using.

          After asking Fanuc for assistance as to why it was returning garbage values, they suggested I use the same API call you’ve suggested, but without supporting documentation. So googling the API call and “override” led me here. After responding to Fanuc support with the addressing you have listed here and asking for any documentation on the conversions you mentioned, they eventually just sent me the docs.

          Which leads me to my question. In the documentation for the 0i-D series, G30 is listed as the address for storing reference position, and Gn030 is listed as the spindle override. However, I don’t see Gn listed as a kind of PMC address that can be passed to adr_type.

          How does one specify that they would like to read a Gn address?

          Thanks for posting this. I’m sure you’ve saved me hours with your response to Antonio’s question.

          • Matthew Hier

            Hi Michael,

            I am glad that you found these posts helpful. For the controllers we use, G30 is the signal for the spindle speed override. I was under the impression that the signals were mostly the same between different models, but I honestly haven’t worked with too many different models. I have never heard of Gn being a memory space that is used by Fanuc. Could you send me or post a screenshot of the material you were sent from Fanuc? I would be interested in seeing it so if I run into this in the future I will know. Here is a screenshot of our manual.

            Spindle Speed Override

    • Author gravatar

      Thank you so much for this post. I have a question. How would you go about checking to see if the automatic execution of CNC program has been fully completed? Is there a way?

      • Matthew Hier

        Hi Rayburn,

        You’re question is difficult to answer. The quick answer is, no. There is no built in functionality to determine whether or not a program has successfully completed.

        With that said, is it possible to make that determination using the Focas library? Yes it is. In fact, I have gone through many iterations of trying to get it just right.

        The subject is much to complex to really give a straight forward answer to here in the comments, but feel free to email me.

        matthew@hierthinking.com

        • Author gravatar

          Hello again.

          I’m also interested in this functionality. In few words, I’m trying to “catch” the M30 signal by software. This is the code I’ve created, it compiles correctly but doesn’t work (returns -1):

          public static int GetM30()
          {

          // Check we have a valid handle
          if (_handle == 0)
          return -1;

          Focas1.ODBPRS a = new Focas1.ODBPRS();
          _ret = Focas1.cnc_rdprstrinfo(_handle, a);

          if (_ret == Focas1.EW_OK)
          {
          return a.rstr_m[30];
          }
          else
          return -1;
          }

          Could you help me about this? (or any other solution that could work).

          P.S. So far I have:
          -Mode
          -Status
          -Current program number
          -The three overrides (rapid, feed, spindle)
          -Spindle speed (I’m interested in if it is spinning or not more than actual speed).

          With all of this I can calculate machine OEE (and more), but with M30 I could additionally calculate how much time (and therefore money) is required for manufacting a part, which is useful (I can do it, but not in real time without M30).

          Thanks in advance.

          • Matthew Hier

            Hi Antonio,

            So I see what you are trying to do, and there is a point in time that I was doing the same exact thing. The problem that you may run into is there are situations where you might miss the M30 because of the speed at which it occurs. I know as an example, the machines that we produce where I work will park the Z-axis head when the M30 occurs which usually will allow you time to catch the M30. Now what ended up happening to me was sometimes the head would already be at the park position, so the M30 would essentially be instantaneous and since my scan time wasn’t quick enough, it would miss the M30.

            That being said, I cannot really give you a solution to more accurately gauge the completion of a program. But I will give you the code to accurately read the M30. The code will be posted below this. I also wanted to cover the question you had about the spindle speed.

            The spindle speed has a couple of different values and really is going to depend on your setup as to what you can read. It is all going to be dependant on the inverter you are using. If you are not using a Fanuc Inverter for your spindle, you are not going to be able to obtain that information through the focas library. Also, if you want the true actual rpm of the spindle, the spindle is going to require encoder feedback. Now, even if you don’t have a Fanuc Inverter and encoder feedback, you can still obtain the programmed spindle speed. I will also give the code to do that.


            public bool CheckForM30()
            {
            short mcode_num = 1;
            var mcode = new Focas1.ODBCMD();
            ret = Focas1.cnc_rdcommand(_handle, 12, 1, ref mcode_num, mcode);

            if (_ret == Focas1.EW_OK && mcode.cmd0.adrs == 'M' && mcode.cmd0.cmd_val == 30)
            return true;
            return false;
            }

            public int CheckSpindleSpeed()
            {
            _ret = Focas1.cnc_rdcommand(_handle, 18, 1, ref mcode_num, mcode);

            if (_ret == Focas1.EW_OK && mcode.cmd0.adrs == 'S')
            return Math.Truncate((mcode.cmd0.cmd_val / Math.Pow(10.0, mcode.cmd0.dec_val)));
            return 0;
            }

            I hope this helps. Let me know if there is anything else I can help you with.

            • Author gravatar

              Hello,

              Thank you very much. Our workshop technician thinks it would be possible to configure the machine in order to extend the duration of M30 signal, which would allow us to capture it (we need to check with Fanuc/Matsuura support). Reading the signal with an higher frequency than this duration would do the trick.

              About the spindle, I’m using a different code that also works. Here it is in case you find it useful/interesting:

              public static int GetSpdSpeed()
              {

              // Check we have a valid handle
              if (_handle == 0)
              return -1;

              Focas1.ODBACT m = new Focas1.ODBACT();
              _ret = Focas1.cnc_acts(_handle, m);

              if (_ret == Focas1.EW_OK)
              {
              return m.data;
              }
              else
              return -1;
              }

              This function returns current speed, and later I convert it to spinning/not spinning with my Python script.

              Again, thank you. This forum is a true lifesaver.

            • Author gravatar

              Hello.

              After making some tests with M30 capturing, I have observed a curious phenomenon. In some cases, I detect a “single” M30 signal (using a 2s search interval), but in some other machines, it seems they get “stuck” in this state and I gather contiuous active M30 until the next production cycle. Do you know which kind of configuration could producte this result? I would be interested in configuring all machines in this way, so if I miss a lecture I would be sure it will be catched in the next read.

              Thank you as always.

            • Matthew Hier

              Hi Antonio,

              I was not exactly sure what would cause this, so I spoke with one of the Fanuc guys at work. He mentioned that some machines are set up to hit the M30 and immediately reset and rewind. Other machines are set to go to the park position on the M30. If a machine never reaches the park position than the M30 would never finish and you would see this issue. He said that he had seen this on machines that have too many decimal places in the park position. This will cause the machine to try to get to a place it can never actually get to.

              Other than that I am not really sure what else to check for this. Let me know if you find this to be the problem.

    • Author gravatar

      This is golden. Keep them coming please sir, couldn’t find anything like it anywhere.

      • Matthew Hier

        Hi Tom,

        Thank you for commenting. When I first started trying to use Focas I had a hard time and I know I tried searching Google for answers, but I was never able to find anything. So I am really glad that my posts are able to help people. If there is anything else that you would like to see me cover, let me know and I will see what I can put together.

    • Author gravatar

      Hey everyone! I am wondering if using .NET leads to some overhead (I am currently working on monitoring, and my acquisition rates should be pretty high, ideally 1kHz). For fast data acquisition, is it better to program in C++? Thanks a lot.

      • Matthew Hier

        I have never pulled data from the Fanuc this fast. In fact, I am not sure why you would need to. The scan time for the Fanuc ladder is somewhere around 8 ms. I would be interested in learning what you are trying to pull at such a fast rate.

        That being said, I have found that when pulling sensor data from accelerometers that using .Net required more CPU than the equivalent code in C++. That is why I tend to use C++ for anything with a high pull rate. But again, I was not using the focas library to accomplish this. What focas calls are you using?

        • Author gravatar

          I still have not implemented anything. I’m on the beginning of an implementation and still deciding which language and framework to use.
          When I have a more developed progress, I can notify you.

    • Author gravatar

      Hello Versex,

      Good Information.

      i have a bit confuse,when i try to your source code :

      public string GetMode()
      {

      short _ret ;

      // Check we have a valid handle
      if (_handle == 0)

      return “NOT AVAILABLE”;

      // Create an instance of our structure
      Focas1.ODBST mode = new Focas1.ODBST();

      // Ask Fanuc for the status information
      _ret = Focas1.cnc_statinfo (_handle, mode);

      // Check to make sure the call was successfull
      // and convert the mode to a string and return it.
      if (_ret == Focas1.EW_OK)

      return GetModeString(mode.aut);

      return “NOT AVAILABLE”;

      }

      how to get respons for handle?
      because when i run above source code handle is = 0, and return “NOT AVAILABLE”.
      actually i’m using CNC 31i Series (Ethernet communication).

      Waiting your kind feedbacks

      thank you.

      • Matthew Hier

        Hi cnc_lovers,

        I actually have three posts covering the Fanuc Focas library. They start from the very beginning and progress from there. I will link the first post in the series below so that you can check it out. Also, if you look on the github link at the top of each page on these posts, you will be able to see all the code.

        Here is the first post in the series. It walks you through the different methods of communication and some of the initial information you will want to be aware of when using the Focas library. https://hierthinking.com/2020/04/25/its-time-to-focas-p1/

        Here is the second post in the series which goes over how to get a handle and how to use the handle for other focas calls. https://hierthinking.com/2020/04/27/its-time-to-focas-p2

        Let me know if you have any other questions.

    • Author gravatar

      Regarding cnc_absolute2 (and cnc_relative2 and cnc_machine) you said, “Now, I have not had much luck reading multiple axes.” That’s exactly what I’m trying to do, albeit from a simulator. What i’ve found, so far, is that when a axis number is specified, the length parameter seems irrelevant as long as it’s >=8, as in your exmples. Conversely, when specifying an axis number of -1 (for all), I get an invalid length error no matter what value is used. I wonder if the simulator can be trusted!

      • Matthew Hier

        Hi Jeff,

        I ran into the same thing. I am not entirely sure what the issue is. What I ended up doing is just reading all the configured axis names using Focas and then reading each of the axes individually in a loop. While this may be a little more resource-intensive, especially at high poll rates, it has worked well for me. If you are interested in that approach, let me know and I will post the code for reading the axis names.

    • Author gravatar

      Yes, I’d like to see that code. Thanks!

    • Author gravatar

      Hello everyone. Hope everything is going well. I am trying to connect CNC machine with my computer to get the data from the FANUC Series. But whenever I try to reference the fwlib32.cs file like “_ret = Focas1.cnc_allclibhndl(out _handle);”, the system keeps warning me that “the name `Focas1′ does not exist in the current context”. Could you help me with how to fix this?

    • Author gravatar

      Hi guys,

      I am struggling by reading maximum tools numbers and tool lifetime data from CNC, because the return code is always 6 (EW_NOOP). Am I missing an addtitional library or what is my mistake? The two functions I wrote are blow the text. I am using the FANUC CNC simulation (model 30i-B).

      private Focas1.ODBTLIFE3 getMaxNumTools()
      {
      int node = 9; //Simulator
      int ret = 999;
      ushort LibHndl = new ushort();
      Focas1.cnc_allclibhndl2(node, out LibHndl);

      Focas1.ODBTLIFE3 oDBTLIFE3 = new Focas1.ODBTLIFE3();
      ret = Focas1.cnc_rdntool(LibHndl, (short)1, oDBTLIFE3); // ret is EW_NOOP

      return (oDBTLIFE3);

      }

      private Focas1.IODBTD getLifeTimeData(int group, int tool)
      {
      int node = 9; //Simulator
      int ret = 999;
      ushort LibHndl = new ushort();
      Focas1.cnc_allclibhndl2(node, out LibHndl);

      Focas1.IODBTD iODBTD = new Focas1.IODBTD();
      ret = Focas1.cnc_rd1tlifedata(LibHndl, (short)group, (short)tool, iODBTD); // ret is EW_NOOP

      return (iODBTD);
      }

    • Author gravatar

      Hi Versex,
      I am trying to extract main & sub program number under execution with following commands, but it seems only main program no (e.g. O1111) is returned by both .data and .mdata properties when my machine is executing a subprogram no (M198 O1610) under main program O1111. Can I please have your help to advise what’s the issue in my code that cause the problem?

      Focas1.ODBPRO odbpro = new Focas1.ODBPRO();
      code = Focas1.cnc_rdprgnum(pHdl, odbpro);

      short current_Subprogram;
      short current_Mainprogram;

      if (code == 0)
      {
      current_Subprogram = odbpro.data; // Subprogram No in execution
      current_Mainprogram = odbpro.mdata; // Mainprogram No in execution
      }

    • Author gravatar

      Hi Jens,

      I am doing the exact same thing as you, and am facing the same problem (cnc_rd1tlifedata returns EW_NOOP).
      Did you manage to find a solution to your problem?

    • Author gravatar

      Hi,
      how can i find the parts count in a Fanuc 32iBs2-4MB?
      Thanks in advance

    • Author gravatar

      Hi Guys,
      I’m using c# to read axis information in Windows CE . Using code I’m able to read axis data. However, I’m unable to read data continuously.
      How to update data continuously.

      • Matthew Hier

        Hi Sipu,

        What is the return code? If you are getting an invalid handle return code (-8), then the issue is most likely that you are not calling the function on the same thread. So for instance, if you use a timer, instead of a simple loop, every time the timer elapses, it will pull and seemingly random thread from the thread pool and use that to call the function. However, a fanuc handle is only valid on the thread it was created on. So this will not work. If you have some other error, let me know and I will try to help you figure it out.

        • Author gravatar

          Hi Versex,
          I’m calling the function in the same thread using System.Threading.Timer. Data are getting updated after every 1 sec. However, I want continuous update of data with much faster sampling. I’m getting garbage value when timer interval time is reduced to 500ms. May you suggest something to achieve this or you can share some sample code for calling my function.

    • Author gravatar

      Thanks a lot Versex for this post. I have a question. Have you ever written data on FANUC? If so, Which ones?
      Thanks.

      • Matthew Hier

        Hi Felice,

        I am not sure what you mean by writing data on Fanuc. However, if you are asking whether or not I have written Parameters / Macro Variables / X, Y, G, F PMC Addresses…. then yes I have. Is there something specific you are looking to write to the Fanuc?

        • Author gravatar

          Hi Versex,
          I would like to send the part program and the quantity to be produced for example. You would have some code to show me in addition to the one already present in the post. Thank you very much.

          • Author gravatar

            Ho dimenticato di chiederti se sai dove posso scricare un simulatore server FANUC per fare dei test. Grazie.

          • Matthew Hier

            Hi Felice,

            So for the most part, I am used to sending information to the CNC via FTP which does not need Focas. However, Focas does include functions to send programs to the controller. I have never personally used these functions to transfer a program to the CNC. I can get you some code that you should be able to use though. As far as the quantity, this is not going to be a Fanuc specific thing. This is likely to be a CNC manufacturer addition and I have no way to determine how it was implemented. Could you create a topic on the forum for this so that we can talk more? I find it is easier to talk there than it is to talk in the comments section. Then I can share screenshots and code with you.

    • Author gravatar

      OK thank you. I will write a post on this topic and also on the FANUC simulator. Granzie again.

    • Author gravatar

      Hi Versex,
      I use cnc_rdparam passing the 6711 and 6712 and the values they return are correct.
      Now I would like to read the total pieces produced during the day.
      The Fanuc screen has the title “Contat1 product management” and the parameter is called “total contat”.
      How can I read it?
      The customer tells me that with each new order, they reset that parameter to count the pieces actually made for that specific order. Thanks
      Sara

      • Matthew Hier

        Hi Sara,

        I am sorry, but I am unfamiliar with the Contat1 Product Management screen and the total contat parameter. Where are you seeing this? Could you take a picture perhaps and post it in the forum so I can see what you are referencing? Also, which parameter are they resetting? Is it the 6711/6712 or is it the Total Contat parameter?

    • Author gravatar

      Hi Versex,

      I am new to programming an interface with a CNC machine and your C# sample code, has been really helpful so far. Thank you.
      Could you also help me with reading tool data? Cutting / correction / tool life data.
      I must confess I haven’t quite figured out Fanuc’s concept with tool data either and I’m really struggling to implement it in code.

      Thanks
      Manuel

      • Matthew Hier

        Hi Manuel,

        I have never interacted with the built-in Fanuc tool life information. I believe that requires a specific option to be turned on. As for tool information such as tool diameter, length, and offset number, those are going to be obtained by utilizing the following code.

        var offset = new Focas1.ODBTOFS();
        var offsetNumber = 1;
        var type = 2; // See the reference link for the different types for each machine.

        _ret = Focas1.cnc_rdtofs(Fanuc.Handle, offsetNumber, type, 8, offset);

        Here is a link that describes this function call and gives you the different “types” you can read such as Tool Length, Cutting Radius, and a bunch of other information. https://www.inventcom.net/fanuc-focas-library/ncdata/cnc_rdtofs

        If you have any specific questions about a function call or something, feel free to send me an email at matthew@hierthinking.com.

    • […] It’s Time to Focas – Part 3: https://hierthinking.com/2020/05/06/its-time-to-focas-p3/ […]

    • Author gravatar

      OMG, you’re a life saver, i think this is one of best tutorial for fanuc focas, everything else was so vague and abstract…..thanks

    • Author gravatar

      Hallo,
      in my fwlib64.dll are very much
      [MarshalAs(UnmanagedType.AsAny)]

      the visual Studio2022 with .net6 says .AsAny is obsolet
      there is a warning: Compiler Warning (level 2) CS0618
      Is there a solution or a newer version from Fanuc.
      Thanks for help.
      Thomas

      • Matthew Hier

        Hi Thomas,

        Unfortunately, .Net has deprecated the AsAny method. Your best best is going to be to use either a .Net core or .Net Framework version. The fwlib32.cs and fwlib64.cs files are sample files that are supplied by Fanuc so they are very unlikely to update those files for newer .Net versions. Wish I could be more help.

    • Author gravatar

      Excellent Tutorial.
      I am trying to connect to FOCAS using Raspberry Pi on Linux.
      Not sure why I am getting error CS0246: The type or namespace name `Focas1′ could not be found. Are you missing an assembly reference?
      Help Appreciated.

      • Matthew Hier

        Hi Pushpak,

        I am glad that you enjoyed the tutorial. Once I get some free time, I plan to expand it a bit more. However, life has been rather hectic as of late.

        As for the error you are getting, it is difficult to say what could be causing it. Are you using C++ or .Net Core? It might be helpful if you could post some code and screenshots of your project in the forum so we can do some more in depth troubleshooting.

    • Author gravatar

      your videos were very helpful. I’d like to know if there are any similar sdk’s for siemens and delta controllers ?

      • Matthew Hier

        Hi Peter,
        Sorry for the late reply. I am sure those SDKs exist, however, I am not familiar with them. The only controllers I have experience with are OSAI and Fanuc. Wish I could be more helpful.

    • Author gravatar

      HELLO !
      It’s very helpful.
      i wanna ask some issue. I am trying to get Signal for ” f0.4 ” with pmc_rdpmcrng , but the return-data alway 0.
      Are you able to post the syntax for pmc_rdpmcrng?
      Maybe post an example for the layman out there?
      Finally, i wanna ask the syntax for cnc_rdexecprog,please.
      It will save me.

      • Matthew Hier

        Hi James,

        I am almost finished with a video that goes over the PMC_RDPMCRNG function. It should hopefully be posted by the end of the week. With that said, idk off the top of my head what f.04 is, but if you are only trying to get that one value, then you should only need to read the F0 byte and then extract out bit 4. You should be using IODBPMC0 struct in your call and the results should be inside the cdata field. Remember that bits are 0 based, so bit 04 is technically the 5th bit. Is the call completing successfully? Are you getting a return code other than 0 from the function call?

      • Matthew Hier

        Also… I forgot about the cnc_rdexecprog function. I do not have much experience with this function call, but I will take a look at it and see if I can figure anything out.

    • Author gravatar

      Hi Versex,
      I want to know if im wasting time or not regarding the following task. I have succesfully conect to my CNC machine which uses FANUC 31 I controler, also read some data from it.

      I get stuck when i try to extract/read the tools inside my CNC machine. Is FOCAS library capable of acces this type of data? Or did I overestimated it’s capabilities.

      • Matthew Hier

        Hi Lur,

        You are not overestimating it’s capabilities. You can certainly obtain tool information from Focas. That being said, it may depend on what type of machine you have. For instance, at Onsrud, we had two different types of tool changers, and the focas calls you needed to get the tool information was dependent on which tool changer you had. I do not have the code right now to show you, but when I get home this evening I will take a look at some of my examples and let you know which calls you may need.

        • Author gravatar

          Hi Versex,

          Thanks for replying. I get stuck here:

          {
          class Program
          {
          static void Main(string[] args)
          {
          ushort handle = 0;
          short result = 0;
          ushort port = 8193;
          string ip = “192.168.0.100”;
          ushort timeout = 10;

          // allocate Focas library handle
          result = Focas1.cnc_allclibhndl3(ip, port, timeout, out handle);
          if (result != 0)
          {
          Console.WriteLine(“Failed to allocate Focas library handle. Error code: {0}”, result);
          return;
          }

          // read tool magazine data
          short magazineType = 0; // 0 for fixed magazine type
          IODBTLMAG toolData = new IODBTLMAG();

          result = Focas1.cnc_rdmagazine(handle, ref magazineType, toolData); //THE ERROR IS HERE “TOOL DATA ”

          if (result == 0)
          {
          short count = toolData.count; // actual number of tools read
          // display tool magazine data
          for (int i = 0; i < count; i++)
          {
          Console.WriteLine("Tool {0}: T{1}, Diameter={2}, Length={3}, Type={4}",
          i + 1,
          toolData.data[i].number, // tool number
          toolData.data[i].diameter, // tool diameter
          toolData.data[i].length, // tool length
          toolData.data[i].type // tool type
          );
          }
          }
          else
          {
          Console.WriteLine("Failed to read tool magazine data. Error code: {0}", result);
          }

          // free Focas library handle
          Focas1.cnc_freelibhndl(handle);
          }
          }

          [StructLayout(LayoutKind.Sequential, Pack = 4)]
          public struct IODBTLMAG
          {
          public short count;
          [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)]
          public IODBTLMAG_DATA[] data;
          }

          [StructLayout(LayoutKind.Sequential, Pack = 4)]
          public struct IODBTLMAG_DATA
          {
          public short number;
          public float diameter;
          public float length;
          public short type;
          }
          }

          I think i´m close, but not sure at all.

          • Matthew Hier

            Hi Lur,

            I do have a couple of questions for you. 1: What kind of machine do you have? Is it a router / mill / etc…? Also, who is the manufacturer? The reason I ask is because when I was at Onsrud, we only used the built in Tool Management for GIFU tool changers. Most of our machines had a standard 12 tool rotary tool changer which didn’t use the tool management. If the machine you have doesn’t use the built-in tool management then you won’t be able to pull the information from that call. Also, when you enter your tool information, which screen do you enter it on?

            • Author gravatar

              Hi Versex,

              I have a 5 axis advanced milling machine from DMGMORI (NMH6300 model). It uses a 31i-A5 Fanuc controller.

              If it helps, when I use cnc_rdtooldata i got ” 1 “as the value of result variable:

              result = Focas1.cnc_rdtooldata(handle, startToolNumber, ref a, toolData);

              if (result != Focas1.EW_OK)
              {
              Console.WriteLine($”Failed to read tool data for tool {i}: {result}”);
              Console.Read();
              }
              Acording the Fanuc Focas API documentation thats because EW_FUNC
              (1) ERROR. Wich says:

              Unavailable
              This function cannot be used except 0i-PD/PF, 16i/18i-P, 30i/31i-LB, 30i/31i-PB.

            • Author gravatar

              This is m last attempt:

              using System;
              using System.Runtime.InteropServices;

              namespace ConsoleApp
              {
              class Program
              {
              static short result = 0;
              static ushort handle = 0;
              static void Main(string[] args)
              {
              // Establish connection
              result = Focas1.cnc_allclibhndl3(“192.168.3.212″, 8193, 10, out handle);
              if (result != Focas1.EW_OK)
              {
              Console.WriteLine($”Failed to connect to CNC: {result}”);
              Console.Read();
              return;
              }
              else
              {
              Console.WriteLine($”Succes to connect to CNC: {result}”);
              string mode = GetReadTool();
              Console.WriteLine($”Tool Data: {mode}”);
              Console.Read();
              }
              // Disconnect
              result = Focas1.cnc_freelibhndl(handle);
              if (result != Focas1.EW_OK)
              {
              Console.WriteLine($”Failed to disconnect from CNC: {result}”);
              Console.Read();
              return;
              }
              }

              public static string GetReadTool()
              {
              if (handle == 0)
              {
              Console.WriteLine($”Failed to connect to CNC: {result}”);
              Console.Read();
              return “”;
              }

              // Read tool data
              Focas1.IODBTLMNG toolData = new Focas1.IODBTLMNG();
              short s_number = 1;
              short data_num = 0;
              result = Focas1.cnc_rdtool(handle, s_number, ref data_num, toolData);

              if (result != Focas1.EW_OK)
              {
              Console.WriteLine($”Failed to read tool data: {result}”);
              Console.Read();
              return “”;
              }
              // Get the number of tools read
              short toolCount = data_num;

              //data_num;

              // Print tool data
              Console.WriteLine($”Number of tools: {toolCount}”);
              Console.Read();

              if (toolCount <= 0)
              {
              Console.WriteLine($"NO TOOLS IN CNC MACHINE");
              Console.Read();
              return "";
              }
              else
              {
              for (int i = 0; i < toolCount; i++)
              {
              Console.WriteLine($"Tool {i + 1}: Number={toolData.data1.T_code}"); //data2 or data3 for what use cases?
              Console.Read();
              }
              }

              if (result != Focas1.EW_OK)
              {
              Console.WriteLine($"Failed to read tool data: {result}");
              return "";
              }
              return "Tool data read successfully";
              }
              }
              }

              It should be work fine but it doenst read anything i get 0 as toolCount value.

    • […] It’s Time to Focas – Part 3: https://hierthinking.com/2020/05/06/its-time-to-focas-p3/ […]

    • […] It’s Time to Focas – Part 3: https://hierthinking.com/2020/05/06/its-time-to-focas-p3/ […]

    • Author gravatar

      Hi mathew, I have been exploring the FANUC Focas API for data retrieval and found your articles particularly helpful. However, I have a few queries regarding the capability of the Focas API in retrieving machine maintenance data. Specifically, I am interested in obtaining the following set of data:

      1. APC Battery
      2. CNC Battery
      3. Servo Spindle Motor Temperature
      4. Encoder Temperature
      5. Servo Spindle Insulation Resistance
      6. CNC Fans
      7. Internal Fan1 Power Supply SPDN Motor AMP
      8. Internal Fan1 Servo Amplifier
      9. Internal Fan1 Power Supply Servo Motor
      10. Internal Fan2 Power Supply SPDN Motor AMP
      11. Internal Fan2 Servo Amplifier
      12. Internal Fan2 Power Supply Servo Motor
      13. Battery Zero Seperate Detector
      14. Battery Zero Serial Seperator
      15. Radiator Fan1 Servo Spindle Amplifier
      16. Radiator Fan2 Servo Spindle Amplifier
      17. Dynamic Parameters (such as servo and spindle loads)

      While I have successfully retrieved some data using MTLinki software, I noticed that the Focas API does not seem to provide direct functions for reading these specific data points, as outlined in the FANUC Focas Library documentation (https://www.inventcom.net/fanuc-focas-library/general/fwlib32).

      I would greatly appreciate your guidance and expertise in this matter. If there are alternative approaches or additional resources that you could recommend for obtaining the aforementioned machine maintenance data through the Focas API, it would be immensely helpful.

      Thank you for your time and consideration. I look forward to your valuable insights.

Leave a Reply