使用三轴XYZ平台绘制空心字

这篇具有很好参考价值的文章主要介绍了使用三轴XYZ平台绘制空心字。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 功能说明 

     本文示例将实现R312三轴XYZ平台绘制“机器时代”空心字的功能。

使用三轴XYZ平台绘制空心字

使用三轴XYZ平台绘制空心字

2. 电子硬件

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

主控板

Basra主控板(兼容Arduino Uno)

扩展板

Bigfish2.1扩展板

SH-ST步进电机扩展板
电池 11.1V动力电池
传感器 触碰传感器

其它

笔架×1(自制,可根据文末资料提供的3D文件打印)

3. 功能实现

      在这里我们采用了一种算法,该算法的思路是:先建立一个平面坐标系,将我们所需要画的图形放置在该坐标系中,这样就可以确定该图形每个顶点的坐标,两个相邻的顶点之间确定一条直线,直线上各点坐标通过插补计算得到,然后画笔依次沿着这些坐标进行移动,完成绘制。所以在这个过程中,我们需要知道如何建立一个图形的坐标系,以及什么是插补计算。插补计算方法可参考 【R311】双轴XY平台-绘制斜向多边形

建立坐标系:

     三轴XYZ平台绘图仪,即通过X, Y, Z三轴的步进电机协调控制绘图笔来进行图形的绘制。通过上位机(PC)来发送gcode代码;下位机(三轴XYZ平台绘图仪)通过对接收到的gcode坐标代码进行解析,并通过插补算法来控制各个轴的步进电机进行图形绘制。

使用三轴XYZ平台绘制空心字

本实验将基于三轴XYZ平台利用processing软件处理gcode文件后,进行绘制文字“机器时代”。

使用三轴XYZ平台绘制空心字

3.1硬件连接

    ① 各轴步进电机与SH-ST步进电机扩展板的接线顺序如下(从上至下):

         X:红蓝黑绿

         Y:红蓝黑绿

         Z:黑绿红蓝

使用三轴XYZ平台绘制空心字

    ② 各个轴的限位传感器(触碰)与Bigfish扩展板的接线如下:

        X:A0

        Y:A4

        Z:A2

使用三轴XYZ平台绘制空心字

3.2 示例程序

编程环境:Arduino 1.8.19

      将参考例程代码(_4_smile.ino)下载到主控板中,烧录完成后打开电源,三轴XYZ平台绘图仪各轴步进电机将进行复位,复位完成后,绘图笔将到达绘图区域中心,本实验中三轴XYZ平台绘图仪绘图面积为80*80mm。

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

  版权说明: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-03-30 https://www.robotway.com/

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

#define EN        8       //步进电机使能端,低电平有效

#define X_DIR     5       //X轴 步进电机方向控制

#define Y_DIR     6       //y轴 步进电机方向控制

#define Z_DIR     7       //z轴 步进电机方向控制

#define X_STP     2       //x轴 步进控制

#define Y_STP     3       //y轴 步进控制

#define Z_STP     4       //z轴 步进控制

boolean DIR;              //boolean类型变量 DIR,控制步进电机方向,true为正向,false为反向,根据接线做调整

int stepper_pulse = 40;   //定义步进电机脉冲发送的时间间隔


#define LINE_BUFFER_LENGTH 512  


const int SENSOR_X = 14;   //定义X,Y,Z轴复位传感器引脚

const int SENSOR_Y = 18;

const int SENSOR_Z = 16;


const int stepsPerRevolution = 3200;   //定义步进电机每圈转动的步数,细分为16


float LEAD = 8;   //定义丝杠导程,即步进电机转动一圈,丝杠前进8mm


struct point {   

  float x;

  float y;

  float z;

};


// Current position of plothead

struct point actuatorPos;


float Xmin = -40;   //定义绘图区域范围

float Xmax = 40;

float Ymin = -40;

float Ymax = 40;


float Xpos = 0;

float Ypos = 0;


boolean verbose = false;


void setup()

{

  Serial.begin(9600);      //开启串口通信,波特率为9600

  pinMode(X_DIR, OUTPUT); pinMode(X_STP, OUTPUT);

  pinMode(Y_DIR, OUTPUT); pinMode(Y_STP, OUTPUT);

  pinMode(Z_DIR, OUTPUT); pinMode(Z_STP, OUTPUT);

  pinMode(EN, OUTPUT);

  digitalWrite(EN, LOW);  

  resetStepper();

  digitalWrite(EN, HIGH);

  delay(1000);

}


void loop()

{           

  delay(200);

  char line[ LINE_BUFFER_LENGTH ];

  char c;

  int lineIndex;

  bool lineIsComment, lineSemiColon;


  lineIndex = 0;

  lineSemiColon = false;

  lineIsComment = false;


  while (1) {


    // 接受来自Grbl的串口数据

    while ( Serial.available()>0 ) {

      c = Serial.read();

      if (( c == '\n') || (c == '\r') ) {             // End of line reached

        if ( lineIndex > 0 ) {                        // Line is complete. Then execute!

          line[ lineIndex ] = '\0';                   // Terminate string

          if (verbose) {

            Serial.print( "Received : ");

            Serial.println( line );

          }

          processIncomingLine( line, lineIndex );

          lineIndex = 0;

        }

        else {

          // Empty or comment line. Skip block.

        }

        lineIsComment = false;

        lineSemiColon = false;

        Serial.println("ok");   

      }

      else {

        if ( (lineIsComment) || (lineSemiColon) ) {   // Throw away all comment characters

          if ( c == ')' )   lineIsComment = false;     // End of comment. Resume line.

        }

        else {

          if ( c <= ' ' ) {                           // Throw away whitepace and control characters

          }

          else if ( c == '/' ) {                    // Block delete not supported. Ignore character.

          }

          else if ( c == '(' ) {                    // Enable comments flag and ignore all characters until ')' or EOL.

            lineIsComment = true;

          }

          else if ( c == ';' ) {

            lineSemiColon = true;

          }

          else if ( lineIndex >= LINE_BUFFER_LENGTH-1 ) {

            Serial.println( "ERROR - lineBuffer overflow" );

            lineIsComment = false;

            lineSemiColon = false;

          }

          else if ( c >= 'a' && c <= 'z' ) {        // Upcase lowercase

            line[ lineIndex++ ] = c-'a'+'A';

          }

          else {

            line[ lineIndex++ ] = c;

          }

        }

      }

    }

  }

}


void processIncomingLine( char* line, int charNB ) {

  int currentIndex = 0;

  char buffer[ 64 ];          // Hope that 64 is enough for 1 parameter

  stepper_pulse = 40;         //设置Z轴抬笔落笔时步进电机脉冲间隔

  struct point newPos;


  newPos.x = 0.0;

  newPos.y = 0.0;


  //   Needs to interpret

  //   G1 for moving

  //   G4 P300 (wait 150ms)

  //   G1 X60 Y30

  //   G1 X30 Y50

  //   M300 S30 (pen down)

  //   M300 S50 (pen up)

  //   Discard anything with a (

  //   Discard any other command!


  while( currentIndex < charNB ) {

    switch ( line[ currentIndex++ ] ) {           // Select command, if any

    case 'U':

      step(Z_DIR, Z_STP, 2000);

      break;

    case 'D':

      step(Z_DIR, Z_STP, -2000);

      break;

    case 'G':

      buffer[0] = line[ currentIndex++ ];          // /!\ Dirty - Only works with 2 digit commands

      //      buffer[1] = line[ currentIndex++ ];

      //      buffer[2] = '\0';

      buffer[1] = '\0';


      switch ( atoi( buffer ) ){                   // Select G command

      case 0:                                      // G00 & G01 - Movement or fast movement. Same here

      case 1:

        // /!\ Dirty - Suppose that X is before Y

        char* indexX = strchr( line+currentIndex, 'X' );    // Get X/Y position in the string (if any)

        char* indexY = strchr( line+currentIndex, 'Y' );

        if ( indexY <= 0 ) {

          newPos.x = atof( indexX + 1);

          newPos.y = actuatorPos.y;

        }

        else if ( indexX <= 0 ) {

          newPos.y = atof( indexY + 1);

          newPos.x = actuatorPos.x;

        }

        else {

          newPos.y = atof( indexY + 1);

          indexY = '\0';

          newPos.x = atof( indexX + 1);

        }

        drawLine(newPos.x, newPos.y );

        //        Serial.println("ok");

        actuatorPos.x = newPos.x;

        actuatorPos.y = newPos.y;

        break;

      }

      break;

    case 'M':

      buffer[0] = line[ currentIndex++ ];     // /!\ Dirty - Only works with 3 digit commands

      buffer[1] = line[ currentIndex++ ];

      buffer[2] = line[ currentIndex++ ];

      buffer[3] = '\0';

      switch ( atoi( buffer ) ){

      case 300:

        {

          char* indexS = strchr( line+currentIndex, 'S' );

          float Spos = atof( indexS + 1);

          //          Serial.println("ok");

          if (Spos == 30) {

            step(Z_DIR, Z_STP, -2000);

          }

          if (Spos == 50) {

            step(Z_DIR, Z_STP, 2000);

          }

          break;

        }

      case 114:                                      // M114 - Repport position

        Serial.print( "Absolute position : X = " );

        Serial.print( actuatorPos.x );

        Serial.print( "   -   Y = " );

        Serial.println( actuatorPos.y );

        break;

      default:

        Serial.print( "Command not recognized : M");

        Serial.println( buffer );

      }

    }

  }

 

}


//直线插补函数,参数为点坐标值

void drawLine(float x1, float y1)

{

  int dx, dy, n, k, i, f, stepInc;

  stepper_pulse = 150;              //设置步进电机写字时脉冲间隔

 

  if (x1 >= Xmax) {

    x1 = Xmax;

  }

  if (x1 <= Xmin) {

    x1 = Xmin;

  }

  if (y1 >= Ymax) {

    y1 = Ymax;

  }

  if (y1 <= Ymin) {

    y1 = Ymin;

  }

 

  x1 = (int)(x1/LEAD*stepsPerRevolution);

  y1 = (int)(y1/LEAD*stepsPerRevolution);

  float x0 = Xpos;

  float y0 = Ypos;

 

  //Serial.println(Xpos);

  //Serial.println(Ypos);

 

  dx = abs(x1-x0);

  dy = abs(y1-y0);

  n = abs(dx+dy);

 

  if(dx==0||dy==0)

  {

    stepInc = 1;

  }

  else

  {

    stepInc = 10;

  }


  if(x1 >= x0)

  {

    k = y1 >= y0 ? 1:4;

  }

  else

  {

    k = y1 >= y0 ? 2:3;

  }

 

  for(i=0,f=0;i<n;i+=stepInc)

  {

    if(f>=0)

    {

      switch(k)

      {

         case 1:

         step(X_DIR, X_STP, stepInc);

         f = f - dy;

         //Serial.println("+x");

         break;

         case 2:

         step(X_DIR, X_STP, -stepInc);

         f = f - dy;

         //Serial.println("-x");

         break;

         case 3:

         step(X_DIR, X_STP, -stepInc);

         f = f - dy;

         //Serial.println("-x");

         break;

         case 4:

         step(X_DIR, X_STP, stepInc);

         f = f - dy;

         //Serial.println("+x");

         break;

         default:break;

      }

    }

    else

    {

      switch(k)

      {

        case 1:

        step(Y_DIR, Y_STP, stepInc);

        f = f + dx;

        //Serial.println("+y");

        break;

        case 2:

        step(Y_DIR, Y_STP, stepInc);

        f = f + dx;

        //Serial.println("+y");

        break;

        case 3:

        step(Y_DIR, Y_STP, -stepInc);

        f = f + dx;

        //Serial.println("-y");

        break;

        case 4:

        step(Y_DIR, Y_STP, -stepInc);

        f = f +dx;

        //Serial.println("-y");

        break;

        default:break;

      }

    }

  }

  Xpos = x1;

  Ypos = y1;

}


/*

//函数:step    功能:控制步进电机方向,步数。

//参数:dirPin对应步进电机的DIR引脚,stepperPin 对应步进电机的step引脚, steps 步进的步数

//无返回值

*/

void step(byte dirPin, byte stepperPin, int steps)

{

  digitalWrite(EN, LOW);

  boolean DIR = steps>0 ? true : false;  

  digitalWrite(dirPin,DIR);

  for(int i=0;i<abs(steps); i++)

  {

    digitalWrite(stepperPin, HIGH);

    delayMicroseconds(stepper_pulse);

    digitalWrite(stepperPin, LOW);

    delayMicroseconds(stepper_pulse);

  }

  digitalWrite(EN, HIGH);

}


//步进电机复位函数

void resetStepper()

{

    stepper_pulse = 40; //设置步进电机复位脉冲间隔

   

    while(digitalRead(SENSOR_Z))

        step(Z_DIR,Z_STP,10);

    step(Z_DIR,Z_STP,-15);

while(digitalRead(SENSOR_X))

        step(X_DIR,X_STP,-10);

    step(X_DIR,X_STP,15);

while(digitalRead(SENSOR_Y))

    step(Y_DIR,Y_STP,10);

    step(Y_DIR,Y_STP,-15);


    //复位笔至平台中间位置,步数根据中间位置距离复位传感器的距离计算

    step(X_DIR, X_STP, 28000);

    step(Y_DIR, Y_STP, -16000);

    step(Z_DIR, Z_STP, -30000);

}

3.3 图形绘制

      接下来我们将通过上位机的processing软件发送生成文字“机器时代”的 gcode文件给三轴XYZ平台绘图仪进行图形绘制。

      首先将 软件资料包\processing-2.0b8.zip 文件解压到电脑上任意磁盘,然后打开processing.exe来启动 Processing 软件,之后按下图所示步骤进行操作:

使用三轴XYZ平台绘制空心字

使用三轴XYZ平台绘制空心字

      此时打开绘图仪电源开关,在英文输入法状态下按键盘P键,选择端口号,等待三轴XYZ平台绘图仪复位完毕,进入接收上位机指令状态;然后英文输入法状态下按键盘G键,选择之前生成的 gcode文件,点击确定,开始发送gcode文件代码,三轴XYZ平台绘图仪开始绘图;三轴XYZ平台绘图仪在绘图过程中,可以按X键来停止发送gcode文件代码。

注意事项:

① 关于绘图笔的安装,可以让绘图仪进入工作状态后关闭电源,此时安装绘图笔使其与纸面相接即可。

② 程序中步进电机使用的细分数为16细分,无细分时200步/圈,16细分即 3200步/圈。

③ 生成gcode坐标文件后,使用windows的笔记本或者Notepad++软件打开gcode文件,然后删除第一行和第二行,如下图所示:

使用三轴XYZ平台绘制空心字

4. 资料内容

①绘制空心字-例程源代码

②绘制空心字-样机3D文件

③软件资料包

资料内容详见:三轴XYZ平台-绘制空心字文章来源地址https://www.toymoban.com/news/detail-421140.html

到了这里,关于使用三轴XYZ平台绘制空心字的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 国标视频融合云平台EasyCVR视频汇聚平台的应用场景及其功能说明

    一、平台简介 EasyCVR国标视频融合云平台是一款基于端-边-云一体化架构的视频融合+AI智能分析网关平台。EasyCVR平台支持视频汇聚、融合管理,兼容多类型设备、多协议接入。其提供的视频功能包括:视频监控、无插件直播录像、云存储、检索回放、智能告警、平台级联、G

    2024年02月11日
    浏览(47)
  • valgrind基本功能介绍、基础使用方法说明 valgrind基本功能介绍、基础使用方法说明

    valgrind基本功能介绍、基础使用方法说明_valgrind使用方法_HNU Latecomer的博客-CSDN博客 拷贝效果不好,请看原文。 1、Valgrind概述 Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。 Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(f

    2024年02月07日
    浏览(61)
  • Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)

    在部分场景搭建中需要整齐摆放一些物品(如仓库中的货堆、货架等),因为有交互的操作在单个模型上,每次总是手动拖动模型操作起来也是繁琐和劳累。 在这背景下,我编写了一个在运行或者编辑状态下都可以进行一键排序模型的脚步。方便在场景搭建时,可以快速搭建

    2024年01月17日
    浏览(72)
  • Python绘制折线图、散点图...Pyplot库功能使用示例大全

    matplotlib.pyplot库是Python中一个非常重要的可视化工具,可以用于绘制各种图表。本文给出了图表绘制的各种示例 1、简单折线图示例 代码中首先导入了matplotlib.pyplot库和numpy库。生成了一些数据并使用plt.plot()函数绘制了折线图,同时使用plt.title()、plt.xlabel()和plt.ylabel() 函数为图

    2024年02月14日
    浏览(41)
  • 使用spss拆分文件功能轻松绘制论文数据基线表(sci表一)

    我们的论文分析时经常需要进行一个一般人群的数据基线表的统计分析,一般来说就是SCI论文中的表一,如下图 表中Q1-Q4为4个亚组,分别描述了每个亚组的均值和标准差,分类变量使用计数和百分比表示,最后还得出组间比较的P值,既往我们已经介绍了使用R语言多个R包绘制

    2024年02月15日
    浏览(40)
  • IP-Guard压缩包穿透加解密功能使用说明

    一、功能简介 增加压缩包穿透加解密功能,启用压缩包加解密穿透功能,用户在对压缩包文件进行加 解密时,加密系统会直接加密或者解密压缩包内的文件,而不是加解密压缩包文件本身。若 不启用压缩包加解密穿透功能,用户在对压缩包文件进行加解密时,加密系统会加

    2024年02月08日
    浏览(41)
  • Pyecharts教程(十一):使用Pyecharts绘制带有滑动数据缩放功能的K线图

    作者:安静到无声 个人主页 K线图是金融市场分析中常见的图表类型之一,它能够直观地展示价格的变化,并帮助分析人员对市场趋势进行预测。Pyecharts是Python一个强大的数据可视化库,提供了绘制各种图表的功能,包括K线图。本文将介绍如何使用Pyecharts绘制带有滑动数据缩

    2024年02月11日
    浏览(33)
  • Baumer工业相机堡盟工业相机软件CameraExplorer常见功能使用说明

    Baumer工业相机堡盟相机是一种高性能、高质量的工业相机,可用于各种应用场景,如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能,可以实时传输高分辨率图像。此外,该相机还具有快速数据传输、低功耗、易于集成以及高度可扩

    2024年02月04日
    浏览(45)
  • 详细接口和使用说明的FPGA IP实现VGA转HDMI功能

    FPGA实现VGA转HDMI功能的IP,配详细的接口和使用说明 ID:3440 718008093072 木若君熙 标题: FPGA实现VGA转HDMI功能的IP及其详细接口和使用说明 摘要: 本文针对FPGA(Field-Programmable Gate Array)实现VGA转HDMI功能的IP进行了详细的分析与说明。首先介绍了FPGA的基本原理和应用领域,然后详细介

    2024年04月25日
    浏览(37)
  • 快速开发web甘特图功能:MZGantt原生js甘特图插件使用说明

    MZGantt是一款原生js开发的甘特图插件。支持vue,ts,js等,支持流行的各种前端框架,可以快速引用到我们的web程序或者移动应用中。 拖拽编辑: 支持拖拽编辑 行内编辑: 支持行内编辑功能 弹框支持: 提供任务model,与外部弹框配合,完成任务编辑。 列自定义: 支持自定

    2024年04月17日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包