python3d打印机_如何使用Python构建自己的CNC控制器和3D打印机

python3d打印机_如何使⽤Python构建⾃⼰的CNC控制器和3D
打印机
python 3d打印机
by Nikolay Khabarov
通过尼古拉·哈巴罗夫(Nikolay Khabarov)
如何使⽤Python构建⾃⼰的CNC控制器和3D打印机 (How you can use Python to build your own CNC controller and 3D printer)
This article discusses the process I used to build the first ever CNC machine controller implementation on pure Python.
本⽂讨论了我⽤来在纯Python上构建第⼀个CNC机床控制器实现的过程。
Computer numerical control (CNC) machine controllers are typically implemented using the C or C++ programming language. They run on OS-less or real-time operating systems with simple microcontrollers.
计算机数控(CNC)机器控制器通常使⽤C或C ++编程语⾔来实现。 它们在⽆操作系统或具有简单微控制器的实时操作系统上运⾏。
In this article, I’ll describe how to build a CNC controller — a 3D printer in particular — using modern ARM boards (Raspberry Pi) with a modern high level language (Python).
在本⽂中,我将介绍如何使⽤具有现代⾼级语⾔(Python)的现代ARM板(树莓派)来构建CNC控制器(尤其是3D打印机)。
Such a modern approach opens a wide range of integration options with other cutting edge technologies, solutions, and infrastructures. This makes the whole project developer-friendly.
这种现代⽅法为与其他前沿技术,解决⽅案和基础架构的集成提供了⼴泛的选择。 这使整个项⽬对开发⼈员友好。
关于该项⽬ (About the Project)
Modern ARM boards typically use Linux as a reference operating system. This gives us access to the entire Linux infrastructure with all the Linux software packages. We can host a web server on a board, use Bluetooth connectivity, use for image recognition, and build a cluster of boards, among ot
her things.
现代ARM板通常使⽤Linux作为参考操作系统。 这使我们可以使⽤所有Linux软件包访问整个Linux基础结构。 我们可以在板上托管Web 服务器,使⽤蓝⽛连接,使⽤进⾏图像识别以及构建板集等。
These are well-known tasks that can be implemented on ARM boards, and they can be really useful for custom CNC machines. For example, auto-positioning using compuvision can be very handy for some machines.
这些是可以在ARM板上执⾏的众所周知的任务,它们对于⾃定义CNC机器⾮常有⽤。 例如,对于某些机器,使⽤compupvision⾃动定位可能⾮常⽅便。
Linux is not a real-time operating system. This means we can’t generate pulses with the required timings to control stepper motors directly from the board pins with running software, even as a kernel module. So, how can we use steppers and high-level Linux features? We can use two chips — one microcontroller with a classic CNC implementation, and an ARM board connected to this microcontroller via UART (universal asynchronous receiver-transmitter).
Linux不是实时操作系统。 这意味着我们⽆法使⽤运⾏软件(甚⾄是内核模块)从具有所需时序的脉冲直
接从板针直接控制步进电机。 那么,我们如何使⽤步进器和⾼级Linux功能? 我们可以使⽤两块芯⽚-⼀个具有经典CNC实现的微控制器,以及⼀个通过UART(通⽤异步收发器)连接到该微控制器的ARM板。
What if there are no suitable firmware features for this microcontroller? What if we need to control additional axes that are not implemented in the microcontroller? Any modifications to the existing C/C++ firmware will require plenty of development time and efforts. Let’s see if we can make it easier and even save money on microcontrollers by simply removing them.
如果该微控制器没有合适的固件功能怎么办? 如果我们需要控制微控制器中未实现的其他轴怎么办? 对现有C / C ++固件的任何修改都将需要⼤量的开发时间和精⼒。 让我们看看是否可以通过简单地删除微控制器来使它变得更容易甚⾄省钱。
氯化萘 (PyCNC)
is a free open-source high-performance G-code interpreter and CNC/3D-printer controller. It can run on various Linux-powered, ARM-based boards, such as Raspberry Pi, Odroid, Beaglebone, and others. This gives you the flexibility to pick any board and use everything that Linux offers. And you can keep the entire G-code runtime on one board without the need for a separate microcontroller for
real-time operation.
是⼀个免费的开源⾼性能G代码解释器和CNC / 3D打印机控制器。 它可以在各种基于Linux的基于ARM的板上运⾏,例如Raspberry
Pi,Odroid,Beaglebone等。 这使您可以灵活地选择任何板并使⽤Linux提供的所有功能。 ⽽且,您可以将整个G代码运⾏时保持在⼀块板上,⽽⽆需单独的微控制器进⾏实时操作。
Choosing Python as the main programming language significantly reduces the code base compared to C/C++ projects. It also reduces the boilerplate and microcontroller-specific code, and makes the project accessible to a wider audience.
与C / C ++项⽬相⽐,选择Python作为主要编程语⾔会⼤⼤减少代码库。 它还减少了样板代码和微控制器特定的代码,并使该项⽬可供更⼴泛的受众使⽤。
这个怎么运作 (How it works)
The project uses DMA (Direct Memory Access) on the chip hardware module. It simply copies the GPIO (General Purpose Input Output) states buffer allocated in RAM to the actual GPIO registers. This copying process is synchronized by the system clock and works completely independently from
the CPU cores. Thus, a sequence of pulses for the stepper
motor’s axis is generated in memory and then the DMA precisely sends them out.
该项⽬在芯⽚硬件模块上使⽤DMA(直接内存访问)。 它仅将RAM中分配的GPIO(通⽤输⼊输出)状态缓冲区复制到实际的GPIO寄存器。 该复制过程由系统时钟同步,并且完全独⽴于CPU内核⽽⼯作。 因此,在内存中⽣成了⼀个⽤于步进电机轴的脉冲序列,然后DMA精确地将其发送出去。三门峡工程
Let’s dig deeper into the code to understand the basics and how to access hardware modules from Python.
让我们深⼊研究代码以了解基础知识以及如何从Python访问硬件模块。
通⽤输⼊输出 (GPIO)
A General Purpose Input Output module controls pin states. Each pin can have low or high state. When we program the micro-controller, we usually use SDK (software development kit) defined variables to write to that pin. For example, to
enable a high state for pins 1 and 3:
通⽤输⼊输出模块控制引脚状态。 每个引脚可以具有低电平或⾼电平状态。 对微控制器进⾏编程时,通常使⽤SDK(软件开发套件)定义的变量来写⼊该引脚。 例如,要使引脚1和3处于⾼电平状态:
PORTA = (1 << PIN1) | (1 << PIN3)
If you look in the SDK, you will find the declaration of this variable, and it will look similar to:
如果查看SDK,则会发现此变量的声明,它的外观类似于:
#define PORTA (*(volatile uint8_t *)(0x12345678))
It’s just a pointer. It doesn’t point to the location in RAM, but to the address of the physical processor. The actual GPIO module is located at this address.
这只是⼀个指针。 它不是指向RAM中的位置,⽽是指向物理处理器的地址。 实际的GPIO模块位于此地址。
To manage pins, we can write and read data. Raspberry Pi’s ARM processor is not an exception, and it has the same module. To control pins, we can write/read data. We can find the addresses and data structures in the for processor peripherals.
要管理引脚,我们可以写⼊和读取数据。 Raspberry Pi的ARM处理器也不例外,它具有相同的模块。 为了控制引脚,我们可以写⼊/读取数据。 我们可以在处理器外围设备的到地址和数据结构。
经济研究导刊
When we run a process in the user’s runtime, the process starts in the virtual address space. The actual peripheral is accessible directly. But we can still access real physical addresses with ‘/dev/mem’ device.
当我们在⽤户的运⾏时中运⾏⼀个进程时,该进程在虚拟地址空间中启动。 实际的外围设备可直接访问。 但是我们仍然可以使
⽤'/dev/mem'设备访问真实的物理地址。
Here is some simple code in Python that controls a pin’s state using this approach:
这是Python中的⼀些简单代码,可以使⽤这种⽅法控制引脚的状态:
教授女儿的婚事Let’s break it down line by line:
让我们逐⾏将其分解:
Lines 1–6: headers, imports.
第1⾄6⾏ :标头,导⼊。
Line 7: open ‘/dev/mem’ device access to the physical address.
第7⾏ :打开'/dev/mem'设备访问物理地址。
Line 8: we use the system call to map a file (though in our case, this file represents physical memory) into the process’s virtual memory. We specify the length and offset of the map area. For the length, we take the page size. And the offset is
0x3F200000.
第8⾏ :我们使⽤系统调⽤将⽂件(尽管在本例中,该⽂件代表物理内存)映射到进程的虚拟内存中。 我们指定地图区域的长度和偏移量。对于长度,我们采⽤页⾯⼤⼩。 偏移量为0x3F200000 。
The documentation says that the bus address 0x7E200000 contains GPIO registers, and we need to specify the physical address. The documentation says (page 6, paragraph 1.2.3) that the 0x7E000000 bus address is mapped to the 0x20000000 physical address, but this documentation is for Raspberry 1. Please note that all module bus addresses are the same for Raspberry Pi 1–3, but this map was changed to 0x3F000000 for RPi 2 and 3. So, the address here is 0x3F200000. For Ra
spberry Pi 1, change it to 0x20200000.
该⽂档说总线地址0x7E200000包含GPIO寄存器,我们需要指定物理地址。 ⽂档说(第6页,第1.2.3节), 0x7E000000总线地址已映射
到0x20000000物理地址,但是本⽂档适⽤于Raspberry1。请注意,Raspberry Pi 1-3的所有模块总线地址均相同,但是对于RPi 2和3,此映射已更改为0x3F000000 。因此,此处的地址为0x3F200000 。 对于Raspberry Pi 1,将其更改为0x20200000 。
After this, we can write to our process’s virtual memory, but it actually writes to the GPIO module.
此后,我们可以写⼊进程的虚拟内存,但实际上是写⼊GPIO模块。
Line 9: close the file handle, since we don’t need to store it.
第9⾏ :关闭⽂件句柄,因为我们不需要存储它。
Lines 11–14: we read and write to our map with the 0x08 offset. According to the documentation, it is the GPFSEL2 GPIO Function Select 2 register. And this register controls pin functions.
第11⾄14⾏ :我们以0x08偏移量读写地图。 根据⽂档,它是GPFSEL2 GPIO功能选择2寄存器。 该寄存器控制引脚功能。
We set (clear all, then set with the OR operator) 3 bits with the 3rd bit set to 001. This value means that the pin works as an output. There are many pins and possible modes for them. This is why the register for modes is divided into several registers, where each contains the modes for 10 pins.
我们设置(清除所有,然后⽤OR运算符设置)3位,并将第3位设置为001 。 该值表⽰该引脚⽤作输出。 有许多引脚和可能的模式。 这就是为什么模式寄存器分为⼏个寄存器,每个寄存器包含10个引脚的模式的原因。
Lines 16 and 22: set up the ‘Ctrl+C’ interruption handler.
第16和22⾏ :设置“ Ctrl + C”中断处理程序。
Line 17: infinite loop.
第17⾏ :⽆限循环。
Line 18: set the pin to the high state by writing to the GPSET0 register.
第18⾏ :通过写⼊GPSET0寄存器将引脚设置为⾼电平状态。
Please note, Raspberry Pi doesn’t have registers like PORTA (AVR microcontrollers) have. We can’t write the whole GPIO state of all pins. There are just set and clear registers which are used to set and clear specified with bitwise mask pins.
请注意,Raspberry Pi没有像PORTA(AVR微控制器)那样的寄存器。 我们不能写所有引脚的整个GPIO状态。 仅有设置和清除寄存器,⽤于设置和清除按位屏蔽引脚指定的寄存器。
Lines 19 and 21: delay
第19和21⾏ :延迟
Line 20: set pin to low state with the GPCLR0 register.
第20⾏ :使⽤GPCLR0寄存器将引脚设置为低电平状态。
Lines 25 and 26: switch pin to default, input state. Close the memory map.
第25和26⾏ :将引脚切换为默认输⼊状态。 关闭内存映射。
This code should be run with superuser privileges. Name the file ‘gpio.py’ and run it with ‘sudo python gpio.py’. If you have a LED connected to pin 21, it will blink.
该代码应以超级⽤户权限运⾏。 将⽂件命名为'gpio.py'并使⽤'sudo python gpio.py'运⾏它。 如果您有⼀个LED连接到引脚21,它将闪烁。DMA (DMA)
Direct Memory Access is a special module that is designed to copy memory blocks from one area to another. We will copy data from the memory buffer to the GPIO module. First of all, we need a solid area in physical RAM that will be copied.
直接内存访问是⼀个特殊的模块,旨在将内存块从⼀个区域复制到另⼀个区域。 我们将数据从内存缓冲区复制到GPIO模块。 ⾸先,我们需要将要复制的物理RAM中的固定区域。
There are few possible solutions:
可能的解决⽅案很少:
1. We can create a simple kernel driver that will allocate, lock, and report to us the address of this memory.
我们可以创建⼀个简单的内核驱动程序,它将分配,锁定并向我们报告该内存的地址。
2. In some implementations, virtual memory is allocated and uses ‘/proc/self/pagemap’ to convert the address to the
physical one. I wouldn't recommend this approach, especially when we need to allocate big area. Any virtually allocated memory (even locked, see the ) can be moved to the physical area.
在某些实现中,虚拟内存被分配并使⽤'/proc/self/pagemap'将地址转换为物理地址。 我不推荐这种⽅法,特别是当我们需要分配⼤⾯积的时候。 任何虚拟分配的内存(即使已锁定,也请参阅 )都可以移⾄物理区域。
气浮垫3. All Raspberry Pi have a ‘/dev/vcio’ device, which is a part of the graphic driver and can allocate physical memory for us.
An official shows how to do it. And we can use it instead of creating our own.
所有的Raspberry Pi都有⼀个'/dev/vcio'设备,该设备是图形驱动程序的⼀部分,可以为我们分配物理内存。 ⼀个官⽅显⽰了如何执⾏此操作。 ⽽且我们可以使⽤它⽽不是创建我们⾃⼰的。
The DMA module itself is just a set of registers that are located somewhere at a physical address. We can control this module via these registers. Basically, there are source, destination, and control r
egisters. Let’s check some simple code that shows how to use the DMA modules to manage the GPIO.
DMA模块本⾝就是⼀组位于物理地址某处的寄存器。 我们可以通过这些寄存器控制此模块。 基本上,有源,⽬标和控制寄存器。 让我们检查⼀些简单的代码,这些代码显⽰了如何使⽤DMA模块来管理GPIO。
Since additional code is required to allocate physical memory with ‘/dev/vcio’, we will use a with an existing CMA PhysicalMemory class implementation. We will also use the PhysicalMemory class, which performs the trick with memap from the previous sample.
由于额外的代码需要分配物理内存'/dev/vcio' ,我们将使⽤⼀个与现有的CMA PhysicalMemory类实现。 我们还将使⽤PhysicalMemory 类,该类使⽤上⼀个⽰例中的memap执⾏技巧。
舌骨
Let’s break it down line by line:
让我们逐⾏将其分解:
Lines 1–3: headers, imports.
第1⾄3⾏ :标头,导⼊。
Lines 5–6: constants with the channel DMA number and GPIO pin that we will use.
第5-6⾏ :常量,我们将使⽤通道DMA编号和GPIO引脚。
Lines 8–15: initialize the specified GPIO pin as an output, and light it up for a half second for visual control. In fact, it’s the same thing we did in the previous example, written in a more pythonic way.
第8-15⾏ :将指定的GPIO引脚初始化为输出,并点亮半秒以进⾏可视控制。 实际上,这与我们在前⾯的⽰例中所做的相同,只是使⽤了更多的Python语⾔。
Line 17: allocates 64 bytes in physical memory.
第17⾏ :在物理内存中分配64个字节。
Line 18: creates special structures — control blocks for the DMA module. The following lines break the structure of this block. Each field has a length of 32 bit.
第18⾏ :创建特殊结构-DMA模块的控制块。 以下⼏⾏中断了此块的结构。 每个字段的长度为32位。
Line 19: transfers information flags. You can find a full description of each flag on page 50 of the official documentation.第19⾏ :传输信息标志。 您可以在官⽅⽂档的第50页上到每个标志的完整说明。
Line 20: source address. This address must be a bus address, so we call get_bus_address(). The DMA control block must be aligned by 32 bytes, but the size of this block is 24 bytes. So we have 8 bytes, which we use as storage.
第20⾏ :源地址。 该地址必须是总线地址,因此我们调⽤get_bus_address() 。 DMA控制块必须对齐32个字节,但是此块的⼤⼩为24个字节。 因此,我们有8个字节,⽤作存储空间。
Line 21: destination address. In our case, it’s the address of the SET register of the GPIO module.
第21⾏ :⽬标地址。 在我们的例⼦中,它是GPIO模块的SET寄存器的地址。
受弯构件挠度Line 22: transmission length — 4 bytes.
第22⾏ :传输长度4个字节。
Line 23: stride. We do not use this feature, set 0.

本文发布于:2024-09-22 07:23:39,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/15632.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

上一篇:Cortex-M3的优势
标签:引脚   寄存器   内存   地址   控制
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议