伺服臂问题

时间:2017-09-26 06:34:25

标签: c# visual-studio arduino servo

我用Arduino uno和一个Servo盾牌建造了一个机器人手臂。手臂由带有USB的C#visual studio控制。目前有6个伺服器连接到臂上,电源与5V,2A一起使用。我可以通过发送数据来控制手臂。问题是在发送少量数据后,伺服臂失去控制并随机移动。

* UPDATE 我使用5V,5A电源并将伺服数量减少到3.在少量数据发送到伺服后,机器人仍然行为异常/随机移动。(机器人行为不到几秒钟,然后回到我想要的位置。 ) (我有6个舵机,我每个试过3个舵机,我也遇到同样的问题。)

这是我的arduino代码

object

这是我的Visual Studio WINFORM代码

#include <Servo.h>  
Servo myservoA;  
Servo myservoB;
Servo myservoC;
Servo myservoD;
Servo myservoE;
Servo myservoF;
int i,pos,myspeed,myshow,COM0,MOVE=0;
int sea,seb,sec,sed,see,sef;
static int v=0;
byte Readbytes [10];
byte byte0, byte1,byte2,byte3,byte4,byte5,byte6,byte7;
byte newpos0, newpos1,newpos2,newpos3,newpos4,newpos5,newpos6,newpos7;
byte oldpos0, oldpos1,oldpos2,oldpos3,oldpos4,oldpos5,oldpos7,oldpos8;

String mycommand="";    /// Serial capture   #auto: automatic operation  
#com: computer serial port control  #stop: standstill
static int mycomflag=2; // #auto:2 automatic operation  , #com: 1  computer 
serial port control    #stop:0  standstill 

void setup() 
{ 
  pinMode(13,INPUT);
  pinMode(12,INPUT);  
  Serial.begin(9600);
  myshow=0;
  mycomflag=2;         // the  ARM default  state: 2 automatic operation
                   //                          1 pc
  myservoA.attach(3);     
  myservoB.attach(5);    
  myservoC.attach(6);  
  myservoD.attach(9);  
  myservoE.attach(10); 
  myservoF.attach(11); 

  myservoA.write(10);   //0A Control wrist rotation
  myservoB.write(20);   //14
  myservoC.write(10);   //0A
  myservoD.write(20);   //3C
  myservoE.write(30);  //64
 myservoF.write(5);    //4B Control waist

oldpos0=10;oldpos1=20;oldpos2=10;oldpos3=20;oldpos4=30;oldpos5=5;


newpos0=10;newpos1=20;newpos2=10;newpos3=20;newpos4=30;newpos5=5;


}

void loop() 
{ 
   if (Serial.available()>0) 
  {
  i=0;int bufferLimit=9;
  while(Serial.available()>0 && i < bufferLimit) 
  {      
    Readbytes[i]= Serial.read();
    i++;       
  }
    newpos0=(Readbytes[0]);
    newpos1=(Readbytes[1]);
    newpos2=(Readbytes[2]);
    newpos3=(Readbytes[3]);
    newpos4=(Readbytes[4]);
    newpos5=(Readbytes[5]);
    newpos6=(Readbytes[6]);
    newpos7=(Readbytes[7]);
  COM0=1;
  }


  delay(100);//Required for all bytes to be read at SP2 before sending
        //at SP2 again
  if (COM0==1&&(newpos5==2||newpos5==24||newpos5==80))
  {
  //Serial.write(Readbytes,i);//To Freezer
  //Serial.write(Readbytes[0]);
  //Serial.write(Readbytes[1]);
  Serial.write(newpos0);
  Serial.write(newpos1);
  Serial.write(newpos2);
  Serial.write(newpos3);
  Serial.write(newpos4);
  Serial.write(newpos5);
  Serial.write(newpos6);
  Serial.write(newpos7);

  COM0=0;
  MOVE=1;
  }

  if(MOVE==1)
  {
  myspeed=800;
  for(pos = 0; pos <=myspeed; pos += 1)  
  {                                
   myservoA.write(int(map(pos,1,myspeed,oldpos0,newpos0))); 
   myservoB.write(int(map(pos,1,myspeed,oldpos1,newpos1))); 
   myservoC.write(int(map(pos,1,myspeed,oldpos2,newpos2))); 
   myservoD.write(int(map(pos,1,myspeed,oldpos3,newpos3))); 
   myservoE.write(int(map(pos,1,myspeed,oldpos4,newpos4))); 
   myservoF.write(int(map(pos,1,myspeed,oldpos5,newpos5)));
   delay(1);                       
  }
  MOVE=0;
  oldpos0=newpos0;
  oldpos1=newpos1;
  oldpos2=newpos2;
  oldpos3=newpos3;
  oldpos4=newpos4;
  oldpos5=newpos5;
 }

2 个答案:

答案 0 :(得分:1)

问题不在于您的代码,而在于您的电源......您正在为您的伺服系统吸取太多电流。无论是升级电源还是减少伺服电机数量,在2A,3 x 9g伺服电机都会推动它,我会给每个伺服电机750mA以保持安全。

答案 1 :(得分:1)

这不是C#问题: - )

但是,您发布的代码中有一些区域可以引起注意:

 i=0;
 while(Serial.available()>0) 
    {      
        Readbytes[i]= Serial.read();
        i++;       
    }

不是一个好主意 - 你需要限制我,以便连续进入的垃圾流不会消耗内存。这看起来有点像C,所以它会像

 i=0;
 while(Serial.available()>0 && i < bufferLimit) 
    {      
        Readbytes[i]= Serial.read();
        i++;       
    }

其中bufferLimit是一个以某种方式设置为ReadBytes长度的值。

此外,您需要一些方法来构建您的通信,以便您知道自己的位置。假设接下来的8个字节是正确的,并将它们插入到您的伺服系统中是一个灾难的处方。您可以实现一个简单的协议,该协议具有明确的引入字符,数据字节和某种校验和或CRC。如果您不确定如何操作,请随时发表评论,我会提出建议。在此期间,请将发送数据的代码发布到您发布的代码中,因为这可能很容易成为罪魁祸首。

编辑:

但是从Aydin Adn的评论开始,因为它是导致问题的第一竞争者。我在这个答案中的建议可以让你在将来免于悲伤。

编辑9月30日:

查看您的C#代码,我越来越认为某些内容会干扰您的数据流并使PC与Arduino不同步,而您无法恢复,因为您的通信没有框架或错误检查。

有几种可能性:

  1. 您的串口适配器;我看到你正在使用COM6,这指向某种USB适配器。如果您正在使用廉价且开朗的适配器,则可能是它正在发明数据 - 我在工作时已经开始使用它,唯一的方法是仅使用使用FTDI芯片组的USB-&gt;串行适配器;来自中国的任何便宜的东西都可以适应各种各样的滑稽动作,包括在几个小时内完全正常工作,然后突然重复当天早些时候的整个数据块。问题在于驱动程序而不是硬件,其中一些可能非常差。
  2. 您的数据线索/ Arduino板本身;因为你有一个厚实的电源和一些伺服电流吸收电流,完全有可能在通信线路中产生噪声,这被Arduino解释为位于其接收缓冲区中的数据,直到你再发送一些并处理它,此时您发送的字节不会进入您想要的伺服。
  3. 你在某些方面超越/比赛;我注意到Thread.Sleep()和串行丢弃,显然是为了尝试和构建框架。这种事情从来没有帮助,并且可以使一切都非常依赖于事件的确切时间,而你需要它更具确定性和时间独立性。
  4. 唯一可行的方法是实现一个简单的协议,该协议可以确定框架命令以移动和验证数据,以确保收到的内容是PC发送的内容。您只能以9600波特率运行,每个字节大约1mS,因此将命令长度从8个裸字节中提升,仍会使命令在20mS以下。我建议使用Intel十六进制格式的变体,它都是ASCII格式,你可以使用类似的东西:

    :{SZ} {厘米} {数据} {CHK}

    :是一个冒号字符,从一个命令到下一个命令是唯一的;得到一个冒号,你知道接下来会发生什么。从那时起,一切都是成对的十六进制字符0-9 / A-F,它们编码了字节。

    {sz}是{data}中的字节数(这是可选的,但如果扩展命令结构,则可以提供一些灵活性)

    {cm}是一个命令字节(您可以将其拆分为一些位以允许简单的重试检测)

    {data}是&#34; sz&#34;编码的数据字节(可能为零但移动命令为8)

    {chk}是:和校验和之间所有原始字节值的否定和

    解码这个很简单,如果你把解码后的字节从sz添加到chk并获得除零以外的任何东西,你就可以扔掉所有的东西,而不是处理它,因为出了什么问题。同样,一旦你收到冒号,只能有0-9 / A-Z,其他任何东西,你可以忽略它,让PC决定它将采取什么行动。

    该方案允许状态命令&#34; 000000&#34;由PC发送以获得当前状态和移动命令类似于&#34;:0801A00A1E3C2891CA70&#34;这将是来自Do4()的值作为示例     &#34; M4bytesToSend =新字节[8] {160,10,30,60,40,24,0x91,0xCA};&#34; 假设01是移动命令。

    一旦Arduino解码了上面的移动命令,它就可以返回它,并设置一个忙位以表明它已经接收到并且即将进行移动,比如&#34;:0861A00A1E3C2891CAD2&#34;然后当它完成并准备好接下来的命令时,它可以发送&#34;:0841A00A1E3C2891CAB2&#34;。在这两种情况下,PC发送的0x01命令都设置了额外的位,这样它自己数据的环回就不会欺骗PC。使用命令的最高位将允许检测重试;如果PC连续两次发送0x01,则Arduino不会执行第二次,但只会发送&#34;:0841A00A1E3C2891CAB2&#34;响应表明它已执行该命令。 PC必须使用0x81来接受一个新的命令,这样PC就可以很高兴地重新发送一个命令,如果它没有得到响应,安全知道如果Arduino没有得到它将被执行。 t第一次得到它,或得到一个响应,告诉它命令已经完成。 PC当然可以发送:000000并返回最后一个响应,如果它不是简单地重试该命令。

    我意识到,当你想做的只是发送六个字节来控制一个手臂时,这看起来很长,但是这种性质的通信本质上很脆弱,因此让它可靠运行的唯一方法就是实现一些协议。

    我已经研究过Arduino方法,并且如果你想尝试将它破解成一个正常工作的程序(我无法编译它,所以它是最好的猜测)。 p>