我试图控制两个伺服电机使用Unity和Arduino之间的串行连接.

然而,我注意到,虽然Arduino代码工作正常,并且我可以根据"逆时针"、"顺时针"、"逆时针关节2"和"顺时针关节2"命令独立地为伺服电机供电,但当我试图在一个更新循环内向串口监视器发送两个命令时,我的两个伺服运动都没有.

以下是Arduino代码:


`#include <Servo.h> // servo library

String input;
int count;
int countSecond;
int rotationAngleStep;

Servo servo1; // servo control object
Servo servo2;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  servo1.attach(13);
  servo1.write(0);
  servo2.attach(10);
  servo2.write(0);
  count = 0;
  countSecond = 0;
  rotationAngleStep = 10;
}

void loop() 
{
  input = Serial.readString();
  Serial.print(input);
      
  if(input == "anticlockwise")
  {
    Serial.println("turn motor");
    count = count + 1;
    servo1.write(count*rotationAngleStep);  
   }

  if(input == "clockwise")
  {
    Serial.println("turn motor");
    if(count > 0)
    {
    count = count - 1;
    servo1.write(count*rotationAngleStep);
    }   
  }


    if(input == "anticlockwise joint 2")
  {
    Serial.println("turn motor");
    countSecond = countSecond + 1;
    servo2.write(countSecond*rotationAngleStep);
   }

    if(input == "clockwise joint 2")
  {
    Serial.println("turn motor");
    if(countSecond > 0)
    {
    countSecond = countSecond - 1;
    servo2.write(countSecond*rotationAngleStep);
    }   
  }

  delay(1000);


}
    
    //}if(data == 'servo1'){
      //servo1.write(10);
    //}if(data == 'servo2'){
      //servo2.write(10);
    
 `

以下是单位代码:

``using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using Unity.VisualScripting;
using UnityEngine;
using System.IO.Ports;

public class IKManager : MonoBehaviour
{


    public SerialPort serial = new SerialPort("COM4",9600);
    //basically want to evaluate how close we are to target by assessing end effector value in the y dimension, against target value in the y dimension.
    //by evaluating distance between two iterative frames (and attaining a slope value) can tell if moving further or closer to end effector. Gradient descent.

    //root of the armature
    public Joint m_root;

    //End effector
    public Joint m_end;

    public GameObject m_target;

    public float m_threshold = 20f;

    public float m_rate = 1.0f;

    private int counter = 2;

    private float timer;

    private float slope1;
    private float slope2;

    private float intermediary;

    void Start(){
        if(serial.IsOpen == false){
            serial.Open();
        }

        serial.Write("hey");
    }

    // Calculate slope - i.e distance between points divided by step (delta theta)
    float CalculateSlope(Joint _joint)
    {
        float deltaTheta = 10f;
        float distance1 = GetDistance(m_end.transform.position, m_target.transform.position);

        _joint.transform.Rotate(0f,0f,deltaTheta,Space.World);

        float distance2 = GetDistance(m_end.transform.position, m_target.transform.position);

        _joint.transform.Rotate(0f,0f,-deltaTheta,Space.World);

        return (distance2 - distance1) / deltaTheta;

    }

    async void Update()
    {
        timer = Time.realtimeSinceStartup;
        //Debug.Log(timer);
        //Debug.Log("counter " + counter);
        if (timer > 4*counter)
        {
            Debug.Log("can move now");
            counter = counter + 1;
            Debug.Log(counter);
            if (GetDistance(m_end.transform.position, m_target.transform.position) > m_threshold)
            {
                Joint current = m_root;
                float slope1 = CalculateSlope(current);
                if (slope1 > 0){
                    current.transform.Rotate(0f,0f,-10f,Space.World);
                    serial.Write("clockwise");
                    Debug.Log("clockwise");
                }if(slope1 < 0){
                    current.transform.Rotate(0f,0f,10f,Space.World);
                    serial.Write("anticlockwise");
                    Debug.Log("anticlockwise");                             
                }
                //Debug.Log("Slope " + slope);
                
                //Debug.Log("Move Servo");

                current = current.GetChild();
                slope2 = CalculateSlope(current);
                if (slope2 > 0){
                    current.transform.Rotate(0f,0f,-10f,Space.World);
                    //serial.Write("clockwise joint 2");
                    Debug.Log("clockwise joint 2");
                }if(slope2 < 0){
                    current.transform.Rotate(0f,0f,10f,Space.World);
                    //serial.Write("anticlockwise joint 2");
                    Debug.Log("anticlockwise joint 2");                               
                }
                //Debug.Log("Slope " + slope);




                
                // if(slope != 0){
                //     serial.Write("servo2");
                // }else{
                //     serial.Write("no change");
                // } 
                // serial.Close() ;
            
            }
        }
        
    }
    float GetDistance(Vector3 _point1, Vector3 _point2)
    {
        return Vector3.Distance(_point1, _point2);
    }

}`

我认为这可能是因为信号可能在同一行上注册,但后来我在Arduino中的serial.read()函数之后引入了延迟,并遇到了同样的问题.任何帮助将不胜感激.

推荐答案

你需要更新你的Arduino循环

From Documentation

Serial.readString()将字符从串口缓冲区读入字符串.如果超时,该函数将终止(请参见setTimeout()).

void loop() {
  while (Serial.available() == 0) {}   // wait for data available
  input = Serial.readString();         // read until timeout
  input.trim();                        // remove any \r \n whitespace at the end of the String
  Serial.print(input);

  if (input == "anticlockwise") {
    Serial.println("turn motor");
    count = count + 1;
    servo1.write(count * rotationAngleStep);
  } else if (input == "clockwise") {
    Serial.println("turn motor");
    if (count > 0) {
      count = count - 1;
      servo1.write(count * rotationAngleStep);
    }
  } else if (input == "anticlockwise joint 2") {
    Serial.println("turn motor");
    countSecond = countSecond + 1;
    servo2.write(countSecond * rotationAngleStep);
  } else if (input == "clockwise joint 2") {
    Serial.println("turn motor");
    if (countSecond > 0) {
      countSecond = countSecond - 1;
      servo2.write(countSecond * rotationAngleStep);
    }
  }
  delay(1000);
}

Extra Solution / Idea - Change the communication protocal

监视Serial.print(input);的输出,然后查看它的值是否在这里发布,因为这样编写时它可能会被合并

anticlockwise
anticlockwiseanticlockwise joint 2
anticlockwise joint 2anticlockwise

如果是这样的话,我建议你在你的串行码的末尾加上一个空字节,然后在你的Arduino中,用空字节分割你的修剪后的字符串,然后把它移到一个循环中,这样你就可以循环通过它,然后执行上述命令

就像来自统一代码的

serial.Write("anticlockwise joint 2" + char.MinValue);
serial.Write("anticlockwise" + char.MinValue);

然后在Arduino代码中执行如下操作

void loop() {
  while (Serial.available() == 0) {} // wait for data available
  input = Serial.readString(); // read until timeout
  input.trim(); // remove any \r \n whitespace at the end of the String
  Serial.print(input);

  // Use strtok to split the string into tokens
  char * token = strtok(input, "\0");
  // Continue until no more tokens are found
  while (token != NULL) {
    if (token == "anticlockwise") {
      Serial.println("turn motor");
      count = count + 1;
      servo1.write(count * rotationAngleStep);
    } else if (token == "clockwise") {
      Serial.println("turn motor");
      if (count > 0) {
        count = count - 1;
        servo1.write(count * rotationAngleStep);
      }
    } else if (token == "anticlockwise joint 2") {
      Serial.println("turn motor");
      countSecond = countSecond + 1;
      servo2.write(countSecond * rotationAngleStep);
    } else if (token == "clockwise joint 2") {
      Serial.println("turn motor");
      if (countSecond > 0) {
        countSecond = countSecond - 1;
        servo2.write(countSecond * rotationAngleStep);
      }
    }
    token = strtok(NULL, "\0");
  }
}

Csharp相关问答推荐

获取Windows和Linux上的下载文件夹

如何将ref T*重新解释为ref nint?

如何使嵌套for-loop更高效?

找不到网址:https://localhost:7002/Category/Add?区域= Admin.为什么我的URL是这样生成的?area = Admin而不是/Admin/

创建临时Collection 最有效的方法是什么?堆栈分配和集合表达式之间的区别?

Blazor WebApp:原始异常:AADSTS700025:客户端是公共的,因此既不应显示客户端,也不应显示客户端

为什么无法将对象转换为泛型类型

如何在VS代码中为C#DotNet配置.json选项以调试内部终端的控制台应用程序

C#Null判断处理失败

VS 2022 for ASP.NET Core中缺少自定义项模板

.NET8->;并发词典总是比普通词典快...怎么回事?[包含基准结果和代码]

在C#ASP.NET内核中使用INT AS-1进行控制器场景的单元测试

如何对特定异常使用Polly重试机制?

C#使用相同内存的多个数组

为什么我可以在注册表编辑器中更改值,但不能在以管理员身份运行的C#表单应用程序中更改?

C#定时器回调对象上下文?

读取测试项目中的应用程序设置

在C#中删除多个不同名称的会话

缩写的MonthNames有问题

根据运行时值获取泛型类型的字典