一个多月没有冒头写点东西了 因为一直在忙着毕业前的大项目 这一个月啃了安卓 初识了Python图像处理 最大的重头戏还是这个魔方机器人 现在正好闲下来了 把这个机器人项目中的一些东西做一下总结
先上一个完工图
整个机器人分为两大功能区
上位机:树莓派作为上位机,从四个摄像头捕捉整个魔方六面的情况,按照算法将每一面的颜色块填充到Kociemba中即可到到对应的魔方解法,解法作为输出给到Ardunio中
下位机:Ardunio作为下位机 ,接收从树莓派中传过来的解法步骤 控制电机进行相应的解魔方步骤
下位机主要进行的是接收树莓派发送来的串口信息和电机驱动
Ardunio中自带步进电机控制相关的库AccelStepper.h
这一部分的代码逻辑流程图如下:
主要包括三个主要的function:Void serialEvent()、void checkStringCase(String str[])、void checkEachCase()
Void serialEvent()
每次树莓派发送数据时,它都会将数据传递给这个函数,然后它会检查是否有数据进来。如果是,则通过循环将传入的字符串读入comdata。
由于我们需要一步一步地执行Raspberry传递的步骤,并一步一步地执行旋转,所以我们需要将传递的字符串转换为字符串数组(字符串readFromGPIO[])
从串口中读取字符串并将字符串切割成字符串数组:
String readFromGPIO[40];
//read string form GIOP
while (Serial.available() > 0)
{
comdata += char(Serial.read());
delay(2);
}
//change string into string array
if (comdata.length() > 0)
{
int pos = 0;
for(int i=0;i<comdata.length();i++)
{
if(comdata[i] != ',')//','as the separator
{
readFromGPIO[pos] += comdata[i];
Serial.println(readFromGPIO[pos] );
}
else
{
pos++;
}
}
void checkStringCase(String str[])
在将字符串分割成字符串数组之后,字符串数组中的每一项都通过checkCase()函数通过一个循环传递
void checkEachCase()
对传入的每个字符串执行相应的旋转函数,如果字符串是“F”而非顺时针旋转90°,如果字符串是“F”而非逆时针旋转90°,以此类推
本来的想法是通过GPIO引脚进行通信,毕竟只需要树莓派向Ardunio发送数据,只需要一个引脚就够了,但是后来看了下树莓派的GPIO输出是3.3V,而Ardunio接收需要5V,所以才选择了USB串口通信
在树莓派终端输入ls /dev/tty*,查看两个连接端口的名称。检查是否有任何ttyACM0文件(注意,这仅在两个硬件usb连接时可用。如果两者没有连接,就没有)
最新的系统一般是自动生成的。看到ttyACM0意味着两者可以通信。接下来,让我们测试代码。
树莓派端的代码:
#import serial #import serial module
ser = serial.Serial('/dev/ttyACM0', 9600,timeout=1); #open named port at 9600,1s timeout
#try and except structure are exception handler
try:
while 1:
ser.write('s'); #write a string to port
response = ser.readall(); #read a string from port
print response;
except:
ser.close( );
Ardunio端的代码:
void setup()
{
Serial.begin(9600); // 9600 bps
}
void loop()
{
if (Serial. available()) {
if('s' == Serial.read())
Serial.println("Hello Raspberry,I am Arduino.");
}
}
上面的Arduino代码只是示例的一部分,我们在工程文件中编写了使用USB连接树莓派-3的代码
有关Ardunio和树莓派通信的内容可以看这一篇博客:树莓派与arduino通信
能完整拍下一个正方形6面的最小摄像头数要求是2个
在我们的项目中因为台架遮挡的原因 一共用了四个摄像头 然后对四个摄像头获取到的颜色块再进行拼接 如下图所示:
解魔方的算法用的是Kociemba算法 github上直接有算法的源码以及 使用方法
传送门:kociemba算法
kociemba算法在主要的思想就是检测每一面的每一个小块颜色并按照下边的样式将魔方6面展开
展开后的六面颜色信息可以成为一个数组
如下 这是魔方还原时候颜色的状态 可以看到在第二行的数组其实就代表了 下面展开后六面颜色情况的一个数组
整个树莓派的代码放不上来 有需要的可以私信找我要喔~
就简单说说逻辑:
1.完整的代码在名为“Cube_project”的包下。
2.其中包含一个main.py文件,帮助执行从“Kociemba”获得的解决方案的完整颜色检测和传输。
3.Main函数从调用Camera_1_data.py函数开始:
,它获取从相机捕获的图像的X和Y坐标。
,然后从common.py中获取颜色边界。
,并根据给定的坐标检测颜色。
,并返回颜色,将它们放置在检测到的脸的例子,如顶部,左边,右边等。
4.按照Kociemba提到的格式追加完整数据“uuuuuuurrrrrrrfffffffffddddddddlllllllbbbbbbbbb”。
5.上面的函数返回两个值,其中一个返回一个标志(true或false),它检查所有的面是否只有9种颜色,其他的值。
6.cube_rep.py显示当前检测到的颜色如下所示(魔方打乱了):
7.如果标志为真,那么附加的数据将被传递给cube_algorithm.py中的Kociemba算法。
8.而得到的解以下面的格式放置为字符串“R ', F, U, U '”。
9.然后这个字符串被传递给Arduino并从Arduino得到一个反馈,不管它是否收到了反馈。
10.如果标志为false,则显示一条错误消息“发现了一些问题,您需要调试这个问题”。
11.如果摄像机连接在正确的位置,只需要运行main.py文件。
具体openCV如何检测魔方上的颜色等后面写图像处理的总结时候再详细写写
不足点总结:
1,颜色识别的时候受环境光的影响很大 太暗和太亮都会影响识别 有没有大佬分享一下怎么提升的
2,电机的控制没有闭环 使用encoder会保证电机转动更加准确