魔方机器人[上]-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 19286|回复: 20

魔方机器人[上]

[复制链接]
发表于 2016-1-20 23:18 | 显示全部楼层 |阅读模式
为了达到完全自主还原魔方的目的,至少需要完成4个方面的工作:识别魔方状态;计算出魔方的还原步骤;将还原步骤发送到下位机指导其运行;下位机转动魔方将其还原。
具体实现起来的细节更加复杂一些。在接收到开始信号后机器首先分别展示魔方的6 个面,同时PC利用开源计算机视觉库OpenCV通过USB摄像头捕捉到魔方6个面的图像,再使用数字图像处理技术识别各个方块的颜色,以此建立魔方表面颜色的数字模型。将颜色模型转换为更适合运算的状态模型之后,参考手解三阶魔方CFOP还原法计算出魔方的还原步骤并转换成标准表示方法。然后PC机通过UART串口将结果发送到下位机。下位机则借用了数控设备的思想,先将结果翻译为基本动作指令组,再驱动4个机械手按照基本动作依次旋转魔方,逐步将魔方复原。

不用多介绍吧,很多小伙伴应该见过。先来简单的部分,arduino控制的下位机。
好吧言归正传,现在开始diy。
先来张硬件连线图:
154807x2mimjjo22igf8fa.png
一共用了8个舵机,还是看图吧
155420ixiisy4h77mzgibx.png
再详细点
155305ree3mkuedbmmdeeu.png
这个没什么新意,而且,本人手工拙劣,这是这个机器人里最烂的一部分。
今天先上总体设计和Arduino上的部分代码,其实还没有完全完成,所以还要和大家多多讨论


整个系统的结构是这样的,
160101rp3yyzkyypy0hzmn.jpg [size=0.83em]下载附件 [size=0.83em](196.46 KB)



我初步估计,仅凭arduino的性能要计算出魔方的解法还是有很大压力的,另外我没有串口摄像头,所以只能用usb摄像头,所以干脆就放到pc上吧。这个算法,不是我写的,我只是改了改输入输出接口,来源戳这里http://www.jaapsch.net/puzzles/cube3.htm
这个算法很优秀,平均步骤只有16步,我用PC计算时间没有超过1秒的,这部分以后再说,先弄arduino。
上arduino上的 代码
[mw_shl_code=bash,true]#include <Servo.h>

#define LED               13
#define BUTTON            12

const int WRISTP[4] = {169,173,173,171};
const int WRISTS[4] = {86,92,90,89};
const int WRISTN[4] = {5,5,5,5};

const int HANDH[4] = {60,50,47,60};
const int HANDR[4] = {120,120,120,120};

const int WAIT_TIME[4] = {100,450,800,1200};

static int State = 0;

Servo wrist[4];
Servo hand[4];

String command;
String answer;
static int ScaningFace = 0;

const String ScanCommand[6] = {"H0H2W0S1S3W1","P0N2W1","S0S2W1H1H3W0R0R2W0P1N3W1","P3N1W1","H0H2W0R1R3W0S1S3W1P2N0W1","P0N2W1W1"};
const String ReadyToStartCommand = "S0S2W1H0H1H2H3W1";

const String ReadyCommand = "";
const String StayCommand = "S0S1S2S3R0R1R2R3W1";
const String Test1 = "P0W1S0W1N0W1";
const String Test2 = "P1W1S1W1N1W1";
const String Test3 = "P2W1S2W1N2W1";
const String Test4 = "P3W1S3W1N3W1";
void setup()
{
  Serial.begin(9600);
  pinMode(LED,OUTPUT);
  pinMode(BUTTON,INPUT);
  digitalWrite(LED,0);

  for(int i=0;i<4;i++)
  {
    wrist.attach(i+4);
    hand.attach(i+8);
  }

  command = "";
  answer = "";
  Stay();
}

void loop()
{
  if(digitalRead(BUTTON) == LOW && State == 0)
  {
    Stay();
  }
  else if(digitalRead(BUTTON) == LOW && State == 1)
  {
    digitalWrite(LED,LOW);
    Ready();
  }
  else if(digitalRead(BUTTON) == LOW && State == 2)
  {
    digitalWrite(LED,HIGH);
    Serial.println('s');
    delay(2500);
    Scan();
  }

  GetCom();
  delay(50);
}

void GetCom()
{
  while(Serial.available())
  {
    int inChar = Serial.read();

    if(inChar != '\r' && inChar != '\n')
    {
      command += (char)inChar;
    }

    else if (inChar == '\r'||inChar=='\n')
    {
      Serial.println('>' + command);
      ExeCom();

    }
  }
}

void ExeCom(String com)
{
  command = com;
  ExeCom();
}

void ExeCom()
{
  if(command == "ready")
  {
    Ready();
  }
  else if(command == "scan")
  {
    Scan();
  }
  else if(command == "stay")
  {
    Stay();
  }
  else if(command == "t1")
  {
    BaseMove(Test1);
  }
  else if(command == "t2")
  {
    BaseMove(Test2);
  }
  else if(command == "t3")
  {
    BaseMove(Test3);
  }
  else if(command == "t4")
  {
    BaseMove(Test4);
  }
  else if(command[0] == '>')
  {
    DoMove();
  }
  else// if(command == "test")
  {
    Solve();
  }
//  else
//    Serial.println("wrong command!");
  command = "";
}

void BaseMove(String com)
{
  for(int i=0;i<com.length()-2;i+=2)
  {
    switch(com)
    {
      case 'S':
      {
        wrist[(int)(com[i+1]-'0')].write(WRISTS[(int)(com[i+1]-'0')]);
        break;
      }
      case 'P':
      {
        wrist[(int)(com[i+1]-'0')].write(WRISTP[(int)(com[i+1]-'0')]);
        break;
      }
      case 'N':
      {
        wrist[(int)(com[i+1]-'0')].write(WRISTN[(int)(com[i+1]-'0')]);
        break;
      }
      case 'H':
      {
        hand[(int)(com[i+1]-'0')].write(HANDH[(int)(com[i+1]-'0')]);
        break;
      }
      case 'R':
      {
        hand[(int)(com[i+1]-'0')].write(HANDR[(int)(com[i+1]-'0')]);
        break;
      }
      case 'W':
      {
        delay(WAIT_TIME[(int)(com[i+1]-'0')]);
        break;
      }
    }
  }
}

void Stay()
{
   State = 1;
   ScaningFace=0;
   BaseMove(StayCommand);
}

void Ready()
{
  State = 2;
  ScaningFace=0;
  BaseMove("R0R1R2R3W0N0P2S1S3W2");
  delay(800);
  wrist[1].write(WRISTP[1]-(WRISTP[1]-WRISTS[1])/3);
  wrist[3].write(WRISTN[3]-(WRISTN[3]-WRISTS[3])/3);
  delay(WAIT_TIME_WRIST);
}

void Test()
{
  BaseMove(command);
}

void Scan()
{
  State = 0;
  for(;ScaningFace<6;ScaningFace++)
  {
    BaseMove(ScanCommand[ScaningFace]);
    delay(WAIT_TIME[2]);
  }
}

void Hold(int handID)
{
  hand[handID].write(HANDH[handID]);
}
void Release(int handID)
{
  hand[handID].write(HANDR[handID]);
}

void Move(char face,char a)
{
  switch(face)
  {
    case 'U':
    {
      switch(a)
      {
        case '1':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1H0W0P0W1R0W0S1S3S0W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
        case '3':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1H0W0N0W1R0W0S1S3S0W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
        case '2':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1N0W1H0W0P0W1R0W0S1S3S0W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
      }
      break;
    }
    case 'D':
    {
      switch(a)
      {
        case '1':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1H0W0P2W1R0W0S1S3S2W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
        case '3':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1H0W0N2W1R0W0S1S3S2W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
        case '2':
        {BaseMove("R1R3W0P1N3W1H1H3W0R0R2W0");
        BaseMove("S1S3W1N2W1H0W0P2W1R0W0S1S3S2W1H0H2W0");
        BaseMove("R1R3W0P3N1W1H1H3W0S1S3W1H0H2W0");break;}
      }
      break;
    }
    case 'F':
    {
      switch(a)
      {
        case '1':
        {BaseMove("P2W1R2W0S2W1H2W0");break;}
        case '3':
        {BaseMove("N2W1R2W0S2W1H2W0");break;}
        case '2':
        {BaseMove("P2W1R2W0N2W1W1H2W0S2W1");break;}
      }
      break;
    }
    case 'B':
    {
      switch(a)
      {
        case '1':
        {BaseMove("P0W1R0W0S0W1H0W0");break;}
        case '3':
        {BaseMove("N0W1R0W0S0W1H0W0");break;}
        case '2':
        {BaseMove("P0W1R0W0N0W1W1H0W0S0W1");break;}
      }
      break;
    }
    case 'R':
    {

      switch(a)
      {
        case '1':
        {BaseMove("P1W1R1W0S1W1H1W0");break;}
        case '3':
        {BaseMove("N1W1R1W0S1W1H1W0");break;}
        case '2':
        {BaseMove("P1W1R1W0N1W1W1H1W0S1W1");break;}
      }
      break;
    }
    case 'L':
    {
      switch(a)
      {
        case '1':
        {BaseMove("P3W1R3W0S3W1H3W0");break;}
        case '3':
        {BaseMove("N3W1R3W0S3W1H3W0");break;}
        case '2':
        {BaseMove("P3W1R3W0N3W1W1H3W0S3W1");break;}
      }
      break;
    }
  }
}
void DoMove()
{
  String temp = "";
  temp = command.substring(1);
  BaseMove(temp);
}
void Solve()
{
  BaseMove(ReadyToStartCommand);
  answer = command;
  for(int i=0;i<answer.length()-1;i+=2)
  {
    Move(answer,answer[i+1]);
  }
}
[/mw_shl_code]


代码没加注释,因为比较简单。看起来很厉害的样子,其实我一说大家就明白了。是不是看到很多字符串,整个东西就是靠这些字符串工作起来的,S1表示第一个爪子回到中点,P1表示第一个爪子顺时针旋转,N1则是逆时针。H1表示第一个爪子夹住,R1表示第一个爪子松开,234当然是一样的啦。W是什么,是wait,咱们平时玩舵机的时候不是都得delay()么,一个意思,只是这里换成了其他的表示。为什么要这样表示?这里有8个舵机,要是一个个自己去控制那不是找虐么,CNC上不是也用G代码控制动作么,这是一个意思。方便,可控性强,所以,有了这些字符串我们就能控制这4个爪子做还原魔方需要的所有的复杂动作了。
 楼主| 发表于 2016-1-20 23:20 | 显示全部楼层
以后会有3D打印的版本,外观会有所改进
发表于 2016-1-21 20:28 | 显示全部楼层
上视频啊 看看效果
发表于 2016-1-22 11:28 | 显示全部楼层
这个创意挺牛的
发表于 2016-1-22 14:20 | 显示全部楼层
怎么觉得2个夹子应该就够呢
发表于 2016-1-31 01:21 | 显示全部楼层
楼主,你那个带螺丝孔的主体框架,是叫什么名字
发表于 2016-1-31 09:17 | 显示全部楼层
晓得了,这框架是井字连接件和万能杆
 楼主| 发表于 2016-1-31 20:36 | 显示全部楼层
风飘红 发表于 2016-1-31 09:17
晓得了,这框架是井字连接件和万能杆

淘宝有很多啊,几毛一根
发表于 2016-3-27 23:24 | 显示全部楼层
楼主求零件啊
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 05:26 , Processed in 0.269649 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表