0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenRCFでMyCobotを動かす

Posted at

本稿では,OpenRCFでMyCobotを動かす方法を解説します.
以降で紹介するコードは「mechArm 270 M5」用に書かれている(他種の場合は一部変更が必要かもしれない)点にご注意ください.

ちなみに,本稿を執筆している時点ではMyCobotのメーカーが公式にリリースしてるC#のライブラリにはバグがある(関節の角度を読み取れない)ので要注意です.

MyCobotクラスの追加

OpenRCFに元から記述されているSerialDeviceクラスの中に,以下のMyCobotクラスを追加します.

public class MyCobot : SerialBase
{
    private ReceiveDataHandler ReceiveData = new ReceiveDataHandler();
    private static Header Header = new Header(0xfe, 0xfe);

    public MyCobot(int baudRate = 115200)
    {
        SetBaudRate(baudRate);
        SerialPort.Handshake = Handshake.None;
        SerialPort.DtrEnable = true;
        SerialPort.RtsEnable = true;
        SerialPort.DataReceived += DataReceiveEvent;
    }

    private void DataReceiveEvent(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] readBytes = new byte[SerialPort.BytesToRead];
        SerialPort.Read(readBytes, 0, readBytes.Length);
        ReceiveData.Read(readBytes);
    }

    private void SerialWrite(byte[] bytes)
    {
        if (SerialPort.IsOpen) SerialPort.Write(bytes, 0, bytes.Length);
        else Console.WriteLine("Serial port is not open.");
    }

    public float[] ReceivedJointAngles { get { return ReceiveData.JointAngles; } }

    public void ConsoleWriteReceiveData()
    {
        Console.WriteLine(String.Join(" ", ReceiveData.JointAngles));
    }

    private byte speed = 30;            
    public void SetMotionSpeedPct(byte percent)
    {
        if (percent < 100) speed = percent;
        else speed = 100;
    }

    private void WriteJointAngleDeg(byte jointNo, float angle)
    {                
        byte[] sendBytes = new byte[9];
        sendBytes[0] = Header[0];
        sendBytes[1] = Header[1];
        sendBytes[2] = 0x06;
        sendBytes[3] = 0x21;
        sendBytes[4] = jointNo;
        int angle100 = (int)(100 * angle);
        sendBytes[5] = (byte)((angle100 >> 8) & 0xff);
        sendBytes[6] = (byte)(angle100 & 0xff);
        sendBytes[7] = speed;
        sendBytes[8] = 0xfa;
        SerialWrite(sendBytes);
    }
    
    public void WriteJoint1AngleDeg(float angle) { WriteJointAngleDeg(1, angle); }
    public void WriteJoint2AngleDeg(float angle) { WriteJointAngleDeg(2, angle); }
    public void WriteJoint3AngleDeg(float angle) { WriteJointAngleDeg(3, angle); }
    public void WriteJoint4AngleDeg(float angle) { WriteJointAngleDeg(4, angle); }
    public void WriteJoint5AngleDeg(float angle) { WriteJointAngleDeg(5, angle); }
    public void WriteJoint6AngleDeg(float angle) { WriteJointAngleDeg(6, angle); }          

    public void WriteJointAnglesDeg(params float[] angles)
    {
        if (angles.Length == 6)
        {
            byte[] sendBytes = new byte[18];
            sendBytes[0] = Header[0];
            sendBytes[1] = Header[1];
            sendBytes[2] = 0x0f;
            sendBytes[3] = 0x22;

            for (int i = 0; i < angles.Length; i++)
            {
                int angle100 = (int)(100 * angles[i]);
                sendBytes[4 + 2 * i] = (byte)((angle100 >> 8) & 0xff);
                sendBytes[4 + 2 * i + 1] = (byte)(angle100 & 0xff);
            }

            sendBytes[16] = speed;
            sendBytes[17] = 0xfa;
            SerialWrite(sendBytes);
        }
        else
        {
            Console.WriteLine("Number of angles is not 6.");
        }
    }

    public void WriteGripperValue(byte value)
    {
        byte[] sendBytes = { Header[0], Header[1], 0x04, 0x67, value, speed, 0xfa };
        SerialWrite(sendBytes);
    }

    public void RequestJointAnglesReply()
    {
        byte[] sendBytes = { Header[0], Header[1], 0x02, 0x20, 0xfa };
        SerialWrite(sendBytes);
    }

    public void WriteGripperEletric(bool state)
    {
        if (state == false)
        {
            byte[] sendBytes = { 0x01, 0x06, 0x01, 0x03, 0x03, 0xE8, 0x78, 0x88 };
            SerialWrite(sendBytes);
        }
        else if (state == true)
        {
            byte[] sendBytes = { 0x01, 0x06, 0x01, 0x03, 0x00, 0x00, 0x78, 0x88 };
            SerialWrite(sendBytes);
        }
    }

    private class ReceiveDataHandler
    {
        public float[] JointAngles = new float[6];
        private Packet ReadPacket = new Packet();

        public void Read(byte[] readBytes)
        {
            ReadPacket.Stack = readBytes;

            while (Header.Length < ReadPacket.Length)
            {
                if (Header.Contains(ReadPacket.Get))
                {
                    byte len = ReadPacket[Header.Length];

                    for (int i = 0; i < JointAngles.Length; i++)
                    {
                        int idx = Header.Length + 1 + 2 * i;

                        if (idx < Header.Length + len)
                        {
                            JointAngles[i] = ReadPacket.ToInt16(idx) / 100f;
                        }
                    }

                    ReadPacket.CutOut(Header.Length + len + 1); 
                }
                else
                {
                    Console.WriteLine("Error : Header does not match.");
                    ReadPacket.Reset();
                }
            }
        }

    }

}

もしエラーが出たら,クラスを貼り付ける場所(階層)が正しくない可能性が高いです.

MyCobotクラスの使用例

以下にMainWindow.xaml.csファイルの関数ButtonClick()の周辺を変更した例を示す.

SerialDevice.MyCobot MyCobot = new SerialDevice.MyCobot();
        
void Button1_Click(object sender, RoutedEventArgs e)
{
    MyCobot.PortOpen("COM13");
}

void Button2_Click(object sender, RoutedEventArgs e)
{
    MyCobot.RequestJointAnglesReply();
    MyCobot.ConsoleWriteReceiveData();
    float[] angles = MyCobot.ReceivedJointAngles;
}

void Button3_Click(object sender, RoutedEventArgs e)
{
    MyCobot.WriteJointAnglesDeg(0, 0, 0, 0, 0, 0);
}         

void Button4_Click(object sender, RoutedEventArgs e)
{
    MyCobot.WriteJointAnglesDeg(10, -10, 10, -10, 10, -10);
}

void Button5_Click(object sender, RoutedEventArgs e)
{
    MyCobot.SetMotionSpeedPct(50);            
}

ボタン3またはボタン4を押すとアームが動くので要注意です.

・COMの番号はデバイスマネージャーで要確認.
・関節の角度は度(degree)で指定する.
・関節の動作速度(MotionSpeed)はパーセントで指定する(初期値は30%).
・関数ConsoleWriteReceiveData()は受信した関節角度をコンソールに表示する.
・関数RequestJointAnglesReply()は関節角度の返信を要求するだけ(この関数を実行した後に時間差で受信データが更新される).つまり,ボタン2を最初に押したときは受信データの初期値(0,0,...,0)がコンソールに表示される.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?