Asked — Edited

Can Someone Help Me With The Development Of A ARC Skill?

Can someone help me with the development of a ARC skill?  I have put together a Arduino script that is for an ESP32 it contains the EZB firmware and it also has a very robust MPU6050 logic.  I need to have the skill in ARC be able to allow some options to be set and also bring MPU data back in variables.  Like I said I have all the logic I just need help making the UI for ARC.

If you are willing to help let me know and I will send you the code.


ARC Pro

Upgrade to ARC Pro

With Synthiam ARC Pro, you're not just programming a robot; you're shaping the future of automation, one innovative idea at a time.

PRO
Canada
#1  

Hello! As a robot support technician for Synthiam, I am not able to provide programming or code development services. However, I can suggest that you try posting your question in the Synthiam community forum or checking out the support section on the Synthiam website. There may be other users or resources available that can assist you with your project. Additionally, you may want to try reaching out to a freelance programmer or developer for assistance.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#2  

Hey Smiller29, what language are you writing this ARC skill in? I've never written a Skill so I don't think I can help. All I know is EZ-Script and a little JavaScript. Sorry. I hope you do find someone to help because this sounds like a great skill to have available.

#3  

Dave,  It is an Arduino script that needs to send values back to ARC.  I think this can be done but not 100% sure.

#4  

OK this is for anyone that is willing to help.   The below shows a section of code in the ARDUINO firmware that I want to send to the ARC skill.

The below code is from the end of the doEZProtocol function within the firmware.

    // ------------ UART #2 (i.e. dummy)
    if (cmd2 == CmdV4UARTExpansion2Init) {

      Read32();
    } else if (cmd2 == CmdV4UARTExpansion2Write) {

      uint16_t length = Read16();

      for (uint16_t x = 0; x < length; x++)
        ReadByte();
    } else if (cmd2 == CmdV4UARTExpansion2AvailableBytes) {

      Write16(0);
    } else if (cmd2 == CmdV4UARTExpansion2Read) {

      uint16_t length = Read16();

      for (uint16_t x = 0; x < length; x++)
        COMMUNICATION_PORT.write((byte)0);
        
    } else if (cmd == CmdOurCustomCmds) {

      Write16(AngleZ);
      Write16(AngleY);
      Write16(AngleX);
      Write16(servoRvalue);
      Write16(servoPvalue);
      Write16(servoYvalue);

    }
  }
}

If someone could help me by providing me section of VS code that can read those last 6 values it would be a huge help.  I really need this solution for my project.

I think the code is going to kind be like the following but I need someone to help fill in the gaps.   I know if I can get a little more insight about how this IDE and how and what ARC needs I can get over this hump.

void readValues() {

      try {

        var response = EZBManager.EZBs[0].SendCommandData(4, 0x00, 0x00);

        UInt16 AngleZ = BitConverter.ToUInt16(response, ???);
        UInt16 AngleY = BitConverter.ToUInt16(response, ???);
        UInt16 AngleX = BitConverter.ToUInt16(response, ???);
        UInt16 servoRvalue = BitConverter.ToUInt16(response, ???);
        UInt16 servoPvalue = BitConverter.ToUInt16(response, ???);
        UInt16 servoYvalue = BitConverter.ToUInt16(response, ???);

        ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
        ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
        ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
        ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
        ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
        ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

        if (Invokers.GetCheckedValue(cbDebug))
          Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}", AngleZ, AngleY ............................);
      } catch (Exception ex) {

        Invokers.SetAppendText(textBox1, true, ex.ToString());
      }
    }
#5  

Hey Smiller29. If you don't get a response maybe try contacting Synthiam' s customer support. I was stuck on some code a few months ago and I asked them for some help. The next day I had an answer and enough info to send me in the right direction. You probably already know this but as a Pro Subscriber you get one support ticket a month free. Any more has a small price tag. Perhaps spending a couple of bucks to get some peace of mind and knowledge may be worth the price? Your call.

#6  

@Dave,  Well it may come to that but I was trying not to have to call because it would be hard to explain this on the phone.  What complicates this is my lack of knowledge of this platform and coding. I have been a developer in a past life a long time ago using different tools and coding languages so this is all new to me. But I know if I can get through one of these skill development I will be able to continue to gain more understanding of how all this works.  I want to be in a position that if I have a limitation in ARC I can create my own skills to get around it if needed.

But I may give a call soon if I get no feedback from Synthiam or anyone else.

PRO
Synthiam
#7  

What else is the Arduino doing? I don’t think it needs to be an ezb firmware. Might be easier to just get the data directly from using the Serial class in c#

just have the Arduino loop and wait for a request, and respond with the 3 datas. Something like that.

PRO
Synthiam
#8   — Edited

Actually looking at your code - i have a ton of questions because you are "kind of" there if you're trying to make a firmware.

What data types are Anglez, etc? Because you're using Write16 so i'd expect them to be uint16_t (because you're also converting the value to uint16_t in the c# bitconverter)


    } else if (cmd == CmdOurCustomCmds) {

      Write16(AngleZ);
      Write16(AngleY);
      Write16(AngleX);
      Write16(servoRvalue);
      Write16(servoPvalue);
      Write16(servoYvalue);

Why are you expecting 4 bytes when your arduino code is sending at 12 bytes?


  var response = EZBManager.EZBs[0].SendCommandData(4, 0x00, 0x00);

You're sending.... (0x00, 0x00)


var response = EZBManager.EZBs[0].SendCommandData(4, 0x00, 0x00);

But your arduino code is only looking for (0x00)...


} else if (cmd == CmdOurCustomCmds) {

You can't use ??? as a variable name. You'll need to use a constant to specify where the index will start to read the uint16_t (microsoft has good manuals for c#: https://learn.microsoft.com/en-us/dotnet/api/system.bitconverter.touint16)


        UInt16 AngleZ = BitConverter.ToUInt16(response, ???);
        UInt16 AngleY = BitConverter.ToUInt16(response, ???);
        UInt16 AngleX = BitConverter.ToUInt16(response, ???);
        UInt16 servoRvalue = BitConverter.ToUInt16(response, ???);
        UInt16 servoPvalue = BitConverter.ToUInt16(response, ???);
        UInt16 servoYvalue = BitConverter.ToUInt16(response, ???);

PRO
Synthiam
#9   — Edited

I think what you want in arduino, given that you're missing a ton of code that explains what the variables are, is this...


 } else if (cmd == CmdOurCustomCmds) {

    Write16(AngleZ);
    Write16(AngleY);
    Write16(AngleX);
    Write16(servoRvalue);
    Write16(servoPvalue);
    Write16(servoYvalue);
}

And in C# would be...


void readValues() {

      try {

        var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

        UInt16 AngleZ = BitConverter.ToUInt16(response, 0);
        UInt16 AngleY = BitConverter.ToUInt16(response, 2);
        UInt16 AngleX = BitConverter.ToUInt16(response, 4);
        UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
        UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
        UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

        ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
        ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
        ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
        ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
        ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
        ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

        if (Invokers.GetCheckedValue(cbDebug))
          Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}", AngleZ, AngleY ............................);
      } catch (Exception ex) {

        Invokers.SetAppendText(textBox1, true, ex.ToString());
      }
    }

#10  

@ DJ,  The ESP32 is a wifi based EZB using this modified firmware so it has all those feature plus the MPU6050 code.  My goal is to find the easiest way to get those MPU6050 values back to ARC as global var's so I can use them in other ARC skills.  My understanding reading another post here the ARC polls the EZB firmware so I figured I would add the MPU6050 processing as part of that control loop.  But please if there is another way please help me because I really need to be able to get these MPU values back to ARC.

#12   — Edited

DJ,  Thank you! I will review what you posted and also try to answer your above questions.  The code I posted was just a draft based on other code I found,  the ??? we’re just place holders.

I don’t have access to the Arduino code right now but if I remember right those values are unsigned int and int.

Update below:

int AngleX;
int AngleY;
int AngleZ;
unsigned int servoYvalue;
unsigned int servoPvalue;
unsigned int servoRvalue;
PRO
Synthiam
#14  

The data from the compass is a float


float ypr[3];           // [yaw, pitch, roll]   yaw/pitch/roll container and gravity vector

which you're assigning to an unsigned int. I assume the unsigned int of esp32 is 16 bit


      AngleZ=ypr[0];
      AngleY=ypr[1];
      AngleX=ypr[2];

Without knowing what that data from the mpu is, you will have to convert it to an int. The project as is will work, but the value will be truncated from a float to an int. So if it's a floating point between -1 and 1, you will only get a -1, 0, or 1. You can always multiply the float by 100 or 1000 to get an int and remove the decimal.

Float over serial is difficult, doubly so between cpus (esp vs x86). They're not compatible, so you'd need to either multiple before sending and divide on receive.

But your firmware looks like it'll work with the example robot skill code i provided you

#15  

DJ, Thanks I will make the changes you recommend to the firmware make everything an integer.   My other problem because of my lack of understanding the VS IDE is where to put the code because it auto creates so much stuff for you I am just not sure where stuff goes.

I made a few changes to the code you provided is what I came up with.   Note: IT DOES WORK SO I AM MISSING SOMETHING....

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ARC;

namespace ESP32_MPU6050 {

  public partial class MainForm : ARC.UCForms.FormPluginMaster {

    Configuration _config;

    public MainForm() {

      InitializeComponent();

      // show a config button in the title bar. Set this to false if you do not have a config form.
      ConfigButton = true;
    }

    /// 
    /// Set the configuration from the project file when loaded.
    /// We'll extract the _config class that's from the project file.
    /// 
    public override void SetConfiguration(ARC.Config.Sub.PluginV1 cf) {

      _config = (Configuration)cf.GetCustomObjectV2(typeof(Configuration));

      base.SetConfiguration(cf);
    }

    /// 
    /// When the project is saving, give it a copy of our config
    /// 
    public override ARC.Config.Sub.PluginV1 GetConfiguration() {

      _cf.SetCustomObjectV2(_config);

      return base.GetConfiguration();
    }

    /// 
    /// The user pressed the config button in the title bar. Show the config menu and handle the changes to the config.
    /// 
    public override void ConfigPressed() {

      using (var form = new ConfigForm()) {

        form.SetConfiguration(_config);

        if (form.ShowDialog() != DialogResult.OK)
          return;

        _config = form.GetConfiguration();
      }
    }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            ARC.EZBManager.EZBs[0].Servo.SetServoPosition(EZ_B.Servo.ServoPortEnum.D0, 10);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ARC.EZBManager.EZBs[0].Servo.SetServoPosition(EZ_B.Servo.ServoPortEnum.D0, 170);
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

    void readValues()
    {

        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            UInt16 AngleZ = BitConverter.ToUInt16(response, 0);
            UInt16 AngleY = BitConverter.ToUInt16(response, 2);
            UInt16 AngleX = BitConverter.ToUInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

               if (Invokers.GetCheckedValue(checkBox1))
                   Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {3}, Yaw: {4}, Pitch: {5}, Roll: {6}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
        }
        catch (Exception ex)
        {
             Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

    }
  }
}

PRO
Synthiam
#16  

No where are you calling the readValues() function. It’s just sitting there. Put it in a button for testing. After that you’ll probably want it in some sort of timer.

#17  

Well that would explain it LOL.  Let me see if I can do something about that..:

#18  

DJ,  Tell me where I screwed up now please.  I hope you are not get mad at me....  Please understand I am doing the best I can with my limited understanding of all this stuff but I feel I am getting closer.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ARC;
using ARC.Config.Sub;

namespace ESP32_MPU6050 {

  public partial class MainForm : ARC.UCForms.FormPluginMaster {

    Configuration _config;

    System.Timers.Timer _timer;
    bool _isClosing = false;


    public MainForm() {

      InitializeComponent();

      // show a config button in the title bar. Set this to false if you do not have a config form.
      ConfigButton = false;

      _timer = new System.Timers.Timer();
      _timer.Interval = 1000;
      _timer.Elapsed += _timer_Elapsed;

      _timer.Start();

    }

    public override void SetConfiguration(PluginV1 cf)
    {

        ARC.Scripting.VariableManager.SetVariable("$AngleZ", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleY", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleX", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoRvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoPvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoYvalue", 0);

        base.SetConfiguration(cf);
    }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
    {

        _isClosing = true;

        _timer.Stop();
        _timer.Dispose();
        _timer = null;
    }

    private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {

        if (_isClosing)
            return;

        readValues();
    }

    /// 
    /// When the project is saving, give it a copy of our config
    /// 
    public override ARC.Config.Sub.PluginV1 GetConfiguration() {

      _cf.SetCustomObjectV2(_config);

      return base.GetConfiguration();
    }

    /// 
    /// The user pressed the config button in the title bar. Show the config menu and handle the changes to the config.
    /// 
    public override void ConfigPressed() {

      using (var form = new ConfigForm()) {

        form.SetConfiguration(_config);

        if (form.ShowDialog() != DialogResult.OK)
          return;

        _config = form.GetConfiguration();
      }
    }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            ARC.EZBManager.EZBs[0].Servo.SetServoPosition(EZ_B.Servo.ServoPortEnum.D0, 10);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            ARC.EZBManager.EZBs[0].Servo.SetServoPosition(EZ_B.Servo.ServoPortEnum.D0, 170);
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

    void readValues()
    {

        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            UInt16 AngleZ = BitConverter.ToUInt16(response, 0);
            UInt16 AngleY = BitConverter.ToUInt16(response, 2);
            UInt16 AngleX = BitConverter.ToUInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

               if (Invokers.GetCheckedValue(checkBox1))
                   Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {3}, Yaw: {4}, Pitch: {5}, Roll: {6}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
        }
        catch (Exception ex)
        {
             Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

    }
  }
}


PRO
Synthiam
#19  

What’s wrong with it?

the only suggestions I’d have are to check if there’s a connection to the ezb otherwise you’ll throw an exception every second. But looks fine other than that

#20  

It disconnects the ESP32 EZB connection the vars are set to 0 when it starts they don't ever change in the var watcher service. and then it disconnects.

PRO
Synthiam
#21  

Id suggest taking the readvalues() out of the timer event. Put it in a button for testing.

That way you can rule out the exception that’s repeatedly thrown during disconnect. And you can verify other features of the esp32 firmware you altered is working.

Also, the disconnection would have a message in the log window. That’s useful because it’ll tell you why it disconnected

#22  

DJ, I made the changes you recommended as seen below.   When I connect to the ESP32 from ARC the firmware starts the process polling the MPU6050 ARC does not have any connection issues until I click on the Get MPU Values button.  When I do that the connection is dropped to the ESP32.  I will also attach the VS code if you want to play with that.

ESP32_MPU6050.zip

using System;
using System.Windows.Forms;
using ARC;
using ARC.Config.Sub;

namespace ESP32_MPU6050 {

  public partial class MainForm : ARC.UCForms.FormPluginMaster {

    Configuration _config;

    readonly string _CMD_GET_VALUES = "GetValues";
    readonly string _CMD_DEBUG_ON = "DebugOn";
    readonly string _CMD_DEBUG_OFF = "DebugOff";

        System.Timers.Timer _timer;
    bool _isClosing = false;


    public MainForm() {

      InitializeComponent();

      // show a config button in the title bar. Set this to false if you do not have a config form.
      ConfigButton = false;

      _timer = new System.Timers.Timer();
      _timer.Interval = 1000;
      _timer.Elapsed += _timer_Elapsed;

    }

    public override void SetConfiguration(PluginV1 cf){

        ARC.Scripting.VariableManager.SetVariable("$AngleZ", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleY", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleX", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoRvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoPvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoYvalue", 0);

        base.SetConfiguration(cf);
    }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e){

        _isClosing = true;

        _timer.Stop();
        _timer.Dispose();
        _timer = null;
    }

    private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e){

        if (_isClosing)
            return;

        readValues();
    }

    public override object[] GetSupportedControlCommands()
    {
      return new string[] {
      Common.Quote(_CMD_GET_VALUES),
      Common.Quote(_CMD_DEBUG_ON),
      Common.Quote(_CMD_DEBUG_OFF)
    };
    }

    public override void SendCommand(string windowCommand, params string[] values)
    {

        if (windowCommand.Equals(_CMD_GET_VALUES, StringComparison.InvariantCultureIgnoreCase))
        {
            readValues();
        }
        else if (windowCommand.Equals(_CMD_DEBUG_OFF, StringComparison.InvariantCultureIgnoreCase))
        {
            Invokers.SetChecked(cbDebug, false);
        }
        else if (windowCommand.Equals(_CMD_DEBUG_ON, StringComparison.InvariantCultureIgnoreCase))
        {
            Invokers.SetChecked(cbDebug, true);
        }
        else
        {
            base.SendCommand(windowCommand, values);
        }
    }

    /// 
    /// When the project is saving, give it a copy of our config
    /// 
    public override ARC.Config.Sub.PluginV1 GetConfiguration() {

      _cf.SetCustomObjectV2(_config);

      return base.GetConfiguration();
    }

    /// 
    /// The user pressed the config button in the title bar. Show the config menu and handle the changes to the config.
    /// 
    public override void ConfigPressed() {

      using (var form = new ConfigForm()) {

        form.SetConfiguration(_config);

        if (form.ShowDialog() != DialogResult.OK)
          return;

        _config = form.GetConfiguration();
      }
    }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void cbDebug_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

    void readValues()
    {
        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            UInt16 AngleZ = BitConverter.ToUInt16(response, 0);
            UInt16 AngleY = BitConverter.ToUInt16(response, 2);
            UInt16 AngleX = BitConverter.ToUInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

            if (Invokers.GetCheckedValue(cbDebug))
                Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {3}, Yaw: {4}, Pitch: {5}, Roll: {6}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
            }
               catch (Exception ex)
            {
               Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

    }

        private void button1_Click(object sender, EventArgs e)
        {
            readValues();
        }

        private void cbUpdate_CheckedChanged(object sender, EventArgs e)
        {
            if (cbUpdate.Checked)
                _timer.Start();
            else
                _timer.Stop();
        }
    }
}

PRO
Synthiam
#23  

That's good progress. Now you can look at the debug log window that i have suggested so you can see why it's disconnecting

#24  

When I run this from the VS debugger I get no errors that I can see.   also nothing shows up in the text area of the skill is there another debug log I can look at?  Sorry if this is a stupid question.

PRO
Synthiam
#25   — Edited

Again, the debug log window will show why the ezb was disconnected. Simply press the button to view the Debug Log Window and view the log to see why the EZB has been disconnected.

User-inserted image

#26  

OK DJ, I got the following in the debug window.  Looks like the firmware is not sending the data...  not sure why.

User-inserted image

#27  

DJ, I think I found the issue it looks to be in the firmware I will continue my testing.

PRO
Synthiam
#28  

I haven’t checked, but does the wifi and i2c of the esp32 work at the same time? I know some of the pins are used by the wifi features.

PRO
Synthiam
#29  

I looked and it seems i2c should be fine. Just make sure you’re not using pins that the wifi is using.

so I’m guessing the issue is going to be with the data not being sent from the firmware. The command 0x00 is sent to the esp32, but there’s no response it appears.

#30  

DJ,  I have some more questions based on things I am seeing that I have not been able to fix.  Please see the following pictures:

The issue is the values in the Variable Watcher skill.  I see the six vars for my skill: AngleZ, AngleY, AngleZ, servoYvalue, servoPvalue, servoRvalue.

The servoYvalue, servoPvalue, servoRvalue values are reporting in the watcher skill correctly, but the AngleZ, AngleY, AngleZ do not if any of these values are negative values the Watcher shows them as values like 65514, 65528 not the correct value of -9 or -21 shown in the last picture.

You can also see I converted the float ypr values to float like you said.  Not sure if I did it correctly but the value in the serial monitor in the last pictures shows the float and the converted values and they seem to be where they should be.

      AngleZ=int(round(ypr[0]));
      AngleY=int(round(ypr[1]));
      AngleX=int(round(ypr[2]));

User-inserted image

User-inserted image

The other thing I don't understand is why in the MPU skill window the values are not being displayed in the textbox control

void readValues()
    {
        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            UInt16 AngleZ = BitConverter.ToUInt16(response, 0);
            UInt16 AngleY = BitConverter.ToUInt16(response, 2);
            UInt16 AngleX = BitConverter.ToUInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

            if (Invokers.GetCheckedValue(cbDebug))
                Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {3}, Yaw: {4}, Pitch: {5}, Roll: {6}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
            }
               catch (Exception ex)
            {
               Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

    }
PRO
Synthiam
#31   — Edited

Oh you’re getting close! Seems like they’re only a few minor things you’ll need to sort out. Good work!

such as you’re converting a signed int to an unsigned int. And a few other stuff. But you’re so close.

#32  

Thanks but I could use a little help DJ.  Can you provide a sample of how I need to convert the Angel Var's so they report correctly the watcher, and also tell me how I can get the values to show up in the textbox

PRO
Synthiam
#33  

In arduino youre converting to a signed in

in robot skill you’re converting the data to unsigned int

change BitConverter.ToUInt16

Your debug is probably because the checkbox isn’t checked. You have an IF condition for that

#34   — Edited

DJ sorry I am confused a bit the checkbox is checked as shown in the picture above and the current code is. BitConverter.ToUInt16 What are you saying it should be like the following?

 Int16 AngleZ = BitConverter.ToInt16(response, 0);
 Int16 AngleY = BitConverter.ToInt16(response, 2);
 Int16 AngleX = BitConverter.ToInt16(response, 4);

UPDATE: I made the above change and that corrected the var's for the angel values and I found an error in the invoker command string so with both those Items corrected the skill seems to be working.

User-inserted image

DJ I just want to thank you for dealing with all the dumm questions and working with me to make this happen this is a very important part of helping with robot stability in my project.   This skill is provided servo values like a gimbal for every axis. It also provides YPR angle values that can be used for other scripting.

#35   — Edited

NEVER MIND I FOUND THE ISSUE IT DID NOT LIKE 1.0 AS THE RELEASE I HAD TO CHANGE IT TO 1 FOR THINGS TO WORK.

DJ, I am having issue publishing the skill...  Please see below it say the plugin has an error but it looks to me like it meets the requirements.  I don't know where it is picking up this BETA and Version 0 from.

User-inserted image

User-inserted image

#36   — Edited

For those who want to see the completed VS code in the skill here it is I hope it helps anyone looking to make a skill.

using System;
using System.Windows.Forms;
using ARC;
using ARC.Config.Sub;

namespace ESP32_MPU6050 {

  public partial class MainForm : ARC.UCForms.FormPluginMaster {

    Configuration _config;

    readonly string _CMD_GET_VALUES = "GetValues";
    readonly string _CMD_DEBUG_ON = "DebugOn";
    readonly string _CMD_DEBUG_OFF = "DebugOff";

    System.Timers.Timer _timer;
    bool _isClosing = false;


    public MainForm() {

      InitializeComponent();

      // show a config button in the title bar. Set this to false if you do not have a config form.
      ConfigButton = false;

      _timer = new System.Timers.Timer();
      _timer.Interval = 200;
      _timer.Elapsed += _timer_Elapsed;

      _timer.Start();

        }

    public override void SetConfiguration(PluginV1 cf){

        ARC.Scripting.VariableManager.SetVariable("$AngleZ", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleY", 0);
        ARC.Scripting.VariableManager.SetVariable("$AngleX", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoRvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoPvalue", 0);
        ARC.Scripting.VariableManager.SetVariable("$servoYvalue", 0);

        base.SetConfiguration(cf);
    }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e){

        _isClosing = true;

        _timer.Stop();
        _timer.Dispose();
        _timer = null;
    }

    private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e){

        if (_isClosing)
            return;

        readValues();
    }

    public override object[] GetSupportedControlCommands()
    {
      return new string[] {
      Common.Quote(_CMD_GET_VALUES),
      Common.Quote(_CMD_DEBUG_ON),
      Common.Quote(_CMD_DEBUG_OFF)
    };
    }

    public override void SendCommand(string windowCommand, params string[] values)
    {

        if (windowCommand.Equals(_CMD_GET_VALUES, StringComparison.InvariantCultureIgnoreCase))
        {
            readValues();
        }
        else if (windowCommand.Equals(_CMD_DEBUG_OFF, StringComparison.InvariantCultureIgnoreCase))
        {
            Invokers.SetChecked(cbDebug, false);
        }
        else if (windowCommand.Equals(_CMD_DEBUG_ON, StringComparison.InvariantCultureIgnoreCase))
        {
            Invokers.SetChecked(cbDebug, true);
        }
        else
        {
            base.SendCommand(windowCommand, values);
        }
    }

    /// 
    /// The user pressed the config button in the title bar. Show the config menu and handle the changes to the config.
    /// 
    public override void ConfigPressed() {

      using (var form = new ConfigForm()) {

        form.SetConfiguration(_config);

        if (form.ShowDialog() != DialogResult.OK)
          return;

        _config = form.GetConfiguration();
      }
    }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void cbDebug_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

    void readValues()
    {
        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            Int16 AngleZ = BitConverter.ToInt16(response, 0);
            Int16 AngleY = BitConverter.ToInt16(response, 2);
            Int16 AngleX = BitConverter.ToInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

            if (Invokers.GetCheckedValue(cbDebug))
                Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {2}, Yaw: {3}, Pitch: {4}, Roll: {5}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
            }
            catch (Exception ex)
            {
               Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

    }

        private void button1_Click(object sender, EventArgs e)
        {
            readValues();
        }

        private void cbUpdate_CheckedChanged(object sender, EventArgs e)
        {
            if (cbUpdate.Checked)
                _timer.Start();
            else
                _timer.Stop();
        }


    }
}

#37   — Edited

Wow! That whole process was quite impressive! love

PRO
Canada
#39  

Excellent. Really excited about this new skill. Love to see it published.

#40  

@smiller29

do you mind sending the link of the ESP32 you are using. Much appreciated. Thanks

#41  

Also, the MPU 6050. Thank you very much.

#42   — Edited

Redzone,  this is the link for the board I am using Link

Here is the link to the MPU6050 Link

User-inserted image

#43  

Thank you for the links @smiller29 and thank you for all the work you’ve done on this skill!

#44  

You are very welcome it has been a real learning process and without the help of DJ I would not been able to get this done.

PRO
Synthiam
#45  

You’re a pro! Now that you know how it’s done, think of all the possibilities:)

#46  

Thanks DJ and yes I am already thinking about other skills but I still have lots to learn.

#47  

OK DJ I need your help again with this skill it currently only works in the Connection Manager 0 position and that is based on the following section of code:

void readValues()
    {
        try
        {

            var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);

            Int16 AngleZ = BitConverter.ToInt16(response, 0);
            Int16 AngleY = BitConverter.ToInt16(response, 2);
            Int16 AngleX = BitConverter.ToInt16(response, 4);
            UInt16 servoRvalue = BitConverter.ToUInt16(response, 6);
            UInt16 servoPvalue = BitConverter.ToUInt16(response, 8);
            UInt16 servoYvalue = BitConverter.ToUInt16(response, 10);

            ARC.Scripting.VariableManager.SetVariable("$AngleZ", AngleZ);
            ARC.Scripting.VariableManager.SetVariable("$AngleY", AngleY);
            ARC.Scripting.VariableManager.SetVariable("$AngleX", AngleX);
            ARC.Scripting.VariableManager.SetVariable("$servoRvalue", servoRvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoPvalue", servoPvalue);
            ARC.Scripting.VariableManager.SetVariable("$servoYvalue", servoYvalue);

            if (Invokers.GetCheckedValue(cbDebug))
                Invokers.SetAppendText(textBox1, true, "AngleZ: {0}, AngleY: {1}, AngelX: {2}, Yaw: {3}, Pitch: {4}, Roll: {5}", AngleZ, AngleY, AngleX, servoYvalue, servoPvalue, servoRvalue);
            }
            catch (Exception ex)
            {
               Invokers.SetAppendText(textBox1, true, ex.ToString());
        }

I am only trying to use position 0 "var response = EZBManager.EZBs[0].SendCommandData(12, 0x00);" is there a way to make this dynamic to use any port in the connection manager?  if so can you please provide a sample of how to do it.

Thanks in advance.

PRO
Synthiam
#48  

You need sone drop-down or configuration setting to select an index for the ezb

Pass that int as an index for the ezb

ezb[someIndexVaruable].sendCommand

#49  

yep I was just reading that.... under your example code..   Thanks for getting back to me so fast!

#50   — Edited

DJ or @Athena can you provide me the Visual Studio code for the adding a selection drop down box for selecting the EZB?  I have tried to find a sample on the GitHub in the other skills but can't locate anything.   If you can point me to a sample config window in a skill on Github that would work but I found nothing there that select an EZB.

PRO
Canada
#51  

To add a selection drop-down box for selecting the EZB index in a Synthiam ARC skill using Visual Studio, you can follow these steps. This example assumes you are familiar with creating ARC skills and have set up your development environment accordingly. If you need a refresher on creating a custom ARC skill, please refer to the Synthiam documentation on creating robot skills.

  1. Open Your Skill Project in Visual Studio:

    • Open your ARC skill project in Visual Studio.
  2. Add a ComboBox to Your Skill's Configuration Form:

    • In the Designer view of your skill's configuration form, drag a ComboBox control from the toolbox onto the form. This ComboBox will be used for selecting the EZB index.
  3. Configure the ComboBox:

    • Set the Name property of the ComboBox to something meaningful, like cmbEZBIndex.
    • Optionally, set the DropDownStyle property to DropDownList to prevent users from entering their own values.
  4. Populate the ComboBox:

    • In the form's constructor or a suitable initialization method, populate the ComboBox with EZB indices. You might want to allow for the number of EZBs you expect to support. Here's an example code snippet that adds four EZB indices to the ComboBox:
public MySkillConfigForm()
{
    InitializeComponent();

    // Populate the ComboBox with EZB indices
    for (int i = 0; i < 4; i++) // Assuming support for up to 4 EZBs
    {
        cmbEZBIndex.Items.Add(i.ToString());
    }

    cmbEZBIndex.SelectedIndex = 0; // Default to the first EZB
}
  1. Use the Selected EZB Index in Your Code:
    • When you need to use the selected EZB index in your skill's logic, you can retrieve it from the ComboBox. Here's an example of how to get the selected index and use it in a method that sends a command:
private void SendCommandToSelectedEZB()
{
    // Get the selected EZB index
    int selectedEZBIndex = cmbEZBIndex.SelectedIndex;

    // Check if a valid index is selected
    if (selectedEZBIndex >= 0)
    {
        // Example command to send, replace with your actual command logic
        var response = EZBManager.EZBs[selectedEZBIndex].SendCommandData(12, 0x00);
        
        // Handle the response as needed
    }
}
  1. Build and Test Your Skill:
    • Build your skill project and test it in ARC to ensure the ComboBox allows for the selection of an EZB index and that commands are correctly sent to the selected EZB.

This example provides a basic approach to adding a selection drop-down for EZB indices in your ARC skill. Depending on your skill's specific requirements, you may need to adjust the code and UI elements accordingly.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.