伺服臂问题
Servo Arm Issue
我用 Arduino uno 和一个伺服扩展板构建了一个机械臂。手臂由 C# visual studio 和 USB 控制。目前有 6 个舵机连接到手臂上,电源使用 5V,2A。我可以通过向它发送数据来控制它。问题是在发送少量数据后,伺服臂失去控制并随机移动。
*更新
我使用 5V,5A 电源并将伺服器的数量减少到 3 个。在向伺服器发送少量数据后,机器人仍然 misbehave/randomly 移动。(机器人行为异常几秒钟,然后回到我想要的位置本身。)
(我有6个舵机,我每个都试了3个舵机,我有同样的问题。)
这是我的arduino代码
#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;
}
这是我的 Visual Studio WINFORM 代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RoboAnimate
{
public partial class Form1 : Form
{
string RxString;
string c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15,
c16, c17;
string fourbytesHexStr;
UInt32 fourbytesHex = 0;
byte A, B, C, D, E, F,timer1val;
bool do1=false, do2 = false, do3 = false, do4 = false, do5 = false, do6
= false, sequence1 = true;
private void timer1_Tick(object sender, EventArgs e)
{
timer1val++;
textBox4.Text = timer1val.ToString();
if (timer1val == 2) Do1();
if (timer1val == 5) Do2();
if (timer1val == 7) Do3();
if (timer1val == 9) Do4();
if (timer1val == 11) Do5();
if (timer1val == 13) Do6();
if (timer1val == 15) Do7();
if (timer1val == 17) Do8();
if (timer1val == 19) Do7();
if (timer1val == 21) Do6();
if (timer1val == 23) Do5();
if (timer1val == 25) Do4();
if (timer1val == 27) Do3();
if (timer1val == 29) Do2();
if (timer1val == 32)
{
Do1();
sequence1 = false;
timer1.Enabled = false;
timer1val = 0;
}
}
byte whichdo;
private void Form1_Load(object sender, EventArgs e)
{
}
private void Pos2_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 30, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos3_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 10, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos4_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos5_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos6_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 90, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos7_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 90, 100, 60, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos8_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 95, 90, 130, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void ScrollA_Scroll(object sender, ScrollEventArgs e)
{
ServoA.Text = ScrollA.Value.ToString();
}
private void ScrollB_Scroll(object sender, ScrollEventArgs e)
{
ServoB.Text = ScrollB.Value.ToString();
}
private void ScrollC_Scroll(object sender, ScrollEventArgs e)
{
ServoC.Text = ScrollC.Value.ToString();
}
private void ScrollD_Scroll(object sender, ScrollEventArgs e)
{
ServoD.Text = ScrollD.Value.ToString();
}
private void ScrollE_Scroll(object sender, ScrollEventArgs e)
{
ServoE.Text = ScrollE.Value.ToString();
}
private void ScrollF_Scroll(object sender, ScrollEventArgs e)
{
ServoF.Text = ScrollF.Value.ToString();
}
private void Send_Click(object sender, EventArgs e)
{
A = Convert.ToByte(ServoA.Text);
B = Convert.ToByte(ServoB.Text);
C = Convert.ToByte(ServoC.Text);
D = Convert.ToByte(ServoD.Text);
E = Convert.ToByte(ServoE.Text);
F = Convert.ToByte(ServoF.Text);
// A B C D E
//byte[] M1bytesToSend = new byte[8] { 0x4A, 0x14, 0x0A, 0x3C, 0x64,
0x4B, 0x91, 0xCA };
byte[] M1bytesToSend = new byte[8] { A, B, C, D, E, F, 0x91, 0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void serialPort1_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
int i;
int bytes = serialPort1.BytesToRead;
byte[] buffer = new byte[bytes];
string[] hex = new string[bytes];
serialPort1.Read(buffer, 0, bytes);
RxString = ByteArrayToHexString(buffer);
for (i = 0; i < bytes; ++i)
{
hex[i] = buffer[i].ToString("X");
}
textBox2.Text = RxString;
textBox3.Text = bytes.ToString();
if (bytes == 9)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
c8 = (hex[7]).PadLeft(2, '0');
c9 = (hex[8]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7, c8,
c9);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
if (bytes == 8)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
c8 = (hex[7]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7, c8);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
if (bytes == 7)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
}
private string ByteArrayToHexString(byte[] buffer)
{
StringBuilder sb = new StringBuilder(buffer.Length * 3);
foreach (byte b in buffer)
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, '
'));
return sb.ToString().ToUpper();
}
private void Pos1_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 115, 95, 80, 21, 31, 2, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Open_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM6";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.Open();
if (serialPort1.IsOpen) PortStatus.Text = "PORT Opened...Click to
Start DAQ";
Close.Enabled = true;
Open.Enabled = false;
}
public Form1()
{
InitializeComponent();
whichdo = 100;
}
private void Animate1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void Do1()
{
byte[] M1bytesToSend = new byte[8] { 115, 95, 80, 21, 31, 2, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Do2()
{
byte[] M2bytesToSend = new byte[8] { 160, 30, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M2bytesToSend, 0, 8);
}
private void Do3()
{
byte[] M3bytesToSend = new byte[8] { 160, 10, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M3bytesToSend, 0, 8);
}
private void Do4()
{
byte[] M4bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M4bytesToSend, 0, 8);
}
private void Do5()
{
byte[] M5bytesToSend = new byte[8] { 160, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M5bytesToSend, 0, 8);
}
private void Do6()
{
byte[] M6bytesToSend = new byte[8] { 90, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M6bytesToSend, 0, 8);
}
private void Do7()
{
byte[] M7bytesToSend = new byte[8] { 90, 100, 60, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M7bytesToSend, 0, 8);
}
private void Do8()
{
byte[] M8bytesToSend = new byte[8] { 95, 90, 130, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M8bytesToSend, 0, 8);
}
}
}
问题不在于您的代码,而在于您的电源...您为伺服系统消耗了太多电流。升级电源或减少舵机数量,在 2A 上,3 x 9g 舵机会推动它 imo,我会给每个舵机 750mA 以保持安全。
这不是 C# 问题:-)
但是,您的 posted 代码中有几个地方需要注意:
i=0;
while(Serial.available()>0)
{
Readbytes[i]= Serial.read();
i++;
}
这不是个好主意 - 您需要限制 i 以便连续进入的垃圾流不会清除内存。这看起来有点像 C,所以它会像
i=0;
while(Serial.available()>0 && i < bufferLimit)
{
Readbytes[i]= Serial.read();
i++;
}
其中 bufferLimit 是以某种方式设置为 ReadBytes 长度的值。
此外,您需要某种方式来构建您的通讯,以便您知道自己的位置。仅仅假设接下来的 8 个字节是正确的并将它们插入您的伺服系统是灾难的根源。您可以实现一个简单的协议,该协议具有明确的导入字符、数据字节和某种校验和或 CRC。如果您不确定如何操作,请随时 post 发表评论,我会提出建议。同时,请 post 无论是什么代码正在向您 post 编辑的代码发送数据,因为这很容易成为罪魁祸首。
编辑:
但是从 Aydin Adn 的评论开始,因为它是导致问题的第一竞争者。我在这个答案中的建议可以让你在未来免去悲伤。
编辑 9 月 30 日:
查看您的 C# 代码,我越来越认为某些东西正在干扰您的数据流并使 PC 与 Arduino 不同步,您无法从中恢复,因为您的通讯没有框架或错误检查。
有两种可能性:
- 你的串行适配器;我看到您正在使用 COM6,这指向某种 USB 适配器。如果您使用的是便宜且令人愉快的适配器,则它可能正在发明数据-我在工作中遇到过这种情况,唯一的解决方法是仅使用 USB-> 使用 FTDI 芯片组的串行适配器;来自中国的任何廉价产品都可能出现各种滑稽动作,包括在几个小时内完全正常工作,然后突然重复当天早些时候的一整块数据。问题出在驱动程序而不是硬件,其中一些可能很差。
- 您的数据lead/the Arduino 开发板本身;因为你有一个笨重的电源和一些伺服系统汲取电流,所以通信线路中完全有可能产生噪音,而这被 Arduino 解释为位于其接收缓冲区中的数据,直到你发送更多并处理它,此时您发送的字节不会发送到您想要的伺服器。
- 你在某个时候是 overrunning/racing;我注意到 Thread.Sleep() 和连续丢弃,它们显然是为了尝试和构建事物。这种事情永远不会有帮助,并且会使一切都非常依赖于事件的确切时间,而你需要它更具确定性和时间独立性。
唯一可以确定的方法是实施一个简单的协议,该协议绝对可以构建一个命令来移动和验证数据,以确保收到的是 PC 发送的。您只有 运行 9600 波特,每字节大约 1 毫秒,因此将命令长度从 8 个裸字节增加仍然会在 20 毫秒以下引入命令。我建议使用一种全部采用 ASCII 的 Intel Hex 格式的变体,您可以使用类似的东西:
:{sz}{cm}{data}{chk}
:是一个冒号字符,从一个命令到下一个命令是唯一的;得到一个冒号,你就知道接下来会发生什么。从那时起,一切都是十六进制字符对 0-9/A-F 组成编码字节。
{sz} 是 {data} 中的字节数(这是可选的,但如果您扩展命令结构,它会提供一些灵活性)
{cm} 是一个命令字节(你可以将其拆分为一些位以允许简单的重试检测)
{data} 是 "sz" 编码的数据字节(可以为零,但对于移动命令为 8)
{chk} 是 : 和校验和
之间所有原始字节值的负和
解码这很简单,如果您将解码后的字节从 sz 添加到 chk 并得到除零之外的任何内容,您可以丢弃所有内容而不处理它,因为出了点问题。同样,一旦你收到冒号,就只能是 0-9/A-Z,其他任何东西你都可以忽略它,让 PC 决定它要做什么。
此方案将允许 PC 发送状态命令“:000000”以获取当前状态,并允许发送类似“:0801A00A1E3C2891CA70”的移动命令,例如来自 Do4() 的值
"M4bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91, 0xCA };"
假设 01 是移动命令。
一旦 Arduino 解码了上面的移动命令,它就可以 return 它设置了一个忙位来指示它已经收到它并且即将进行移动,说“:0861A00A1E3C2891CAD2”然后当它已经完成并准备好发送下一个命令“:0841A00A1E3C2891CAB2”。在这两种情况下,PC 发送的 0x01 命令都设置了额外的位,这样它自己的数据环回就不会欺骗 PC。使用命令的最高位将允许检测到重试;如果 PC 连续两次发送 0x01,Arduino 将不会执行第二次,而只会发送“:0841A00A1E3C2891CAB2”响应以表明它已执行该命令。 PC 必须使用 0x81 来接受新命令,这样 PC 可以愉快地重新发送命令,如果它没有得到响应,安全地知道如果 Arduino 没有得到它,它将被执行第一次,或者得到一个响应,告诉它命令已经完成。如果 PC 不简单地重试命令,它当然可以发送 :000000 并取回最后的响应。
我意识到当你只想发送六个字节来控制一个手臂时,这似乎很啰嗦,但这种性质的通信本质上是脆弱的,所以让它可靠运行的唯一方法是实施某种协议。
我已经研究了 Arduino 方法并且有代码可以做到这一点,如果你想尝试将它破解成一个工作程序(我没有办法编译它所以这是一个最好的猜测)。
我用 Arduino uno 和一个伺服扩展板构建了一个机械臂。手臂由 C# visual studio 和 USB 控制。目前有 6 个舵机连接到手臂上,电源使用 5V,2A。我可以通过向它发送数据来控制它。问题是在发送少量数据后,伺服臂失去控制并随机移动。
*更新 我使用 5V,5A 电源并将伺服器的数量减少到 3 个。在向伺服器发送少量数据后,机器人仍然 misbehave/randomly 移动。(机器人行为异常几秒钟,然后回到我想要的位置本身。) (我有6个舵机,我每个都试了3个舵机,我有同样的问题。)
这是我的arduino代码
#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;
}
这是我的 Visual Studio WINFORM 代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RoboAnimate
{
public partial class Form1 : Form
{
string RxString;
string c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15,
c16, c17;
string fourbytesHexStr;
UInt32 fourbytesHex = 0;
byte A, B, C, D, E, F,timer1val;
bool do1=false, do2 = false, do3 = false, do4 = false, do5 = false, do6
= false, sequence1 = true;
private void timer1_Tick(object sender, EventArgs e)
{
timer1val++;
textBox4.Text = timer1val.ToString();
if (timer1val == 2) Do1();
if (timer1val == 5) Do2();
if (timer1val == 7) Do3();
if (timer1val == 9) Do4();
if (timer1val == 11) Do5();
if (timer1val == 13) Do6();
if (timer1val == 15) Do7();
if (timer1val == 17) Do8();
if (timer1val == 19) Do7();
if (timer1val == 21) Do6();
if (timer1val == 23) Do5();
if (timer1val == 25) Do4();
if (timer1val == 27) Do3();
if (timer1val == 29) Do2();
if (timer1val == 32)
{
Do1();
sequence1 = false;
timer1.Enabled = false;
timer1val = 0;
}
}
byte whichdo;
private void Form1_Load(object sender, EventArgs e)
{
}
private void Pos2_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 30, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos3_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 10, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos4_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos5_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 160, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos6_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 90, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos7_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 90, 100, 60, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Pos8_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 95, 90, 130, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void ScrollA_Scroll(object sender, ScrollEventArgs e)
{
ServoA.Text = ScrollA.Value.ToString();
}
private void ScrollB_Scroll(object sender, ScrollEventArgs e)
{
ServoB.Text = ScrollB.Value.ToString();
}
private void ScrollC_Scroll(object sender, ScrollEventArgs e)
{
ServoC.Text = ScrollC.Value.ToString();
}
private void ScrollD_Scroll(object sender, ScrollEventArgs e)
{
ServoD.Text = ScrollD.Value.ToString();
}
private void ScrollE_Scroll(object sender, ScrollEventArgs e)
{
ServoE.Text = ScrollE.Value.ToString();
}
private void ScrollF_Scroll(object sender, ScrollEventArgs e)
{
ServoF.Text = ScrollF.Value.ToString();
}
private void Send_Click(object sender, EventArgs e)
{
A = Convert.ToByte(ServoA.Text);
B = Convert.ToByte(ServoB.Text);
C = Convert.ToByte(ServoC.Text);
D = Convert.ToByte(ServoD.Text);
E = Convert.ToByte(ServoE.Text);
F = Convert.ToByte(ServoF.Text);
// A B C D E
//byte[] M1bytesToSend = new byte[8] { 0x4A, 0x14, 0x0A, 0x3C, 0x64,
0x4B, 0x91, 0xCA };
byte[] M1bytesToSend = new byte[8] { A, B, C, D, E, F, 0x91, 0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void serialPort1_DataReceived(object sender,
SerialDataReceivedEventArgs e)
{
Thread.Sleep(50);
int i;
int bytes = serialPort1.BytesToRead;
byte[] buffer = new byte[bytes];
string[] hex = new string[bytes];
serialPort1.Read(buffer, 0, bytes);
RxString = ByteArrayToHexString(buffer);
for (i = 0; i < bytes; ++i)
{
hex[i] = buffer[i].ToString("X");
}
textBox2.Text = RxString;
textBox3.Text = bytes.ToString();
if (bytes == 9)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
c8 = (hex[7]).PadLeft(2, '0');
c9 = (hex[8]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7, c8,
c9);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
if (bytes == 8)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
c8 = (hex[7]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7, c8);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
if (bytes == 7)
{
c1 = (hex[0]).PadLeft(2, '0');
c2 = (hex[1]).PadLeft(2, '0');
c3 = (hex[2]).PadLeft(2, '0');
c4 = (hex[3]).PadLeft(2, '0');
c5 = (hex[4]).PadLeft(2, '0');
c6 = (hex[5]).PadLeft(2, '0');
c7 = (hex[6]).PadLeft(2, '0');
fourbytesHexStr = string.Concat(c1, c2, c3, c4, c5, c6, c7);
fourbytesHexStr = fourbytesHexStr.PadRight(8, '0');
textBox1.Text = fourbytesHexStr;
textBox3.Text = bytes.ToString();
serialPort1.DiscardInBuffer();
}
}
private string ByteArrayToHexString(byte[] buffer)
{
StringBuilder sb = new StringBuilder(buffer.Length * 3);
foreach (byte b in buffer)
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, '
'));
return sb.ToString().ToUpper();
}
private void Pos1_Click(object sender, EventArgs e)
{
// Gripper
// A B C D E F
byte[] M1bytesToSend = new byte[8] { 115, 95, 80, 21, 31, 2, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Open_Click(object sender, EventArgs e)
{
serialPort1.PortName = "COM6";
serialPort1.BaudRate = 9600;
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.Open();
if (serialPort1.IsOpen) PortStatus.Text = "PORT Opened...Click to
Start DAQ";
Close.Enabled = true;
Open.Enabled = false;
}
public Form1()
{
InitializeComponent();
whichdo = 100;
}
private void Animate1_Click(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void Do1()
{
byte[] M1bytesToSend = new byte[8] { 115, 95, 80, 21, 31, 2, 0x91,
0xCA };
serialPort1.Write(M1bytesToSend, 0, 8);
}
private void Do2()
{
byte[] M2bytesToSend = new byte[8] { 160, 30, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M2bytesToSend, 0, 8);
}
private void Do3()
{
byte[] M3bytesToSend = new byte[8] { 160, 10, 10, 20, 30, 24, 0x91,
0xCA };
serialPort1.Write(M3bytesToSend, 0, 8);
}
private void Do4()
{
byte[] M4bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M4bytesToSend, 0, 8);
}
private void Do5()
{
byte[] M5bytesToSend = new byte[8] { 160, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M5bytesToSend, 0, 8);
}
private void Do6()
{
byte[] M6bytesToSend = new byte[8] { 90, 60, 30, 60, 40, 24, 0x91,
0xCA };
serialPort1.Write(M6bytesToSend, 0, 8);
}
private void Do7()
{
byte[] M7bytesToSend = new byte[8] { 90, 100, 60, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M7bytesToSend, 0, 8);
}
private void Do8()
{
byte[] M8bytesToSend = new byte[8] { 95, 90, 130, 100, 40, 80, 0x91,
0xCA };
serialPort1.Write(M8bytesToSend, 0, 8);
}
}
}
问题不在于您的代码,而在于您的电源...您为伺服系统消耗了太多电流。升级电源或减少舵机数量,在 2A 上,3 x 9g 舵机会推动它 imo,我会给每个舵机 750mA 以保持安全。
这不是 C# 问题:-)
但是,您的 posted 代码中有几个地方需要注意:
i=0;
while(Serial.available()>0)
{
Readbytes[i]= Serial.read();
i++;
}
这不是个好主意 - 您需要限制 i 以便连续进入的垃圾流不会清除内存。这看起来有点像 C,所以它会像
i=0;
while(Serial.available()>0 && i < bufferLimit)
{
Readbytes[i]= Serial.read();
i++;
}
其中 bufferLimit 是以某种方式设置为 ReadBytes 长度的值。
此外,您需要某种方式来构建您的通讯,以便您知道自己的位置。仅仅假设接下来的 8 个字节是正确的并将它们插入您的伺服系统是灾难的根源。您可以实现一个简单的协议,该协议具有明确的导入字符、数据字节和某种校验和或 CRC。如果您不确定如何操作,请随时 post 发表评论,我会提出建议。同时,请 post 无论是什么代码正在向您 post 编辑的代码发送数据,因为这很容易成为罪魁祸首。
编辑:
但是从 Aydin Adn 的评论开始,因为它是导致问题的第一竞争者。我在这个答案中的建议可以让你在未来免去悲伤。
编辑 9 月 30 日:
查看您的 C# 代码,我越来越认为某些东西正在干扰您的数据流并使 PC 与 Arduino 不同步,您无法从中恢复,因为您的通讯没有框架或错误检查。
有两种可能性:
- 你的串行适配器;我看到您正在使用 COM6,这指向某种 USB 适配器。如果您使用的是便宜且令人愉快的适配器,则它可能正在发明数据-我在工作中遇到过这种情况,唯一的解决方法是仅使用 USB-> 使用 FTDI 芯片组的串行适配器;来自中国的任何廉价产品都可能出现各种滑稽动作,包括在几个小时内完全正常工作,然后突然重复当天早些时候的一整块数据。问题出在驱动程序而不是硬件,其中一些可能很差。
- 您的数据lead/the Arduino 开发板本身;因为你有一个笨重的电源和一些伺服系统汲取电流,所以通信线路中完全有可能产生噪音,而这被 Arduino 解释为位于其接收缓冲区中的数据,直到你发送更多并处理它,此时您发送的字节不会发送到您想要的伺服器。
- 你在某个时候是 overrunning/racing;我注意到 Thread.Sleep() 和连续丢弃,它们显然是为了尝试和构建事物。这种事情永远不会有帮助,并且会使一切都非常依赖于事件的确切时间,而你需要它更具确定性和时间独立性。
唯一可以确定的方法是实施一个简单的协议,该协议绝对可以构建一个命令来移动和验证数据,以确保收到的是 PC 发送的。您只有 运行 9600 波特,每字节大约 1 毫秒,因此将命令长度从 8 个裸字节增加仍然会在 20 毫秒以下引入命令。我建议使用一种全部采用 ASCII 的 Intel Hex 格式的变体,您可以使用类似的东西:
:{sz}{cm}{data}{chk}
:是一个冒号字符,从一个命令到下一个命令是唯一的;得到一个冒号,你就知道接下来会发生什么。从那时起,一切都是十六进制字符对 0-9/A-F 组成编码字节。
{sz} 是 {data} 中的字节数(这是可选的,但如果您扩展命令结构,它会提供一些灵活性)
{cm} 是一个命令字节(你可以将其拆分为一些位以允许简单的重试检测)
{data} 是 "sz" 编码的数据字节(可以为零,但对于移动命令为 8)
{chk} 是 : 和校验和
之间所有原始字节值的负和解码这很简单,如果您将解码后的字节从 sz 添加到 chk 并得到除零之外的任何内容,您可以丢弃所有内容而不处理它,因为出了点问题。同样,一旦你收到冒号,就只能是 0-9/A-Z,其他任何东西你都可以忽略它,让 PC 决定它要做什么。
此方案将允许 PC 发送状态命令“:000000”以获取当前状态,并允许发送类似“:0801A00A1E3C2891CA70”的移动命令,例如来自 Do4() 的值 "M4bytesToSend = new byte[8] { 160, 10, 30, 60, 40, 24, 0x91, 0xCA };" 假设 01 是移动命令。
一旦 Arduino 解码了上面的移动命令,它就可以 return 它设置了一个忙位来指示它已经收到它并且即将进行移动,说“:0861A00A1E3C2891CAD2”然后当它已经完成并准备好发送下一个命令“:0841A00A1E3C2891CAB2”。在这两种情况下,PC 发送的 0x01 命令都设置了额外的位,这样它自己的数据环回就不会欺骗 PC。使用命令的最高位将允许检测到重试;如果 PC 连续两次发送 0x01,Arduino 将不会执行第二次,而只会发送“:0841A00A1E3C2891CAB2”响应以表明它已执行该命令。 PC 必须使用 0x81 来接受新命令,这样 PC 可以愉快地重新发送命令,如果它没有得到响应,安全地知道如果 Arduino 没有得到它,它将被执行第一次,或者得到一个响应,告诉它命令已经完成。如果 PC 不简单地重试命令,它当然可以发送 :000000 并取回最后的响应。
我意识到当你只想发送六个字节来控制一个手臂时,这似乎很啰嗦,但这种性质的通信本质上是脆弱的,所以让它可靠运行的唯一方法是实施某种协议。
我已经研究了 Arduino 方法并且有代码可以做到这一点,如果你想尝试将它破解成一个工作程序(我没有办法编译它所以这是一个最好的猜测)。