

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、ython3d_PythonCNC3D打印機python 3d打印機by Nikolay Khabarov通過尼古拉哈巴羅夫(Nikolay Khabarov)如何使 Python構建的 CNC控制器和 打印機 (How you can use Python to buildyour 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.本討論了
2、我來在純Python上構建第個CNC機床控制器實現的過程。Computer numerical control (CNC) machine controllers are typically implemented using the C or C+ programminglanguage. They run on OS-less or real-time operating systems with simple microcontrollers.計算機數控(CNC)機器控制器通常使C或C +編程語來實現。 它們在操作系統或具有簡單微控制器的實時操作系統上運。In this article,
3、 Ill 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 te
4、chnologies, solutions, andinfrastructures. This makes the whole project developer-friendly.這種現代法為與其他前沿技術,解決案和基礎架構的集成提供了泛的選擇。 這使整個項對開發員友好。 Modern ARM boards typically use Linux as a reference operating system. This gives us access to the entire Linuxinfrastructure with all the Linux software packages
5、. Wecan host a web server on a board, use Bluetooth connectivity, usefor image recognition, and build a cluster of boards, among other things.現代ARM板通常使Linux作為參考操作系統。 這使我們可以使所有Linux軟件包訪問整個Linux基礎結構。 我們可以在板上托管Web服務器,使藍連接,使進圖像識別以及構建板集群等。These are well-known tasks that can be implemented on ARM boards,
6、and they can be really useful for custom CNCmachines. 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 cant generate pulses with the required
7、 timings to control steppermotors directly from the board pins with running software, even as a kernel module. So, how can we use steppers and high-level Linux features? Wecan use two chips one microcontroller with a classic CNC implementation, and an ARM boardconnected to this microcontroller via U
8、ART (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 a
9、xes that arenot implemented in the microcontroller? Any modifications to the existing C/C+ firmware will require plenty ofdevelopment time and efforts. Lets see if we can make it easier and even save money on microcontrollers by simplyremoving them.如果該微控制器沒有合適的固件功能怎么辦? 如果我們需要控制微控制器中未實現的其他軸怎么辦? 對現有C
10、/ C +固件的任何修改都將需要量的開發時間和精。 讓我們看看是否可以通過簡單地刪除微控制器來使它變得更容易甚省錢。 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 anyb
11、oard and use everything that Linux offers. And you can keep the entire G-code runtime on one board without the need fora separate microcontroller for real-time operation.是個免費的開源性能G代碼解釋器和CNC / 3D打印機控制器。 它可以在各種基于Linux的基于ARM的板上運,例如RaspberryPi,Odroid,Beaglebone等。 這使您可以靈活地選擇任何板并使Linux提供的所有功能。 且,您可以將整個G代碼
12、運時保持在塊板上,需單獨的微控制器進實時操作。Choosing Python as the main programming language significantly reduces the code base compared to C/C+ projects. Italso reduces the boilerplate and microcontroller-specific code, and makes the project accessible to a wider audience.與C / C +項相,選擇Python作為主要編程語會減少代碼庫。 它還減少了樣板代碼和微控
13、制器特定的代碼,并使該項可供更泛的受眾使。 The project uses DMA (Direct Memory Access) on the chip hardware module. It simply copies the GPIO (General PurposeInput Output) states buffer allocated in RAM to the actual GPIO registers. This copying process is synchronized by thesystem clock and works completely independent
14、ly from the CPU cores. Thus, a sequence of pulses for the steppermotors axis is generated in memory and then the DMA precisely sends them out.該項在芯硬件模塊上使DMA(直接內存訪問)。 它僅將RAM中分配的GPIO(通輸輸出)狀態緩沖區復制到實際的GPIO寄存器。 該復制過程由系統時鐘同步,并且完全獨于CPU內核作。 因此,在內存中成了個于步進電機軸的脈沖序列,然后DMA精確地將其發送出去。Lets dig deeper into the code t
15、o understand the basics and how to access hardware modules from Python.讓我們深研究代碼以了解基礎知識以及如何從Python訪問硬件模塊。 A General Purpose Input Output module controls pin states. Each pin can have low or high state. When we program themicro-controller, we usually use SDK (software development kit) defined variable
16、s to write to that pin. For example, toenable 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,則會發現此
17、變量的聲明,它的外觀類似于:#define PORTA (*(volatile uint8_t *)(0 x12345678)Its just a pointer. It doesnt point to the location in RAM,but to the address of the physical processor. The actual GPIOmodule is located at this address.這只是個指針。 它不是指向RAM中的位置,是指向物理處理器的地址。 實際的GPIO模塊位于此地址。To manage pins, we can write and r
18、ead data. Raspberry Pis ARM processor is not an exception, and it has the samemodule. To control pins, we can write/read data. Wecan find the addresses and data structures in the for processorperipherals.要管理引腳,我們可以寫和讀取數據。 Raspberry Pi的ARM處理器也不例外,它具有相同的模塊。 為了控制引腳,我們可以寫/讀取數據。 我們可以在處理器外圍設備的找到地址和數據結構。Wh
19、en we run a process in the users runtime, the process starts in the virtual address space. The actual peripheral isaccessible directly. But we can still access real physical addresses with/dev/mem device.當我們在戶的運時中運個進程時,該進程在虛擬地址空間中啟動。 實際的外圍設備可直接訪問。 但是我們仍然可以使設備訪問真實的物理地址。Here is some simple code in Pyt
20、hon that controls a pins state using this approach:這是Python中的些簡單代碼,可以使這種法控制引腳的狀態:Lets break it down line by line:讓我們逐將其分解:Lines 16:headers, imports.第16 :標頭,導。Line 7:open/dev/memdevice access to the physical address.第7 :打開設備訪問物理地址。Line 8:we use the system call to map a file (though in our case, this
21、file represents physical memory) into the processsvirtual memory. Wespecify the length and offset of the map area. For the length, we take the page size. And the offset is0 x3F200000.第8 :我們使系統調將件(盡管在本例中,該件代表物理內存)映射到進程的虛擬內存中。 我們指定地圖區域的長度和偏移量。對于長度,我們采頁。 偏移量為0 x3F200000 。The documentation says that the
22、 bus 0 x7E200000 contains GPIO registers, and we need to specify the physicaladdress. The documentation says (page 6,paragraph 1.2.3) that the0 x7E000000 bus address is mapped to the0 x20000000physical address, but this documentation is for Raspberry 1.Please note that all module bus addresses are t
23、he same forRaspberry Pi 13,but this map was changed 0 x3F000000 for RPi 2 and 3.So, the address here is0 x3F200000. ForRaspberry Pi 1,change it to0 x20200000.該檔說總線地址0 x7E200000包含GPIO寄存器,我們需要指定物理地址。 檔說(第6頁,第1.2.3節),0 x7E000000總線地址已映射到0 x20000000物理地址,但是本檔適于Raspberry1。請注意,Raspberry Pi 1-3的所有模塊總線地址均相同,但
24、是對于RPi2和3,此映射已更改為0 x3F000000 。因此,此處的地址為0 x3F200000 。 對于Raspberry Pi 1,將其更改為0 x20200000 。After this, we can write to our processs virtual memory, but it actually writes to the GPIO module.此后,我們可以寫進程的虛擬內存,但實際上是寫GPIO模塊。Line 9:close the file handle, since we dont need to store it.第9 :關閉件句柄,因為我們不需要存儲它。Li
25、nes 1114:we read and write to our map with the0 x08 offset. According to the documentation, it is the GPFSEL2 GPIOFunction Select 2 register. And this register controls pin functions.第1114 :我們以0 x08偏移量讀寫地圖。 根據檔,它是GPFSEL2 GPIO功能選擇2寄存器。 該寄存器控制引腳功能。Weset (clear all, then set with the OR operator) 3 bit
26、s with the 3rd bit set to001. This value means that the pin works as anoutput. There are many pins and possible modes for them. This is why the register for modes is divided into severalregisters, where each contains the modes for 10 pins.我們設置(清除所有,然后OR運算符設置)3位,并將第3位設置為001 。 該值表該引腳作輸出。 有許多引腳和可能的模式。
27、這就是為什么模式寄存器分為個寄存器,每個寄存器包含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 doesnt have registers l
28、ike PORTA (AVR microcontrollers) have. Wecant write the whole GPIOstate 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:dela
29、y第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 filegpio.py and run it withsudo python gpio.py.
30、 If you have aLED connected to pin 21,it will blink.該代碼應以超級戶權限運。 將件命名為gpio.py并使sudo python gpio.py運它。 如果您有個LED連接到引腳21,它將閃爍。Direct Memory Access is a special module that is designed to copy memory blocks from one area to another. Wewill copydata from the memory buffer to the GPIO module. First of all
31、, we need a solid area in physical RAM that will be copied.直接內存訪問是個特殊的模塊,旨在將內存塊從個區域復制到另個區域。 我們將數據從內存緩沖區復制到GPIO模塊。 先,我們需要將要復制的物理RAM中的固定區域。There are few possible solutions:可能的解決案很少:1. Wecan create a simple kernel driver that will allocate, lock, and report to us the address of this memory.我們可以創建個簡單的內核
32、驅動程序,它將分配,鎖定并向我們報告該內存的地址。2. In some implementations, virtual memory is allocated and uses/proc/self/pagemap to convert the address to thephysical one. I wouldnt recommend this approach, especially when we need to allocate big area. Any virtually allocatedmemory (even locked, see the ) can be moved t
33、o 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
34、 of creating our own.所有的Raspberry /dev/vcio設備,該設備是圖形驅動程序的部分,可以為我們分配物理內存。 個官顯了如何執此操作。 且我們可以使它不是創建我們的。The DMA module itself is just a set of registers that are located somewhere at a physical address. Wecan control thismodule via these registers. Basically, there are source, destination, and control r
35、egisters. Lets check some simple codethat 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 CMAPhys
36、icalMemory class implementation. Wewill also use the PhysicalMemory class, which performs the trick with memapfrom the previous sample.由于額外的代碼需要分配物理內存/dev/vcio ,我們將使個與現有的CMA PhysicalMemory類實現。 我們還將使PhysicalMemory類,該類使上個例中的memap執技巧。Lets break it down line by line:讓我們逐將其分解:Lines 13:headers, imports.第1
37、3 :標頭,導。Lines 56:constants with the channelDMA number and GPIO pin that we will use.第5-6 :常量,我們將使通道DMA編號和GPIO引腳。Lines 815:initialize the specified GPIO pin as an output, and light it up for a half second for visual control. In fact, itsthe same thing we did in the previous example, written in a more
38、 pythonic way.第8-15 :將指定的GPIO引腳初始化為輸出,并點亮半秒以進可視控制。 實際上,這與我們在前的例中所做的相同,只是使了更多的Python語。Line 17:allocates64 bytes in physical memory.第17 :在物理內存中分配64個字節。Line 18:creates special structures control blocks for the DMA module. The following lines break the structure of thisblock. Each field has a length of3
39、2 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 callget_bus_address()
40、. The DMA control block must bealigned by 32 bytes, but the size of this block 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, its the address of the SET regist
41、er of the GPIO module.第21 :標地址。 在我們的例中,它是GPIO模塊的SET寄存器的地址。Line 22:transmission length 4 bytes.第22 :傳輸長度4個字節。Line 23:stride. Wedo not use this feature, set0.第23 :步向前。 我們不使此功能,設置為0。Line 24:address of the next control block, in our case, next 32 bytes.第24 :下個控制塊的地址,在本例中為下個32字節。Line 25:padding. But sinc
42、e we used this address as a data source, put a bit, which should trigger GPIO.第25 :填充。 但是,由于我們將此地址作數據源,因此請放置點,這將觸發GPIO。Line 26:padding.第26 :填充。Lines 2837:fill in the second DMA control block. The difference is that we write to CLEAR GPIO register and set our firstblock as a next control block to loo
43、p the transmission.第2837 :填寫第個DMA控制塊。 區別在于我們寫CLEAR GPIO寄存器,并將我們的第個塊設置為循環傳輸的下個控制塊。Lines 3839:write control blocks to physical memory.第3839 :將控制塊寫物理內存。Line 41:get the DMA module object with the selected channel.第41 :獲取具有所選通道的DMA模塊對象。Lines 4243:reset the DMA module.第4243 :重置DMA模塊。Line 44:specify the ad
44、dress of the first block.第44 :指定第個塊的地址。Line 45:run the DMA module.第45 :運DMA模塊。Lines 4952:clean up. Stop the DMA module and switch the GPIO pin to the default state.第4952 :清理。 停DMA模塊,并將GPIO引腳切換為默認狀態。Lets connect the oscilloscope to the specified pin and run this application (do not forget about sudo
45、privileges). Wewillobserve 1.5 MHzsquare pulses:讓我們將波器連接到指定的引腳并運該應程序(不要忘記sudo特權)。 我們將觀察到約1.5 MHz的波: There are several things that you should take into consideration before building a real CNC machine.在構建真正的CNC機床之前,您需要考慮件事。First, the size of the DMA buffer can be hundreds of megabytes.先,DMA緩沖區的可以為數百兆
46、字節。Second, the DMA module is designed for a fast data copying. If several DMA channels are working, we can go beyond thememory bandwidth, and buffer will be copied with delays that can cause jitters in the output pulses. So, its better to havesome synchronization mechanism.其次,DMA模塊設計于快速數據復制。 如果個DMA通
47、道正在作,我們將超出內存帶寬,緩沖區將被復制,延遲會導致輸出脈沖抖動。 因此,最好具有些同步機制。To overcome this, I created a special design for control blocks:為了克服這個問題,我為控制塊創建了個特殊的設計:The oscillogram at the top of the image shows the desired GPIO states. The blocks below represent the DMA control blocksthat generate this waveform. “Delay 1” spec
48、ifies the pulse length, and “Delay 2” is the pause length between pulses.With this approach, the buffer size depends only on the number of pulses.圖像頂部的波形圖顯了所需的GPIO狀態。 下的塊表產此波形的DMA控制塊。 “延遲1”指定脈沖長度,“延遲2”是脈沖之間的暫停長度。 使這種法,緩沖區僅取決于脈沖數。For example, for a machine with 200mm travel length and 400 pulses per
49、mm,each pulse would take 128 bytes (4 controlblocks per 32 bytes), and the total size will be 9.8MB. Wewould have more than one axis, but most of the pulses wouldoccur at the same time. And it would be dozens of megabytes, not hundreds.例如,對于程長度為200mm的機器和每毫400個脈沖的機器,每個脈沖將占128字節(每32字節4個控制塊),總約為9.8MB。我
50、們將有多個軸,但多數脈沖將同時發。 它將是兆字節,不是數百兆字節。I solved the second challenge, related to synchronization, by introducing temporary delays through the control blocks. TheDMA module has a special feature: it can wait for a special ready signal from the module where it writes data. The mostsuitable module for us is
51、the PWM (pulse width modulation) module, which will also help us with synchronization.我通過在控制塊中引了臨時延遲來解決了與同步有關的第個挑戰。 DMA模塊具有個特殊功能:它可以等待來其寫數據的模塊的特殊就緒信號。 最適合我們的模塊是PWM(脈沖寬度調制)模塊,它也將幫助我們進同步。The PWM module can serialize the data and send it with fixed speed. In this mode, it generates a ready signal for t
52、he FIFO(first in, first out) buffer of the PWM module. So, lets write data to the PWM module and use it only for synchronization.PWM模塊可以序列化數據并以固定速度發送。 在這種模式下,它將為PWM模塊的FIFO(先進先出)緩沖器成就緒信號。 因此,讓我們將數據寫PWM模塊,并將其僅于同步。Basically, we would need to enable a special flag in the perceptual mapping of the transf
53、er information flag, and then run thePWM module with the desired frequency. The implementation is quite long you can it yourself.基本上,我們需要在傳輸信息標志的感知映射中啟特殊標志,然后以所需的頻率運PWM模塊。 實現時間很長-您可以 。Instead, lets create some simple code that can use the existing module to generate precise pulses.相反,讓我們創建些簡單的代碼,可以使
54、現有模塊成精確的脈沖。import rpgpioPIN=21PINMASK = 1 PINPULSE_LENGTH_US = 1000PULSE_DELAY_US = 1000DELAY_US = 2000 g = rpgpio.GPIO()g.init(PIN, rpgpio.GPIO.MODE_The code is pretty simple, and there is no need to break it down. If you run this code and connect an oscilloscope, you willsee:代碼很簡單,不需要分解。 如果運此代碼并連接
55、波器,則會看到:And now we can create real G-code interpreter and control stepper motors. But wait! It is already implemented . You can usethis project, as its distributed under the MIT license.現在,我們可以創建真正的G代碼解釋器并控制步進電機。 可是等等! 它已經實現。 您可以使此項,因為它是根據MIT許可證分發的。 The Python project can be adopted for your purpose
56、s. But in order to inspire you, I will describe the original hardwareimplementation of this project a 3D printer. It basically contains the following components:可以根據需要使Python項。 但是為了激發您的靈感,我將介紹該項的原始硬件實現-3D打印機。 它基本上包含以下組件:1. Raspberry Pi 3樹莓派32.3. 4 A4988 or DRV8825 module4個A4988或DRV8825模塊4. RepRap Pr
57、usa i3 frame with equipment (end-stops, motors, heaters, and sensors)RepRap Prusa i3框架,帶設備(終端擋塊,電機,加熱器和傳感器)5. 12V 15A power supply unit12V 15A電源單元6. LM2596S DC-DC step down converter moduleLM2596S DC-DC降壓轉換器模塊7. MAX4420 chipMAX4420芯8. ADS1115 analog to digital converter moduleADS1115模數轉換器模塊9. UDMA13
58、3 IDE ribbon cableUDMA133 IDE帶狀電纜10. Acrylic glass亞克玻璃11. PCB standsPCB架12. Set of connectors with 2.54mm step組2.54mm臺階的連接器The 40-pin IDE ribbon cable is suitable for the Raspberry Pi 40 pins connector, but the opposite end requires some work.Cut off the existing connector from the opposite end and
59、crimp connectors to the cable wires.40針IDE帶狀電纜適于Raspberry Pi 40針連接器,但另端需要做些作。 從相反的端切斷現有的連接器,然后將連接器壓接到電纜上。The RAMPSv1.4 board was originally designed for connection to the Mega connector, so there is no easy way to connectthis board to the Raspberry Pi. The following method allows you to simplify the
60、 boards connection. You will need to connectless than 40 wires.RAMPSv1.4開發板最初是為連接 Mega連接器設計的,因此沒有簡便的法將該開發板連接Raspberry Pi。 以下法可以簡化電路板的連接。 您將需要連接少于40根電線。I hope this connection diagram is fairly simple and easily duplicated. Its better to connect some pins (2nd extruder,servos) for future use, even if
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 政委聘用合同協議
- 閃送團隊合同協議
- 旋轉收納合同協議
- 選擇法院協議合同
- 物流經營合同協議
- 生產月結合同協議
- 相親公司合同協議
- 直腸癌的健康教育
- 商鋪樓房買賣協議書
- 直播崗位合同協議
- 配電箱巡檢表
- 廣東省廣州市2024年中考英語真題(含答案)
- 英語國家概況:Chapter-10-Government(美國政府)
- 金屬加工基礎知識考試考核試卷
- DB23T 3840-2024 非煤礦山隱蔽致災因素普查治理工作指南
- 2024年建設工程質量檢測人員-建設工程質量檢測人員(使用功能)考試近5年真題集錦(頻考類試題)帶答案
- 專題03二元一次方程(組)中含參數問題壓軸題三種模型全(原卷版)
- 龐貝病護理教學查房
- 第3節 第2課時 理想氣體狀態方程和氣體實驗定律的微觀解釋 教學課件
- 人教版初中數學《等腰三角形》-課件-
- 【必刷題型07】機械能守恒與能量守恒問題(原卷版)
評論
0/150
提交評論