查看: 17096|回復: 79
打印 上一主題 下一主題

SpiderRobot 蜘蛛

  [復制鏈接]
  • TA的每日心情
    奮斗
    2019-3-22 20:44
  • 簽到天數: 6 天

    [LV.2]偶爾看看I

    跳轉到指定樓層
    樓主
    發表于 2018-6-3 09:39 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
    本帖最后由 createskyblue 于 2020-3-3 12:08 編輯

    關于SpiderRobot 項目實行方案





    之前有人推薦我做這個項目,于是乎就有了這個




    http://regishsu.blogspot.tw/search/label/0.SpiderRobot
    蜘蛛制作教程以及程序:http://www.instructables.com/id/DIY-Spider-RobotQuad-robot-Quadruped/



    好啦,廢話不多說,接下來是我的制作過程以及注意事項,希望想做的朋友可以成功!


    第一部分  材料準備
    Atmega328  或 Arduino 2650          X1
    16M晶振              X1
    22pf陶瓷電容             X2    最好有
    SG90舵機                X12
    7x9CM洞洞板              X1
    LED                                                   X1
    220Ω電阻                X1
    波動開關                                          X1
    3x25MM螺絲            X6    最好有
    排針若干
    焊絲若干
    3D打印件

    3D打印文件下載:
    files.zip (784.96 KB, 下載次數: 139)



    第二部分 進行組裝

    這一步組裝要注意好方向,有兩組相反的零部件,一定要注意,當時我沒留意對不上硬是搞了半小時反復拆裝!



    安裝時,每只腳可以分為3部分,我個人推薦先安裝紅色部分然后再到藍色部分最后安裝綠色部分,這樣擰螺絲會比較方便
    然后紅色部分的灰白色位置是朝上的,因為這個蜘蛛有兩組相對的腳相對應也有兩組相反的零件,這里注意下就好。藍色部分分為A和B;比較長的為A比較短的為B。組裝的時候要注意方向

    每只腳還有兩個關節固定點,所以我們需要打印2份固定卡扣 (一共8個)。下圖中紅色為沒有扣上固定卡扣,藍色為扣上并擰上螺絲;安裝時先把卡扣懟到卡位,再安裝舵機。

    并且舵機安裝過程中一定要使用舵機測試程序進行測試,不然會導致后期腿會發瘋甚至燒毀舵機,我因為沒有留意原文的這一步導致最后又要拆掉重裝!推薦每安裝一條腿隨后一起測試著3條腿的舵機!
    舵機測試.zip (430 Bytes, 下載次數: 67)

    圖中的數字為對應舵機接到板子上的接口位置
    根據這個關系我們需要制作最小系統電路板,它是蜘蛛的大腦,我們需要它來完成之后的測試




    測試的要求,腿的紅色部分要與地面垂直,藍色部分向上傾斜大約40°,最后綠色部分也就是最靠近中間的4個舵機要形成X字形;

    如果測試中達不到要求可以執行以下步驟:
    1. 取下舵機臂上的螺絲及其舵機臂
    2. 運行測試程序
    3. 然后把舵機臂扣上,確保舵機臂為上述要求,最后擰上螺絲
    4. 再次運行測試程序
    5. 如果有小偏差重復以上步驟,大偏差說明你還沒有理解以上步驟
    6. 如果舵機臂與3d打印支架存在松動情況不推薦使用膠布或膠水,推薦使用橡皮筋,像我一樣


    如果最終測試像上圖一樣,恭喜,你已經完成90%的步驟!


    第三部分  演示

    視頻:審核完成  

    https://www.bilibili.com/video/av24322376/

    程序: spider_robot.zip (4.06 KB, 下載次數: 143)
    游客,如果您要查看本帖隱藏內容請回復


    // 由RegisHsu添加

    void body_left(int i)
    {
      set_site(0, site_now[0][0] + i, KEEP, KEEP);
      set_site(1, site_now[1][0] + i, KEEP, KEEP);
      set_site(2, site_now[2][0] - i, KEEP, KEEP);
      set_site(3, site_now[3][0] - i, KEEP, KEEP);
      wait_all_reach();
    }

    void body_right(int i)
    {
      set_site(0, site_now[0][0] - i, KEEP, KEEP);
      set_site(1, site_now[1][0] - i, KEEP, KEEP);
      set_site(2, site_now[2][0] + i, KEEP, KEEP);
      set_site(3, site_now[3][0] + i, KEEP, KEEP);
      wait_all_reach();
    }

    void hand_wave(int i)
    {
      float x_tmp;
      float y_tmp;
      float z_tmp;
      move_speed = 1;
      if (site_now[3][1] == y_start)
      {
        body_right(15);
        x_tmp = site_now[2][0];
        y_tmp = site_now[2][1];
        z_tmp = site_now[2][2];
        move_speed = body_move_speed;
        for (int j = 0; j < i; j++)
        {
          set_site(2, turn_x1, turn_y1, 50);
          wait_all_reach();
          set_site(2, turn_x0, turn_y0, 50);
          wait_all_reach();
        }
        set_site(2, x_tmp, y_tmp, z_tmp);
        wait_all_reach();
        move_speed = 1;
        body_left(15);
      }
      else
      {
        body_left(15);
        x_tmp = site_now[0][0];
        y_tmp = site_now[0][1];
        z_tmp = site_now[0][2];
        move_speed = body_move_speed;
        for (int j = 0; j < i; j++)
        {
          set_site(0, turn_x1, turn_y1, 50);
          wait_all_reach();
          set_site(0, turn_x0, turn_y0, 50);
          wait_all_reach();
        }
        set_site(0, x_tmp, y_tmp, z_tmp);
        wait_all_reach();
        move_speed = 1;
        body_right(15);
      }
    }

    void hand_shake(int i)
    {
      float x_tmp;
      float y_tmp;
      float z_tmp;
      move_speed = 1;
      if (site_now[3][1] == y_start)
      {
        body_right(15);
        x_tmp = site_now[2][0];
        y_tmp = site_now[2][1];
        z_tmp = site_now[2][2];
        move_speed = body_move_speed;
        for (int j = 0; j < i; j++)
        {
          set_site(2, x_default - 30, y_start + 2 * y_step, 55);
          wait_all_reach();
          set_site(2, x_default - 30, y_start + 2 * y_step, 10);
          wait_all_reach();
        }
        set_site(2, x_tmp, y_tmp, z_tmp);
        wait_all_reach();
        move_speed = 1;
        body_left(15);
      }
      else
      {
        body_left(15);
        x_tmp = site_now[0][0];
        y_tmp = site_now[0][1];
        z_tmp = site_now[0][2];
        move_speed = body_move_speed;
        for (int j = 0; j < i; j++)
        {
          set_site(0, x_default - 30, y_start + 2 * y_step, 55);
          wait_all_reach();
          set_site(0, x_default - 30, y_start + 2 * y_step, 10);
          wait_all_reach();
        }
        set_site(0, x_tmp, y_tmp, z_tmp);
        wait_all_reach();
        move_speed = 1;
        body_right(15);
      }
    }

    void head_up(int i)
    {
      set_site(0, KEEP, KEEP, site_now[0][2] - i);
      set_site(1, KEEP, KEEP, site_now[1][2] + i);
      set_site(2, KEEP, KEEP, site_now[2][2] - i);
      set_site(3, KEEP, KEEP, site_now[3][2] + i);
      wait_all_reach();
    }

    void head_down(int i)
    {
      set_site(0, KEEP, KEEP, site_now[0][2] + i);
      set_site(1, KEEP, KEEP, site_now[1][2] - i);
      set_site(2, KEEP, KEEP, site_now[2][2] + i);
      set_site(3, KEEP, KEEP, site_now[3][2] - i);
      wait_all_reach();
    }

    void body_dance(int i)
    {
      float x_tmp;
      float y_tmp;
      float z_tmp;
      float body_dance_speed = 2;
      sit();
      move_speed = 1;
      set_site(0, x_default, y_default, KEEP);
      set_site(1, x_default, y_default, KEEP);
      set_site(2, x_default, y_default, KEEP);
      set_site(3, x_default, y_default, KEEP);
      wait_all_reach();
      //stand();
      set_site(0, x_default, y_default, z_default - 20);
      set_site(1, x_default, y_default, z_default - 20);
      set_site(2, x_default, y_default, z_default - 20);
      set_site(3, x_default, y_default, z_default - 20);
      wait_all_reach();
      move_speed = body_dance_speed;
      head_up(30);
      for (int j = 0; j < i; j++)
      {
        if (j > i / 4)
          move_speed = body_dance_speed * 2;
        if (j > i / 2)
          move_speed = body_dance_speed * 3;
        set_site(0, KEEP, y_default - 20, KEEP);
        set_site(1, KEEP, y_default + 20, KEEP);
        set_site(2, KEEP, y_default - 20, KEEP);
        set_site(3, KEEP, y_default + 20, KEEP);
        wait_all_reach();
        set_site(0, KEEP, y_default + 20, KEEP);
        set_site(1, KEEP, y_default - 20, KEEP);
        set_site(2, KEEP, y_default + 20, KEEP);
        set_site(3, KEEP, y_default - 20, KEEP);
        wait_all_reach();
      }
      move_speed = body_dance_speed;
      head_down(30);
    }


    /*
      - 舵機服務/定時器中斷功能/50Hz
      - 當設置site expected時,這個函數會移動到目標直線
      - 在設置expect之前,應該設置temp_speed[4][3],確保
    直線移動,決定移動速度。
       ---------------------------------------------------------------------------*/
    void servo_service(void)  //舵機服務
    {
      sei();
      static float alpha, beta, gamma;

      for (int i = 0; i < 4; i++)
      {
        for (int j = 0; j < 3; j++)
        {
          if (abs(site_now[j] - site_expect[j]) >= abs(temp_speed[j]))
            site_now[j] += temp_speed[j];
          else
            site_now[j] = site_expect[j];
        }

        cartesian_to_polar(alpha, beta, gamma, site_now[0], site_now[1], site_now[2]); //從笛卡爾坐標系到極坐標轉化
        polar_to_servo(i, alpha, beta, gamma); //用對應的極坐標控制舵機
      }

      rest_counter++;
    }

    /*
      - 設置一個預計位置點
      - 這個函數將同時設置temp_speed[4][3]
      - non - 模塊化功能
       ---------------------------------------------------------------------------*/
    void set_site(int leg, float x, float y, float z)  //設置某一條腿的坐標
    {
      float length_x = 0, length_y = 0, length_z = 0;  //初始化float類型變量length_x,length_y,length_z

      if (x != KEEP)  //假若x軸不是保持狀態
        length_x = x - site_now[leg][0];  //計算x軸長度
      if (y != KEEP)  //假若y軸不是保持狀態
        length_y = y - site_now[leg][1];  //計算y軸長度
      if (z != KEEP)  //假若z軸不是保持狀態
        length_z = z - site_now[leg][2];  //計算z軸長度

      float length = sqrt(pow(length_x, 2) + pow(length_y, 2) + pow(length_z, 2));   //計算宗長度

      temp_speed[leg][0] = length_x / length * move_speed * speed_multiple;  //計算對應腿的舵機1移動速度
      temp_speed[leg][1] = length_y / length * move_speed * speed_multiple;  //計算對應腿的舵機2移動速度
      temp_speed[leg][2] = length_z / length * move_speed * speed_multiple;  //計算對應腿的舵機3移動速度

      if (x != KEEP)  //假若x軸不是保持狀態,則設置目標角度
        site_expect[leg][0] = x;
      if (y != KEEP)  //假若y軸不是保持狀態,則設置目標角度
        site_expect[leg][1] = y;
      if (z != KEEP)  //假若z軸不是保持狀態,則設置目標角度
        site_expect[leg][2] = z;
    }

    /*
       ---------------------------------------------------------------------------*/
    void wait_reach(int leg)  //等待某條腿動作完成函數
    {
      while (1) //死循環
        if (site_now[leg][0] == site_expect[leg][0])    //等待目標腿的 舵機 1達到目標角度
          if (site_now[leg][1] == site_expect[leg][1])//等待目標腿的 舵機 2達到目標角度
            if (site_now[leg][2] == site_expect[leg][2])//等待目標腿的 舵機 3達到目標角度
              break;  //跳出循環
    }

    /*
       ---------------------------------------------------------------------------*/
    void wait_all_reach(void) //等待全部腿動作完成函數
    {
      for (int i = 0; i < 4; i++)   //依次等待4條腿動作完成
        wait_reach(i);
    }

    /*
      - 從笛卡爾坐標系到極坐標轉化
      - 數學模型2/2
       ---------------------------------------------------------------------------*/
    void cartesian_to_polar(volatile float &alpha, volatile float &beta, volatile float &gamma, volatile float x, volatile float y, volatile float z)
    {
      //calculate w-z degree
      float v, w;
      w = (x >= 0 ? 1 : -1) * (sqrt(pow(x, 2) + pow(y, 2)));
      v = w - length_c;
      alpha = atan2(z, v) + acos((pow(length_a, 2) - pow(length_b, 2) + pow(v, 2) + pow(z, 2)) / 2 / length_a / sqrt(pow(v, 2) + pow(z, 2)));
      beta = acos((pow(length_a, 2) + pow(length_b, 2) - pow(v, 2) - pow(z, 2)) / 2 / length_a / length_b);
      //calculate x-y-z degree
      gamma = (w >= 0) ? atan2(y, x) : atan2(-y, -x);
      //trans degree pi->180
      alpha = alpha / pi * 180;
      beta = beta / pi * 180;
      gamma = gamma / pi * 180;
    }

    /*
      - 用對應的極坐標控制舵機
      - 數學模型與事實相吻合的情況下
      - EEprom中存儲的錯誤將被添加
       ---------------------------------------------------------------------------*/
    void polar_to_servo(int leg, float alpha, float beta, float gamma)
    {
      if (leg == 0)
      {
        alpha = 90 - alpha;
        beta = beta;
        gamma += 90;
      }
      else if (leg == 1)
      {
        alpha += 90;
        beta = 180 - beta;
        gamma = 90 - gamma;
      }
      else if (leg == 2)
      {
        alpha += 90;
        beta = 180 - beta;
        gamma = 90 - gamma;
      }
      else if (leg == 3)
      {
        alpha = 90 - alpha;
        beta = beta;
        gamma += 90;
      }

      servo[leg][0].write(alpha);  //設定對應腿上的舵機1旋轉角度
      servo[leg][1].write(beta);   //設定對應腿上的舵機2旋轉角度
      servo[leg][2].write(gamma);  //設定舵機3旋轉角度
    }
    有讀者提到一個問題,怎么轉換為極坐標,可以看另外一個制作貼

    芯片裝配.pdf

    253.92 KB, 下載次數: 91

  • TA的每日心情
    擦汗
    2018-7-19 09:55
  • 簽到天數: 2 天

    [LV.1]初來乍到

    推薦
    發表于 2018-7-18 10:10 | 只看該作者
    放假就開始設計—打印—安裝—調試…………那里是爬啊就是在挪
    謝謝樓主分享,給予很多的啟發

    該用戶從未簽到

    地板
    發表于 2018-6-13 17:19 | 只看該作者
    3d打印每樣都要打印幾個?

    該用戶從未簽到

    5#
    發表于 2018-6-13 17:55 | 只看該作者
    有原理圖嗎
  • TA的每日心情
    開心
    2018-9-5 18:03
  • 簽到天數: 1 天

    [LV.1]初來乍到

    10#
    發表于 2018-9-5 17:46 | 只看該作者
    感謝樓主分享
    您需要登錄后才可以回帖 登錄 | 立即注冊

    本版積分規則

    熱門推薦

    【零知esp8266教程】快速入門30 rc-switch無線收發模塊的使用
    【零知esp8266教程】快速
    本實驗使用零知esp8266和rc-switch模塊的使用。 1、實驗材料 零知ESP8266開發板 R433
    基于L293D的藍牙、尋跡、避障、四驅遙控小車
    基于L293D的藍牙、尋跡、
    鏈接外網的視頻放不了,只好發鏈接了 視頻地址:https://v.youku.com/v_show/id_XNDQ4
    又偷東西咯。dht11溫濕度+oled+小愛+blinker
    又偷東西咯。dht11溫濕度+
    不玩了,不建議和我一樣的新手進qq群。
    【原創】 drawbot平面關節scara機械臂寫字機 畫畫機器人直播...
    【原創】 drawbot平面關節
    這個項目上個月就在做了,結構和代碼反反復復改了多次,加上自己又太忙,一直沒來得及
    基于機器視覺的智能分揀機械臂
    基于機器視覺的智能分揀機
    本作品是一個基于機器視覺的智能機械臂操作平臺,其采用atmega32單片機作為主控制系統
    Copyright   ©2015-2016  Arduino中文社區  Powered by©Discuz!   
    快速回復 返回頂部 返回列表
    财神捕鱼游戏手机版下载