我用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;
}
答案 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不同步,而您无法恢复,因为您的通信没有框架或错误检查。
有几种可能性:
唯一可行的方法是实现一个简单的协议,该协议可以确定框架命令以移动和验证数据,以确保收到的内容是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>