内容目录

   用fischertechnik(慧鱼创意组合模型)和Arduino制作的极坐标绘图机,使用G-code,它可以绘制任何位图或矢量图形。

APP与在线服务

         

 ARDUINO IDE           Microsoft Visual Studio 2015

关于这个项目:

基本思路:

“正常”绘图仪有两个线性轴,并用笛卡尔坐标控制。与这些机器不同,极坐标绘图机只具有一个线性轴,第二个轴用旋转板代替。因此,这个绘图机是用极坐标控制的。纸上的任何点都可以用一个角度和一个半径来描述,即点与旋转板的中心之间的距离。

从技术上讲,这个特性会带来一些困难,因为几乎没有任何CNC软件可以处理极坐标。

然而,我解决了困难,开发了我自己的极坐标绘图机:

正在绘制老虎的极坐标绘图机

主要部分:

  • 旋转板调整角度φ
  • 线性轴到半径R
  • 钢笔升降机构
  • 基于Arduino Mega的可用微控制器

旋转板

画纸卡在转盘上,通过旋转板,可以调整角度φ,旋转板由NEMA 17步进电机驱动,允许快速准确定位。

旋转板分解视图

直线轴

线性轴主要由fischertechnik组成。这一措施节省了3D打印成本和时间。此外,模型还可以在其他项目中重复使用。

直线轴由NEMA 14步进电机驱动。与NEMA 17电机不同,它具有较小的扭矩,较高的转速,这是必不可少的,因为在螺纹上进行高速齿轮传动。虽然步进电机允许精确定位,但需要一个限位开关来设置校准点的参考点。

控制器

控制器本身可以是一个项目,因为它是一个具有集成电机驱动器的即插即用控制器。它专注于控制fischertechnik硬件,如直流电机和各种不同的传感器。

fischertechnik硬件做的即插即用控制器

软件

如何用位图绘图?

步骤1:在Inkskape中打开位图,对其进行矢量化,并将其导出为 .dxf文件

步骤2:用CAM处理生成G-Code

步骤3:由笛卡尔坐标组成,G-Code必须被传输到极坐标。因此,我写了一个java小程序。

步骤4:将极性G-Code传到绘图机。为了执行命令,Arduino运行G-Code解释器。它控制步进电机,使绘图机在纸上进行绘制。

更多视频

相关代码

plotter_firmaware_3_1.ino (下载22 )
#include <MegaDueShield.h>

#define BUFFER_SIZE 1200
#define RAXIS_ZERO 2822 // Kugelschreiber

/*  Plotter Firmware 3_1
     
     March, 2017

     requires a G-code preprocessor
     requires C# App to load G-code

     G-code is transferred while drawing
     optimized parallelization of serial communication and drawing
     optimized serial communication

*/

StepperMotor & nema14 = *shield.getStepper(1);
StepperMotor & nema17 = *shield.getStepper(2);

DCMotor & stift = *shield.getDCMotor(1);

long posn14 = 0;
long posn17 = 0;

uint8_t lastCommand = 0;
boolean complete = false;
uint8_t commands[BUFFER_SIZE];
int commandPos[BUFFER_SIZE][2];

/*  G-Code commands:
   G00: Rapid positioning
   G01: Linear interpolation
   G02: Circular interpolation, clockwise
   G03: Circular interpolation, counterclockwise

   M03: Spindle on: Pen down
   M05: Spindle off: Pen up
*/

/* 11 Umdrehungen = 52,3mm
   2200 Schritte = 52,3mm
   1mm = 41,35338 Schritte

   r = 0mm: 2843 Schritte
   pos (r) = 2843 - r * 41,35338
*/

long rToPos(float r)
{
  return RAXIS_ZERO - (r * 41.885);
}

int rStepsToPos(int steps)
{
  return RAXIS_ZERO - steps;
}

/* 2Pi = 1800 Schritte

   pos (phi) = phi / 2Pi * 1800
*/

long phiToPos(float phi)
{
  while (posn17 >= 1800)
  {
    posn17 -= 1800;
  }
  while (posn17 < 0)
  {
    posn17 += 1800;
  }
  float posf = phi / 2.0 / PI * 1800;
  long pos = (long) posf;

  if (pos - posn17 > 900)
  {
    pos -= 1800;
  }

  if (posn17 - pos > 900)
  {
    pos += 1800;
  }
  return pos;
}

int phiStepsToPos(int steps)
{
  while (posn17 >= 1800)
  {
    posn17 -= 1800;
  }
  while (posn17 < 0)
  {
    posn17 += 1800;
  }
  if (steps - posn17 > 900)
  {
    steps -= 1800;
  }

  if (posn17 - steps > 900)
  {
    steps += 1800;
  }
  return steps;
}

void homeR()
{
  int counter = 0;
  while (!digitalRead(D4))
  {
    long pos = posn14 - 1;
    bool t = false;
    while (!t) {
      t = nema14.stepping(posn14, pos);
    }
    counter++;
  }
  posn14 = 0;
  //Serial.println("Referenzpunkt");
  //Serial.println(counter);
}

void penZ(bool value)
{

  if (value)
  {
    // Pen up
    while (digitalRead(C4) != 1)
    {
      stift.ccw(200);
    }
    stift.stop();
  }
  else
  {
    // Pen down
    stift.cw(200);
    delay(500);
    stift.stop();
  }
}

bool findCharacter(char character)
{
  if (Serial.available() > 0)
  {
    char serialCharacter = Serial.read();
    if (serialCharacter == character)
    {
      return true;
    }
  }
  return false;
}

int parseInteger()
{
  bool delimiter = false;
  int returnInt = 0;
  while (!delimiter)
  {
    while(Serial.available() < 1) {}
    int character = (int) Serial.read();
    character -= 48;
    if(character >= 0 && character <= 9)
    {
      returnInt *= 10;
      returnInt += character;
    }
    else
    {
      delimiter = true;
    }
  }
  return returnInt;
}

bool readGCodeLine(uint8_t & command, int arguments[])
{
  //int arguments[2];
  Serial.print('n');
  Serial.print('\n');
  Serial.flush();
  while (!findCharacter('G')) {}
  command = parseInteger();
  switch (command) {
    case 0:
      while (!findCharacter('P')) {}
      arguments[0] = parseInteger();
      while (!findCharacter('R')) {}
      arguments[1] = parseInteger();
      break;
    case 8:
      complete = true;
      break;
    case 9:
      while (!findCharacter('Z')) {}
      arguments[0] = parseInteger();
      break;
  }
}

bool stepwiseReadGCodeLine(uint8_t & milestone, uint8_t & command, int arguments[])
{
  switch (milestone)
  {
    case 0:
      Serial.print('n');
      Serial.print('\n');
      Serial.flush();
      milestone++;
      return false;
    case 1:
      if (Serial.available() > 0) {
        milestone++;
      }
      return false;
    case 2:
      if (findCharacter('G'))
      {
        milestone++;
      }
      return false;
    case 3:
      command = parseInteger();
      milestone++;
      return false;
    case 4:
      switch (command)
      {
        case 0:
          milestone = 5;
          break;
        case 8:
          complete = true;
          milestone = 8;
          break;
        case 9:
          milestone = 7;
          break;
      }
      return false;
    case 5:
      if (findCharacter('P'))
      {
        arguments[0] = parseInteger();
        milestone++;
      }
      return false;
    case 6:
      if (findCharacter('R'))
      {
        arguments[1] = parseInteger();
        milestone = 8;
      }
      return false;
    case 7:
      if (findCharacter('Z'))
      {
        arguments[0] = parseInteger();
        milestone = 8;
      }
      return false;
    case 8:
      return true;
  }
}

void processGCode()
{
  uint8_t command;
  int arguments[2];
  int nextArguments[2];
  uint8_t milestone = 0;

  while(!findCharacter('s')) {}

  readGCodeLine(command, arguments);  // get first G-code line
  nema14.wakeUp();
  delay(10);
  while (!complete)
  {
    bool t = false;
    milestone = 0;
    switch (command)
    {
      case 0:
        while (!t) {
          t = nema14.stepping(posn14, rStepsToPos(arguments[1]));
          t &= nema17.stepping(posn17, phiStepsToPos(arguments[0]));
          t &= stepwiseReadGCodeLine(milestone, command, nextArguments);
        }
        arguments[0] = nextArguments[0];
        arguments[1] = nextArguments[1];
        break;
      case 9:
        penZ(arguments[0]);
        readGCodeLine(command, arguments);
        break;
      case 8:
        break;
    }
  }
}

void setup() {
  Serial.begin(115200);

  delay(1000);
  nema14.motorConfig(200, 190, 600, 400);
  nema17.motorConfig(200, 120, 280, 400);

  // Stift
  pinMode(C4, INPUT_PULLUP);
  penZ(1);

  // R-Achse
  pinMode(D4, INPUT_PULLUP);
  homeR();
  while (!nema17.stepping(posn17, 900)) {}
  posn17 = 0;
  nema14.release();

  delay(400);

  //fahren();
  complete = false;
  processGCode();
  int p = posn17 + 900;
  bool t = false;
  while (!t)
  {
    t = nema17.stepping(posn17, p);
    t &= nema14.stepping(posn14, 50);
  }
  nema14.release();
}

void loop() {
  // put your main code here, to run repeatedly:

}

定制零件和外壳

gear_wENW3QXap7.stl (下载29 )

https://skfb.ly/6yyQP

翻译: DaStudio

原文链接: Arduino Project Hub

dastudio

By dastudio

You are not special.

发表评论