3自由度并联绘图机器人实现写字功能(二)

news2024/12/23 0:02:32

1. 功能说明

    本文示例将实现R305b样机3自由度并联绘图机器人写字的功能。本实验使用的样机是用探索者兼容零件制作的。

2. 电子硬件

    在这个示例中,采用了以下硬件,请大家参考:

主控板

Basra主控板(兼容Arduino Uno)

扩展板

Bigfish2.1扩展板

传感器触碰传感器
电池7.4V锂电池

3. 功能实现

3.1建立坐标系

      我们需要先对3自由度并联绘图机器人进行极限位置调节,下图中为左极限位置,右极限位置与其对称。3自由度并联绘图机器人绘图主要由图中所示两个伺服电机控制。

3.2 硬件连接

       ① 触碰传感器连接Bigfish扩展板A0端口

       ② 左侧舵机连接Bigfish扩展板D4号引脚

       ③ 右侧舵机连接Bigfish扩展板D7号引脚

       ④ 控制底部连杆的舵机连接到Bigfish扩展板D11号引脚

3.3 示例程序

编程环境:Arduino 1.8.19

实现思路:接通电源后,等待3秒,按下触碰传感器,3自由度并联绘图机器人开始依次写出“王”、“云”、“飞”三个汉字。  

将参考例程(ThreeServo_Writing.ino)下载到主控板:

/*------------------------------------------------------------------------------------

  版权说明:Copyright 2023 Robottime(Beijing) Technology Co., Ltd. All Rights Reserved.

           Distributed under MIT license.See file LICENSE for detail or copy at

           https://opensource.org/licenses/MIT

           by 机器谱 2023-04-03 https://www.robotway.com/

  ------------------------------*/

/*******************************************************************************************************

实现功能:

         三自由度舵机组成的机械臂实现写字;



实现思路:

          接通电源后,等待3秒,按下触碰传感器,3自由度并联绘图机器人开始依次写出“王”、“云”、“飞”三个汉字



实验接线:

         触碰传感器接到A0;

         控制左边连杆的舵机接到D4;

         控制右边连杆的舵机接到D7;

         控制底部连杆的舵机接到D11;

*******************************************************************************************************/


#include <Servo.h> //驱动舵机需要的函数库


#define SERVOLEFTNULL 500      //左侧舵机转动到0度的值

#define SERVORIGHTNULL 500     //右侧舵机转动到0度的值


#define SERVOFAKTORLEFT 603    //左侧舵机转动到0度右侧舵机转动到90度时的值

#define SERVOFAKTORRIGHT 610   //左侧舵机转动到90度右侧舵机转动到180度时的值


#define LIFT0 1500             //落笔写字时舵机转动的值

#define LIFT1 1800             //一笔写完换笔时舵机转动的值

#define LIFT2 1400             //初始及完成写字后抬笔时舵机的值


#define SERVOPINLEFT 4         //定义左边舵机要连接的引脚;

#define SERVOPINRIGHT 7        //定义右边舵机要连接的引脚;

#define SERVOPINLIFT 11        //定义底部舵机要链接的引脚;


#define TouchSensor A0         //触碰传感器连接的引脚


#define LIFTSPEED 1500         //定义抬笔落笔时舵机转动的速度


#define L1 90                  //定义与舵机相连杆的长度 mm  

#define L2 117.6               //定义与舵机相连杆的端点铰接处中心到笔中心的距离 mm

#define L3 31.6                //定义中间杆顶端铰接处中心到笔的距离 mm


#define X1 40.0                //定义左侧舵机中心轴到原点在X方向上的距离

#define Y1 -42                 //定义左侧舵机中心轴到X轴的垂直距离

#define X2 111.4               //定义右侧舵机中心轴到原点在X方向上的距离

#define Y2 -42                 //定义右侧舵机中心轴到到X轴的垂直距离


//坐标系建立第一象限,X轴方向为140mm,Y轴方向为120mm,选取坐标点时Y值建议大于70

int coAry[10][10][2] = {         


              //汉字   王

              {{25,110},{0,0},{51,110},{1,1}},

              {{26,98},{0,0},{49,98},{1,1}},

              {{25,84},{0,0},{51,84},{1,1}},

              {{37,110},{0,0},{37,84},{1,1}},


              //汉字   云

              {{61,110},{0,0},{81,110},{1,1}},

              {{58,100},{0,0},{85,100},{1,1}},

              {{68,100},{0,0},{62,85},{86,85},{1,1}},

              {{80,96},{0,0},{91,82},{1,1}},

             

              //汉字   飞

              {{99,110},{0,0},{114,110},{114,98},{115,90},{115,86},{118,84},{121,82},{126,88},{1,1}},

              {{121,103},{0,0},{116,98},{122,94},{1,1}}

                         

};



int servoLift = LIFT2;


Servo servo1; //声明舵机1

Servo servo2; //声明舵机2

Servo servo3; //声明舵机3


volatile double lastX = 25;   //笔初始坐标值

volatile double lastY = 110;


void setup() {

  Serial.begin(9600);        //开启串口通信

  servo1.attach(SERVOPINLEFT);

  servo2.attach(SERVOPINRIGHT);

  servo3.attach(SERVOPINLIFT);   //声明舵机引脚;

  servo3.writeMicroseconds(LIFT0+500); //初始化机械身躯的高度;

  drawTo(lastX,lastY); //舵机初始角度;

  delay(3000);

}


void Waiting() //直到触碰传感器触发,程序开始运行

{

  while(digitalRead(TouchSensor)){

    delay(2);

  }

  delay(1000);

}


void loop() {

  Waiting();//直到触碰传感器触发,程序开始运行

  if(1)

  {     

    if(!servo1.attached()) servo1.attach(SERVOPINLEFT);

    if(!servo2.attached()) servo2.attach(SERVOPINRIGHT);

    if(!servo3.attached()) servo3.attach(SERVOPINLIFT);   

    lift(2);

    //汉字坐标处理

    for(int i=0;i<10;i++)

    {

      for(int j=0;j<10;j++)

      {

        int x = coAry[i][j][0];

        int y = coAry[i][j][1];               

        if(x == 0 && y == 0)

        {

          lift(0);

          continue;

        }

        else if(x == 1 && y == 1)

        {

          lift(1);

          break;

        }       

        drawTo(x,y);       

      }

    }

    lift(2);   

    servo1.detach();

    servo2.detach();

    servo3.detach();           

  }

  delay(1/0); //程序一直处于等待状态;(类似于死循环)

}


//抬笔舵机转动函数,三个动作,落笔、换笔、起笔, 0 ,1, 2

void lift(char lift)

{

  switch(lift)

  {

    case 0:

        Serial.println("lift0");

        if(servoLift >= LIFT0)

        {

          while(servoLift >= LIFT0)

          {

            servoLift--;

            servo3.writeMicroseconds(servoLift);

            delayMicroseconds(LIFTSPEED);

          }

        }

        else

        {

           while(servoLift <= LIFT0)

           {

             servoLift++;

             servo3.writeMicroseconds(servoLift);

             delayMicroseconds(LIFTSPEED);

           }

        }

    break;

    case 1:

        Serial.println("lift1");

        if(servoLift >= LIFT1)

        {

          while(servoLift >= LIFT1)

          {

            servoLift--;

            servo3.writeMicroseconds(servoLift);

            delayMicroseconds(LIFTSPEED);

          }

        }

        else

        {

          while(servoLift <= LIFT1)

          {

            servoLift++;

            servo3.writeMicroseconds(servoLift);

            delayMicroseconds(LIFTSPEED);

          }

        }

    break;

    case 2:

        Serial.println("lift2");

        if(servoLift >= LIFT2)

        {

          while(servoLift >= LIFT2)

          {

            servoLift--;

            servo3.writeMicroseconds(servoLift);

            delayMicroseconds(LIFTSPEED);

          }

        }

        else

        {

          while(servoLift <= LIFT2)

          {

            servoLift++;

            servo3.writeMicroseconds(servoLift);

            delayMicroseconds(LIFTSPEED);

          }

        }

    break;

    default:break;

  }

}


//笔移动函数,参数为点坐标值,计算两点坐标距离来控制笔移动

void drawTo(double pX, double pY) {

  double dx, dy, c;

  int i;

 

  Serial.println(pX);

  Serial.println(pY);


  // dx dy of new point

  dx = pX - lastX;

  dy = pY - lastY;

  //path lenght in mm, times 4 equals 4 steps per mm

  c = floor(10 * sqrt(dx * dx + dy * dy));


  if (c < 1) c = 1;


  for (i = 0; i <= c; i++) {

    // draw line point by point

    set_XY(lastX + (i * dx / c), lastY + (i * dy / c));

  }


  lastX = pX;

  lastY = pY;

}



double return_angle(double a, double b, double c) {

  // cosine rule for angle between c and a

  return acos((a * a + c * c - b * b) / (2 * a * c));

}



//用各种三角函数把位置坐标换算成舵机的角度,如何计算,请参考

//http://www.thingiverse.com/thing:248009/

void set_XY(double Tx, double Ty)

{

  delay(1);

  double dx, dy, c, a1, a2, Hx, Hy;


  // calculate triangle between pen, servoLeft and arm joint

  // cartesian dx/dy

  dx = Tx - X1;

  dy = Ty - Y1;


  // polar lemgth (c) and angle (a1)

  c = sqrt(dx * dx + dy * dy); //

  a1 = atan2(dy, dx); //

  a2 = return_angle(L1, L2, c);

 

  //Serial.println(floor(((M_PI-a1 - a2) * SERVOFAKTORLEFT) + SERVOLEFTNULL));


  servo1.writeMicroseconds(floor(((M_PI-a1 - a2) * SERVOFAKTORLEFT) + SERVOLEFTNULL));


  // calculate joinr arm point for triangle of the right servo arm

  a2 = return_angle(L2, L1, c);

  Hx = Tx + L3 * cos((a1 - a2 + 0.621) + M_PI); //36,5掳

  Hy = Ty + L3 * sin((a1 - a2 + 0.621) + M_PI);


  // calculate triangle between pen joint, servoRight and arm joint

  dx = Hx - X2;

  dy = Hy - Y2;


  c = sqrt(dx * dx + dy * dy);

  a1 = atan2(dy, dx);

  a2 = return_angle(L1, (L2 - L3), c);

 

  //Serial.println(floor(((M_PI - a1 + a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));


  servo2.writeMicroseconds(floor(((M_PI - a1 + a2) * SERVOFAKTORRIGHT) + SERVORIGHTNULL));


}

4. 资料内容

①写字2-例程源代码

②写字2-样机3D文件

资料内容详见:3自由度并联绘图机器人-写字2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/467096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Visual Studio C# WinForm开发入门(5):TabControl 控件使用

TabContrl选项卡控件可创建标签化窗口&#xff0c;在实际 编程中经常用到&#xff0c;该控件的作用是将相关的组件组合到一系列选项卡页面上。 比如下面的例子&#xff0c;在tabPage1页面和tabPage2页面各放了2个checkBox控件&#xff0c;通过点击不同page即可切换&#xff1a;…

交叉编译工具

工具链有一个松散的名称约定&#xff0c;如 arch[-vendor][-os]-abi-language . arch 适用于架构&#xff0c;编译器用于哪个目标平台&#xff1a; arm &#xff0c; mips &#xff0c; x86 &#xff0c; i686 ... vendor 是工具链供应商&#xff0c;以厂家名称命名的&#xf…

权威学者、企业CFO荟聚上海国家会计学院,共探「智能会计 价值财务」

4月21日&#xff0c;由用友主办的「智能会计 价值财务」2023企业数智化财务创新峰会在上海国家会计学院圆满举办。学院权威教授、业内专家与来自央国企、行业领先企业的财务先锋&#xff0c;线下云端共聚一堂&#xff0c;数万人共探大型企业财务数智化的全新价值主张。 会议伊始…

WLAN - 五大安全措施

文章目录 1 概述2 五大安全措施2.1 SSID 访问控制2.2 物理地址过滤 MAC2.3 有线等效保密 WEP2.4 WPA&#xff08;IEEE 802.11i 草案&#xff09;2.5 WPA2&#xff08;IEEE 802.11i&#xff09; 3 扩展3.1 网工软考真题 1 概述 无线局域网面临着两个主要问题&#xff0c;一是增…

【Unity入门】19.定时调用Invoke

【Unity入门】定时调用Invoke 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;计时器 &#xff08;1&#xff09;Invoke 单词调用 计时器我们并不陌生&#xff0c;在cocos上有着schedule类是…

深度学习 - 45.MMOE Gate 简单实现 By Keras

目录 一.引言 二.MMoE 模型分析 三.MMoE 逻辑实现 • Input • Expert Output • Gate Output • Weighted Sum • Sigmoid Output • 完整代码 四.总结 一.引言 上一篇文章介绍了 MMoE 借鉴 MoE 的思路&#xff0c;为每一类输出构建一个 Gate 并最终加权多个 Exper…

http---HTTP缓存

目录 1、缓存介绍 2、http缓存 3、强缓存 4、协商缓存 1、缓存介绍 缓存&#xff1a;存储将被用的数据&#xff0c;让数据访问更快。 缓存相关术语 命中&#xff1a;在缓存中找到了请求的数据不命中/穿透&#xff1a;缓存中没有需要的数据命中率&#xff1a;命中次数/总…

Yarn(Yet Another Reource Negotiator)另一个资源协调者

官网引用 总结性 产生的需求 YARN工作逻辑 通用的资源管理系统&#xff0c;为上一层应用提供统一的资源管理和调度。解决集群资源利用率&#xff0c;数据共享&#xff0c;资源管理统一问题&#xff0c;yarn取代Job Tracker角色 组件说明 Client 向RM提交任务&#xff0c;终…

1、软件测试概述

1、软件测试概述 一、软件生命周期二、软件开发模型1、瀑布模型2、增量模型3、原型模型4、敏捷开发 三、软件质量1、软件质量概念2、影响软件质量的因素 一、软件生命周期 软件生命周期分为多个阶段&#xff0c;每个阶段有明确的任务&#xff0c;通常&#xff0c;可将软件生命…

ARM寄存器组织

ARM有37个32位长的寄存器&#xff1a; 1个用做PC&#xff08;Program Counter&#xff09;&#xff1b; 1个用做CPSR(Current Program Status Register)&#xff1b; 5个用做SPSR&#xff08;Saved Program Status Registers&#xff09;&#xff1b; 30个通用寄存器。 AR…

Unity之OpenXR+XR Interaction Toolkit实现 射线和物体交互事件回调

前言 前面我们介绍了如何抓取物体&#xff0c;今天我们来说一下如何和3D的物体进行交互&#xff0c;得到接触的事件回调。 交互的两种方式&#xff1a; 1.直接抓取或者射线抓取物体&#xff0c;得到接触回调 2.射线或者手部触摸物体后&#xff0c;得到接触回调 准备工作 有了…

Android 10.0 设置默认launcher后安装另外launcher后默认Launcher失效的功能修复

1.前言 在10.0的系统rom定制化开发中,在系统中有多个launcher的时候,会在开机进入launcher的时候弹窗launcher列表,让用户选择进入哪个launcher,这样显得特别的不方便 所以产品开发中,要求用RoleManager的相关api来设置默认Launcher,但是在设置完默认Launcher以后,在安…

嵌入式软考备考_3 嵌入式操作系统概述

嵌入式操作系统概述 工作在嵌入式环境中的操作系统 Embedded Operating System。 嵌入式和一般操作系统区别&#xff1a; 非通用操作系统&#xff0c;用于完成特定功能&#xff1b;性能实时性能源可靠性要求高&#xff1b;占用资源少&#xff1b;可剪裁&#xff0c;可配置。…

渗透测试 | Web信息收集

0x00 免责声明 本文仅限于学习讨论与技术知识的分享&#xff0c;不得违反当地国家的法律法规。对于传播、利用文章中提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;本文作者不为此承担任何责任&#xff0c;一旦造成后果请自行承担…

《程序员面试金典(第6版)》面试题 16.04. 井字游戏(棋盘类问题,C++)

题目描述 设计一个算法&#xff0c;判断玩家是否赢了井字游戏。输入是一个 N x N 的数组棋盘&#xff0c;由字符" "&#xff0c;“X"和"O"组成&#xff0c;其中字符” "代表一个空位。 以下是井字游戏的规则&#xff1a; 玩家轮流将字符放入空位…

专门为麻醉科和手术室开发的:手术麻醉系统源码,系统稳定,功能完整,支持二次开发

手术麻醉系统源码&#xff1a;C# .net 桌面软件 C/S版 系统极其稳定&#xff0c;扩展性强&#xff0c;已在多家医院运营。 文末获取联系 手术麻醉信息管理系统是专门为麻醉科和手术室开发的围手术期临床信息管理系统&#xff0c;具备以下功能: 1.手术程管理系统整合了手术室、…

人工智能实践: 基于T-S 模型的模糊推理

模糊推理是一种基于行为的仿生推理方法, 主要用来解决带有模糊现象的复杂推理问题。由于模糊现象的普遍存在, 模糊推理系统被广泛的应用。模糊推理系统主要由模糊化、模糊规则库、模糊推理方法以及去模糊化组成, 其基本流程如图1所示。

C++(继承下)

目录&#xff1a; 1.继承与有元 2.继承与静态成员 3.单继承、多继承 4.如何定义一个不能被继承的类&#xff1f;&#xff1f; 5.分享有意思的一道题 6.菱形继承及菱形虚拟继承 --------------------------------------------------------------------------------------------…

【c语言】全局变量 | 局部变量的生命周期与作用域

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

亚马逊云科技赋能客户,为海思科打造安全高效的营销业务中台系统

羽翼渐丰&#xff0c;翱翔云端 携手亚马逊云科技&#xff0c;打造互联网级企业解决方案 秉承“为客户创造价值”的理念&#xff0c;在公司发展过程中&#xff0c;博智信息先后服务了众多知名企业&#xff0c;客户行业覆盖制造、零售、餐饮、科技、电子等。经过近20年的发展&a…