Designing End Node for LoRa

The aim was to develop a small end node capable of reading some sensors and send the information through LoRa. Furthermore the end node is battery powered so power consumption plays an important role.

1 – Hardware

These are the main hardware components used on the node:

  1. PIC18F27J53 Microcontroller – This microcontroller has several low power features like “Deep Sleep Mode” and “Deep Sleep Watch Dog Timer” both used during this project.
  2. RFM98W LoRa transceiver from HOPERF.
  3. Voltage regulator – Initially the TC1015-3.3V from Microchip was selected because its low quiescent Current of 50uA. Later on, it was changed to an alternative part from Micrel the MIC5504-3.3. The Micrel is cheaper and has a lower quiescent current of typically 38uA.

The board exposes the typical communications ports such as: serial, i2C and 1-Wire. It is also possible to measure the battery voltage and cut power to the all peripherals including the resistors used to monitor the battery voltage.

For the enclosure I wanted to use something that was readily available. I had seen PVC piping being used for this purpose before so I’ve decided to use it. The board shape and dimensions are such that they can be mounted on a 50mm PVC tube cap. The board is glued to the PVC cap with the SMA connector protrudingp from the top to mount the antenna.

This should provide a water free enclosure shouldn’t it? (it hasn’t!)

A DS18B20 1-Wire temperature sensor was mounted at the bottom using a cable gland. The PVC piping acting as a pole was milled to have 4 slots allowing air to pass through as illustrated on the following picture.

2 – Firmware

Firmware was developed in C using MPLAB X and XC8. For the LoRa module I’ve used RadioHead ( https://www.airspayce.com/mikem/arduino/RadioHead/) library adapted to use C instead of C++. The program is very simple, it reads the temperature sensor, battery (and PV pannel if available) voltage sends the data through LoRa and enters low power “Deep Sleep Mode” until it is awaken and does the same thing again.

The complete packet sent by the end node to the Gateway has the following structure with data fields separated by commas to easilly parse the data.

As can be seen from the previous image the end node sends a string containing a letter representing the type of data followed by the value, all fields are separated by commas.

  • I – Is an integer and represents the end node ID. This ID has to match an existing database entry otherwise the message will be discarded.
  • T – Is a float representing the temperature read from the DS18B20.
  • B – Is a float representing the battery voltage.
  • P – Is a float representing the PV pannel voltage if available.
  • F – Is an integer and represents the Firmware version of the end node.

3 – Power Consumption

In my application the system only has to measure the temperature and send the value to the gateway every half an hour (more or less). If left continuously running in normal operation the system consumes about 6mA (when only the microcontroller is ON) with large current peaks when transmiting. To increase battery life the microcontroller can be put into a low power mode that significantly reduces the power consumption.

Measuring these small currents that are continuously changing poses some problems. Dave Jones fom the EEVBLOG addresses this problem and created the µCurrent Gold. On his Youtube channel it has many information on the subject. There are other equipments used for this purpose nevertheless they tend to be expensive to the hobbyst. Here is a list of some that I’ve found:

  1. µCurrent Gold – https://www.eevblog.com/product/ucurrentgold/
  2. CurrentRanger – https://lowpowerlab.com/guide/currentranger/
  3. Otii Arc – https://www.qoitech.com/
  4. Joulescope – https://www.joulescope.com/
  5. ZS-1100-A – https://www.crowdsupply.com/zscircuits/zs1100a-power-meter

On Andreas Spiess Youtube channel (great channel with many LoRa related information) he also discusses this topic and presents a comparison between µCurrent Gold and the CurrentRanger. You can watch it here: https://youtu.be/HmXfyLyN38c

As I had none of the above available I’ve tried to find something I could use. An INA219A I2C shunt resistor current meter board was available with a shunt resistor of 0.1 Ohms, this would not going to do it because 0.1Ohms*50E-6A is simply to small to be measured by INA. Nevertheless changing the shunt resistor to 10 Ohms allows for a much higher resolution.

With this in mind and with a USB to I2C adapter (https://acroname.com/products/DEVANTECH-USB-I2C-INTERFACE-ADAPTER) the following setup was prepared:

INA219A board connected to a LoRa end node and the USB to I2C adapter.

With some python code using PyQT and PyQTGraph the following User Interface was created (work in progress):

uCurrent Logger User Interface showing ms on the X axis and uA on the Y axis.

The previous “tool” is nothing compared to the solutions presented previously but gives a bird eye view on the consumptions. The following images show a comparison between the two different regulators

From the two sets of images above the following values can be taken:

Sleep Mode rough average [µA]Deep Sleep Mode rough average [µA]
TC1015 – 3.3V8070
MIC5504 – 3.3V6055
No Regulator Vin = 3.3V3020
With Vin = 3.7V (Lithium Battery Nominal Voltage)

For the sake of completion the following graph shows the noise level of setup when nothing is attached. INA219A is prefered to INA219B because it has lower noise level:

I plan to make the sw available as soon as it is more robust.

LoRa and LoRa”Gateway”

1 – Introduction to LoRa.

LoRa (short for Long Range) is a type of RF communication designed for low-power and high range. Due to these characteristics it enables small end nodes (typically battery powered microcontrollers and sensors) to send information for IoT applications. LoRa has been developed by Semtech that licenses this technology to other vendors such as HopeRF, ST, Microchip, etc.

LoRaWAN concept illustration by www.libelium.com.
Libelium LoRa End Node + Sensors.

For IoT application there are several competitors such as LoRaWAN (that uses LoRa technology), Sigfox, NB-IoT, 6LoWPAN, etc. LoRaWAN providers can be both public and private. The most known public network is “The Things Network” or TTN. Upon free registration of an end node at TTN website, credentials are created allowing it to connect and transmit to a vast infrastructure of LoRa gateways spread across the globe. Furthermore a user can also add its own gateways to become part of the TTN increasing its coverage. In this article I won’t be discussing TTN or other LoRaWAN providers. I wanted to create a complete custom solution (nevertheless I plan to look at TTN in a near future).

2 – Wireless Sensor Network Architecture

Custom Wireless Sensor Network Architecture.

The previous image illustrates the architecture, it is very straight forward. Components were selected because they were available / match my knowledge.

When the “Gateway” receives a packet from an End Node it adds the RSSI and SNR information and sends the final packet through RS232. At the other end of the RS232 cable is an Orange Pi Zero running a python script (more on this below). If the message is considered valid it will make an HTTP request to store data into the cloud.

For the cloud section I’ve used www.pythonanywhere.com as it is free (with some limitations) and provides MySQL database and a web framework written in Python named Flask. Flask allows the creation of a web application using Python, work that would traditionally be made using PHP or other web oriented language.  

3 – LoRa Gateway

Commercial LoRa gateways can be either outdoor or indoor units, they are responsible for receiving and transmitting data from a LoRaWAN provider. They are self-contained units typically running some type of embedded linux to handle all the tasks.

 Wifx Lorix One Gateway can be used as a TTN gateway.

Furthermore the RF chipsets used on gateways (like the Semtech SX1301) are different from the ones used in end nodes as they can handle simultaneously different Spreading Factors (SF7 to SF12) and Coding Rates used in LoRa communications. This makes the selection of such parameters more flexible to the end nodes allowing a tradeoff between range and power consumption. 

My “gateway” on the other hand uses an RFM98w (434MHz) transceiver from HOPERF. It is designed for end nodes and capable of dealing with only one configuration at a time. This forces the end nodes to use the same configuration as the gateway for sake of compatibility, despite not being a problem in my case it is a limitation of the system. A PCB containing all the necessary elements (RF transceiver, microcontroller, RS232 transceiver, etc.) plus a DCDC converter and a One Wire temperature sensor were incased on an IP65 plastic box. The Box was mounted on a pole using the same hardware used to mount TV antennas.

First version of the “Gateway” still using an Arduino while PIC code was not ready.

A CAT5 cable was used to connect the outdoor box to inside the house where a RS232 to USB connects to the Orange Pi Zero SBC. This CAT5 cable carries both supply and data as follows:

Cable pair colorFunction
Orange0V
BlueSBC TX
GreenSBC RX
Brown+12V DC

4 – Antenna

As the project was a proof of concept I didn’t wanted to spend money on an antenna. After some research and for sake of build simplicity I’ve decided to go for a ground plane antenna.

As illustrated by the previous image the antenna consists on a vertical radiating element and 4 radials at 45⁰. I’ve used the following link to calculate the length of both radiating element and radials: https://m0ukd.com/calculators/quarter-wave-ground-plane-antenna-calculator/. At 433MHz yields the following lengths:

I’ve used a SMA to female BNC as the structure and cable of the antenna (a female N chassis connector is also popular option), and thick electrical copper wire for the elements. I’ve made a copper ring using the electrical wire and soldered the radials to it, this was fasten to the “GND” part of the BNC connector. The radiating element was soldered directly to the center of the BNC connector avoid shorting GND and signal. Finally hot glue has been used to give better mechanical properties and to avoid water accumulation. The complete assembly was mounted on a piece of plastic tube.

The final result is this:

After building the antenna I’ve used a nanoVNA to analyze its performance. The initial measures showed that the antenna was not resonating at the correct frequency, clipping slightly the radiating element corrected this and the final measures are the following:

In the end I think the result is very good. A very large dip at around 434MHz when measuring the S11 return loss, an impedance of almost 50Ohms (433 and 434 MHZ almost at the center of the Smith Chart)  and a VSWR near to 1. I’ve used this antenna for some time with very good results nevertheless I’m no RF engineer and surely there is room for improvements.

5 – Single Board Computer (SBC)

A computer was used to handle the communications to the server. For this task numerous solutions are available such as the ubiquitous Raspberry Pi, nevertheless I’ve decided to go for a cheaper Orange Pi Zero. Thanks to Armbian support to this board it was relatively simple to setup wireless connection, install Python3 and the necessary modules (“pyserial” and “Requests”).

Orange Pi Zero running python script

The script is launched during boot using cron jobs. For this purpose the crontab was edited with the command:

crontab -e

and the following line added:

@reboot sh /home/pi/app/launcher.sh >> /home/pi/app/log.txt

Inside the shell script “launcher.sh” is where the python script is executed. This was the way I’ve found for making this work maybe there is a better way of doing it.

cd /home/pi/app
python3 loadDBv2.py

During execution the script continuously reads the serial port, when a complete packet is received the script executes a HTTP GET request to the server saving the data to a MySQL database.

We can check if the script is running with the following command:

ps -A | grep python
Script is running with PID 733

The complete listing of the script is as follows:

import serial
from serial.tools import list_ports
import requests
import time
import sys

# [ping] GWID:01;SWV:01;T18.87
# [ping] GWID:01;SWV:01;T18.87
# [msg] RSSI:-61;SNR:10;msg:I04,T-0.06,B4.06,P0.01,F02
# [ping] GWID:01;SWV:01;T18.87
# [ping] GWID:01;SWV:01;T18.87

def serialreader():
    data = ''
    while(True):
        c = serialport.read(1)
        c = c.decode('utf-8')
        if c != '\r':
            data = data + c
        else:
            if len(data) < 2:
                data = ''
                continue
            else:    
                return data
        
    
    

def httprequest(requestparameters):
    if requestparameters[-1] == '&':
        requestparameters = requestparameters[:-1]
    #print( requestparameters )            
    r = requests.get( requestparameters )
    if(r.ok == False):
        print("Error while adding measure to DB")
        

#p = list(list_ports.grep("1A86:7523")) #Silabs
p = list(list_ports.grep("0403:6001"))  #FTDI

if len(p) == 0:
    print("No Serial Ports Detected")
    sys.exit(1) #abnormal exit error
else:
    print(p[0][1])
    print(p[0][2])
    serialport  = serial.Serial(port=p[0][0], baudrate=19200, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout = 12, xonxoff=False, rtscts=False, write_timeout=None, dsrdtr=False, inter_byte_timeout=None)
    serialport.flush()
    
    

while True:
    
    st = serialreader()
    messagedata = st.split(' ')
    
    messagetype = messagedata[0]
    payload = messagedata[1]
     
    if (messagetype == '[info]'):
        print(st)
        continue
    
    if (messagetype == '[ping]'):
        continue
    
    if (messagetype == '[msg]'):
        request = 'link to website'
        
        messagefields = payload.split(';')
        
        for messagefield in messagefields:
            temp = messagefield.split(':')
            
            if(temp[0] == 'RSSI'):
                request = request + 'R={}&'.format(temp[1]) 
                
            if(temp[0] == 'SNR'):
                request = request + 'SNR={}&'.format(temp[1]) 
                
            if(temp[0] == 'msg'):
                messagecontent = temp[1]
                if( len(messagecontent)< 1):# or st[0]!='I'):
                    continue
                else:
                    parameters = messagecontent.split(',')
                    for param in parameters:
                        request = request + '{}={}&'.format(param[0], param[1:]) 

        httprequest(request)

Led Display

Há já algum tempo que tinha planeada a construção de um Display de Leds. 

Estes displays encontram-se com frequência e constituem um projecto interessante e com utilidade.

Hardware

Neste projecto foram usadas 10 matrizes da Kingbright que contêm 7 linhas e 5 colunas no total de 35 leds por matriz perfazendo 350 leds em todo o painel.
Foram usados 7 shift registers (74HC164) para activar uma linha completa e 7 transístores pnp (visto que o painel é de ânodo comum) para ir comutando entre as diferentes linhas. O controlo do painel está a cargo de um PIC18F2680.

led_controller_schematic

O layout da board de controlo e da board que contém as matrizes foi feito no EAGLE.

led_display

Board que contem as 10 matrizes é um “shield” da placa de controlo.

led_controller_3D

Placa de controlo com os 7 shift registers e as resistências para os leds.

led_controller_assembly

Algoritmo

O firmware foi desenvolvido utilizando o C18 segundo o seguinte algoritmo.

algoritmo

Suporte

Foi desenhado um suporte para o Led Display utilizando o SolidWorks e posteriormente maquinado na CNC em PVC expandido de 5mm de espessura.

5423388810_50ec31f1cc_b

Imagem CAD do suporte.

5418795618_a68eee9de4_b

Suporte depois de maquinado e montado.

Resultado Final

5418199443_37f0851863_b

VFDclock

Displays VFD (Vacuum Fluorescent Display) são um tipo de display muito usado em electrónica de consumo capazes de mostrar símbolos, texto e números com alto brilho e contraste. São constituídos por um filamento, grelhas de controlo e dígitos revestidos com fósforo.

Com o pretexto de usar um destes displays e tendo recentemente adquirido um tubo IV18 decidi fazer um relógio.

O IV18 e seus constituintes podem ser vistos na imagem seguinte:

vfdgrelha

Existem muitos projectos que usam este tubo em diversas configurações como por exemplo:

confs

A configuração que mais gostei foi a ultima que se encontra na imagem anterior, assim usando um programa CAD desenhei o meu futuro relógio a ser construído em PVC expandido:vfdclockprojecto

Dentro do PVC expandido foi deixado espaço para alojar toda a electrónica necessária ao funcionamento do relógio como se pode ver no seguinte corte do desenho 3D:

vfdclockcorte

As peças são de PVC expandido de 1cm de espessura e foram cortadas na CNC. Os dois lados são ligados através de 4 varões de Inox e parafusos:
Foto0088

A placa de circuito impresso desenvolvida terá de encaixar no espaço reservado e conter os drivers para o tubo, o conversor DC-DC o microcontrolador e o RTC (Real Time Clock). Para este projecto foi usado o PIC18F4620, o RTC MCP79410 e o driver MAX6921.

pcbvfdclock

O layout da PCB foi feito no EAGLE e mede 5x5cm:

pcb

Uma representação 3D pode ser criada usando o EAGLE UP:

pcb2

Na imagem seguinte pode-se ver a PCB já feita e o primeiro teste para verificar as dimensões:

Foto0007_001

PCB montada e componentes mecânicos. Foi necessário usar duas peças intermédias em vez de uma originalmente prevista:

Foto0018_001

Relógio praticamente montado, faltando apenas os varões a unir as duas metades:

Foto0015_002

Primeiros testes ao firmware nomeadamente ao Led RGB montado na base do tubo:

Foto0013_002

Por fim o relógio já completamente montado e a funcionar:

Foto0035_001

Vídeo em funcionamento:

Under construction sign

Conversor DC-DC Step Up

No projecto de um relógio que construí, decidi usar um display VFD (Vacuum Fluorescent Display). Trata-se de um display muito usado em electrónica de consumo capaz de mostrar símbolos, texto e números com alto brilho e contraste. Este tipo de displays são constituídos por um filamento, grelhas de controlo e dígitos revestidos com fósforo. O modelo  usado é o IV18, precisa de uma tensão de alimentação do filamento de 5V e de pelo menos 25V para para as grelhas e dígitos.

vfdgrelha

Como mais facilmente se consegue um transformador de 230Vac para 12Vdc decidi usar um para alimentar o relógio e usar um conversor DC-DC para gerar as tensões necessárias para o funcionamento do tubo.

Um conversor “DC-DC step-up” (ou boost) é um conversor de energia em corrente contínua, em que a tensão de saída é maior do que a sua tensão de entrada. Trata-se de uma fonte de alimentação comutada (em Inglês SMPS – Switch Mode Power Supply) e contém (na sua forma mais simples) dois comutadores; um díodo e um transístor (regra geral um mosfet) e dois elementos de armazenamento de energia; um indutor e um condensador. O diagrama destes conversores é o que se segue:

dcdcdiagrama

O conversor trabalha em duas etapas. Na primeira, o díodo encontra-se inversamente polarizado e o comutador (mosfet) permite a passagem de corrente pela bobine. Durante esta fase, a carga é alimentada exclusivamente pelo condensador de saída.  dcdcstage1

Na segunda fase o comutador é aberto e gera-se uma tensão mais elevada aos terminais da indutância descrita pela equação:

V_l = L \frac{d_i}{d_t}

Nesta situação o díodo fica directamente polarizado e a energia armazenada na indutância durante a primeira fase é transferida para o condensador de saída  numa tensão mais elevada.

dcdcstage2

Os requisitos do conversor DC-DC para uso no relógio são:

Tensão de entrada Vin minimo 11.9V; nominal 12V ; máximo 12.1V

Tensão de saída Vout 25V ± 5%

Corrente de saída Iout 10mA

O tempo que o mosfet conduz (Ton) é de extrema importância porque controla a tensão de saída. A relação entre o Ton e o período de comutação (Ton+Toff) é conhecida por Dutty Cycle e é representado como sendo uma percentagem.

A equação seguinte relaciona a tensão de entrada e de saída para calcular o Dutty Cycle necessário:

D = 1 - \frac{ V_{inmin} }{ V_{out} } = 1 - \frac{ 11.9 }{ 25 } \equiv D = 52.4 \%

Os conversores DC-DC podem funcionar em dois modos, descontinuo ou continuo. Esta designação diz respeito ao facto da corrente no indutor se anular (modo descontinuo) ou não (modo contínuo) durante o funcionamento do conversor. O modo continuo é regra geral mais desejado pois proporciona uma maior eficiência. Para que o conversor trabalhe no modo contínuo é necessário que a indutância usada seja maior que a indutância crítica (valor mínimo que garante o funcionamento no modo contínuo).

 L_{min} = D \cdot V_ { in } \cdot \frac { 1 - D } {f \cdot 2 \cdot I_{out} }

Pela equação anterior, pode-se concluir que quanto maior a frequência, menor será a indutância necessária. Assumindo uma frequência de 50kHz:

L_{ min } = 0.524 \cdot 11.9 \cdot \frac{ 1 - 0.524 }{ 50000 \cdot 2 \cdot 0.01 } \equiv L_{ min} = 2968 \mu H

Neste caso foi usada uma indutância de 3900uH ( > que Lmin ) que já possuía. Com estes dados obtemos as seguintes formas de onda:

L3900_F50000_Vinmin_11.9_Vinmax_12.1

Como a frequência é 50kHz, o período T=20µS e o tempo que o mosfet está ligado Ton=T*D=10.48µS. Com esta informação podemos calcular a corrente máxima que atravessa a bobine através de:

\Delta I_L = \frac{V_{inmax} \cdot T_{on}}{L} = \frac{12.1 \cdot 10.48 E^{-6}}{3900 E^{-6}} \simeq 33 mA

A corrente de entrada é calculada através de:

 I_{in} = I_{out} \cdot \frac{V_{out} + V_D }{V_{in}} \simeq 21.17mA

e a corrente máxima:

I_{pk} = I_{in} + \frac{\Delta I_{L}} {2} \simeq 38mA

Tanto a indutância como o mosfet têm de conseguir suportar este valor. Para terminar falta calcular o condensador de saída e podemos fazê-lo através de:

 C_{out _{min}} = \frac{ I_{out _{max}} \cdot D }{f_s \cdot \Delta V_{ out } } = \frac{0.01 \cdot 0.524 }{50 E^{3} \cdot 1.25} = 85nF \Rightarrow 100nF

Com todos os componentes dimensionados pode-se simular o circuito para ver como se comporta, para isso usei o LTspice com o seguinte circuito:simulacaodcdcschematic

Utilizando um condensador de 100nF obtiveram-se os seguintes resultados:

dcdc100nf

A tensão de ripple situa-se dentro das especificações de 25V±5%=1.25V com um valor de aproximadamente 1V. Para melhorar esta situação usei um condensador de 300nF com os seguintes resultados:

dcdc300nf

Os resultados do circuito real são os seguintes onde a onda azul representa a tensão de saída e a vermelha o comando do mosfet (PWM):

com condensador de saída de 100nF:

25V_100nF

com condensador de saída de 300nF:

25V_300nF

GUI com IronPython

Na continuação do artigo anterior que mostrava como criar e executar um script em IronPython, iremos agora ver como pode ser criado um GUI (Graphical User Interface) utilizando Python e os componentes do “.NET”.

O GUI que pretendemos construir é constituido por uma janela (Form), uma caixa de texto (TextBox) e tem o seguinte aspecto:

gui

A Microsoft agrupa “funcionalidades” (classes) em “NameSpaces” e “Assemblies”. Os “NameSpaces” são usados para organizar de forma lógica classes que estejam de alguma forma relacionada, têm também como objectivo evitar conflitos entre classes provenientes de várias fontes. As “Assemblies” são código compilado, tipicamente um ficheiro DLL e podem conter vários “NameSpaces”.

Windows Forms (WinForms) é o nome dado à API (Application Programming Interface) de interface gráfica usada nas aplicações. Esta API proporciona o acesso a elementos nativos do interface do Windows como janelas, botões, caixas de texto, labels entre muitos outros. O “.NET” possui um namespace chamado “System.Windows.Forms” que iremos usar para importar para a nossa aplicação a janela e a caixa de texto.

Na documentação online disponível na MSDN (Microsoft Developer Network) pode ver-se quais as classes que pertencem ao namespace “System.Windows.Forms” em http://msdn.microsoft.com/en-us/library/k50ex0x9.aspx. Pesquisando um pouco é fácil de encontrar dentro deste namespace a class “Form” em http://msdn.microsoft.com/en-us/library/system.windows.forms.form.aspx e a class “TextBox” em http://msdn.microsoft.com/en-us/library/system.windows.forms.textbox.aspx

O código necessário para gerar esta aplicação pode ser escrito utilizando o Notepad++ e é o que se segue:

import clr
clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')

from System.Windows.Forms import Application, Form, TextBox
from System.Drawing import Point

form = Form()
form.Text = 'Exemplo GUI'

#http://msdn.microsoft.com/en-us/library/system.windows.forms.textbox.aspx
#http://msdn.microsoft.com/en-us/library/a19tt6sk.aspx

posicao=Point(20,30)

texto=TextBox()
texto.Location=posicao
texto.Text='Hello World'

form.Controls.Add(texto)

Application.Run(form)

Para que um programa possa usar uma assembly/namespace, é necessário adicionar explicitamente uma referência para este. Para adicionar referências usa-se o módulo CLR e para usar o módulo CLR é necessário importá-lo. É precisamente isso que faz a primeira linha de código:

import clr

As referencias são adicionadas através do método “AddReference”. Para este programa vamos adicionar duas referências para os namespaces “System.Windows.Forms” e “System.Drawing”:

clr.AddReference('System.Windows.Forms')
clr.AddReference('System.Drawing')

Destes namespaces vamos importar a class “Application” a “Form” e a “TextBox” bem como a estrutura “Point” para tal usamos o seguinte:

from System.Windows.Forms import Application, Form, TextBox
from System.Drawing import Point

Agora que o nosso código já tem acesso a estas classes vamos instanciar (criar um objecto de um tipo) uma janela (form):

form = Form()
form.Text = 'Exemplo GUI'

O código acima também mostra como aceder e alterar a propriedade Text (Nome da janela) através do operador “.”.

De seguida vamos criar (instanciar) uma caixa de texto. O código seguinte também inicializa uma estrutura do tipo “Point” para escolhermos as coordenadas da caixa de texto em relação à janela e altera o texto para “Hello World”.

texto=TextBox()
posicao=Point(20,30)
texto.Location=posicao
texto.Text='Hello World'

As ultimas duas linhas adicionam a caixa de texto à janela e executam a aplicação:

form.Controls.Add(texto)

Application.Run(form)

Para executarmos o nosso programa assumindo que lhe chamámos “gui.py” podemos (na consola) chamar a aplicação da seguinte forma:

ipy gui.py

esta forma é mais correcta para fazer debug da aplicação.

Quanto tudo funcionar correctamente podemos executar a aplicação (através de um atalho por exemplo) com o comando:

ipyw gui.py

Usando o “ipyw” em vez do “ipy” a aplicação não vai abrir uma janela da consola quando se executa.

Python + .NET = IronPython

Introdução:

Python é uma linguagem de programação de alto nível multi plataforma (Windows, Linux, MAC),  interpretada (os programas em Python são muitas vezes chamados scripts) e orientada a objectos. A linguagem foi projectada com a filosofia de diminuir o esforço do programador bem como da  legibilidade do código. Combina uma sintaxe concisa e recursos poderosos através da sua biblioteca padrão e de módulos e frameworks desenvolvidos por terceiros. A distribuição padrão é conhecida como CPython, é desenvolvida em “C” e pode-se encontrar em http://www.python.org/.

Microsoft .NET é uma iniciativa da Microsoft, que visa uma plataforma única para desenvolvimento e execução de sistemas e aplicações. Com uma ideia semelhante à plataforma Java, o programador deixa de escrever código para um sistema ou dispositivo específico, e passa a escrever para a plataforma .NET. Esta plataforma é executada sobre uma Common Language Runtime – CLR  (Ambiente de Execução Independente de Linguagem) interagindo com um Conjunto de Bibliotecas Unificadas (framework).

Actualmente o .NET suporta um conjunto de Linguagens de Programação através do seu IDE, o Microsoft Visual Studio ou Visual Studio Express (gratuito mas com algumas funções limitadas), entre elas encontram-se o Visual Basic, o Visual C++ e  o C#.

IronPython é uma implementação de Python escrita integralmente em C# utilizando o .NET (em oposição ao CPython escrito em C) e permite aos utilizadores de Python o uso da estrutura .NET e todas as funcionalidades compatíveis, tornando Python outra linguagem do .NET ao lado do Visual Basic ou do C#. O IronPython pode ser descarregado em http://ironpython.net/

Instalação:

Para poder usar o IronPython é necessário fazer o download do installer na página oficial em: http://ironpython.net/ (versão mais actual à data deste artigo 2.7.3).

De seguida executa-se o “installer” e seguem-se os passos normais na instalação de um programa. Findado o processo de instalação é necessário adicionar ao “System Path” (variável de sistema que especifica um conjunto de directorias contendo os executáveis de diversos programas) a  directoria de instalação do IronPython de forma a que este seja reconhecido em qualquer lado.

Nas “Definições Avançadas de Sistema” escolher o separador “Avançadas” e a opção “Variáveis de Ambiente”:

systemvars

De seguida escolher:

systemvars2

Na janela que aparece navega-se até ao fim do texto e adiciona-se um “;” seguido da directoria de instalação do IronPython, no meu caso:

systemvars3

Teste:

Para confirmar que tudo está a funcionar correctamente abram uma janela da consola (DOS) e escrevam “ipy” seguido de “enter”. Deverão obter o seguinte resultado:

ipy

A consola deverá  mostrar a versão do IronPython usada e ficar com o cursor a piscar a seguir a “>>>” . Este é o modo interactivo e permite testar todos os comandos e funções do IronPython (o CPython também tem um modo equivalente).

Podemos criar um programa “Hello World”, para tal escreva na consola:

print('Hello World')

Deverá obter algo do género:
helloPara sair do modo interactivo e voltar à consola, basta escrever o comando “quit()” seguido de “enter”:

quit()

Escrever Scripts:

Podem-se criar ficheiros com código dentro e depois executá-los sem que para isso necessitemos de usar o modo interactivo da consola. Para isso podemos usar um programa como o Notepad++ disponivel em http://notepad-plus-plus.org/. O exemplo anterior ficaria:

scriptpy

No Notepad++ pode-se escolher qual a linguagem de programação de forma a que ele faça o “highlight” do código de forma correcta. De seguida é necessário guardar o ficheiro na localização e com o nome pretendido através de “File-> Save As”:

saveas

Como anteriormente tinha sido escolhido a linguagem de programação o Notepad++ sabe que é um ficheiro com código Python e vai adicionar automaticamente a extensão “.py” ao ficheiro. Neste exemplo o nome do ficheiro vai ser “helloworld.py”.

Para executar o nosso script voltamos à consola e navegamos até à directoria onde guardámos o script e escrevemos:

ipy helloworld.py

O resultado deverá ser:
exec
No próximo tutorial avançaremos para a utilização de componentes .NET e ambiente gráfico.

CAD para Gcode

De forma a poder maquinar uma peça utilizando uma CNC é necessário converter o desenho 3D em algo que o controlador da CNC entenda. As CNCs têm a sua própria linguagem conhecida como “Código G” (G Code em inglês), assim, é necessário algo que converta o desenho em código G.

cad2gcode

Como o esquema anterior demonstra, o workflow de cortar uma peça utilizando a CNC começa com o desenho da mesma num software CAD como o Autocad, Freecad, Solidworks, CamBam (limitado), entre outros.

De seguida o desenho passa por um software CAM como o Mastercam, Sprutcam ou o CamBam onde são escolhidas as opções de maquinagem como o tipo de passagens, o tipo fresa  e informações como diâmetro, velocidade de corte e número de passagens e altura de segurança. É também o software CAM que vai gerar o ficheiro com o código G.

Por fim o ficheiro contendo código G é importado pelo controlador da CNC como o MACH3, o EMC2 Linux, ou um controlador físico como Fanuc ou Heidenhain responsável por controlar a máquina.

Muitas das peças são apenas um contorno 2D com uma profundidade. Este tipo de peças é conhecido como 2.5D e é sobre elas que este tutorial incide usando o CamBam (versão gratuita) http://www.brusselsprout.org/cambam/download.htm

Assumindo que desejamos maquinar uma peça 2.5D (definida por um contorno 2D e por uma altura, regra geral a do próprio material) em PVC expandido de 10mm de espessura como a seguinte :

peca

Por convenção, o topo da peça tem cota (eixo dos Zs)  igual a zero, esta será negativa quando a fresa está a cortar (encontra-se dentro do material) e positiva quando está a viajar entre pontos sem cortar (altura de segurança).

Usando o desenho CAD (por exemplo com o SolidWorks) devemos guardar uma versão com a extensão “DXF” e vamos abri-la no CAMBAM usando a opção “File->Open”:

cambam

Convém verificar se as unidades no CamBam são coincidentes com as usadas no controlador. Na imagem anterior é possível ver o contorno da peça.

Para este exemplo vamos usar PVC expandido de 10mm de espessura e uma fresa de 3mm de diâmetro com duas laminas em hélice.

fresapvc

Clicando em qualquer dos contornos este ficará realçado a vermelho e usando o “control (ctrl)” podemos seleccionar mais que um contorno.

cambam25d

Com estes contornos seleccionados iremos agora escolher o tipo de operação a efectuar sobre eles e seguidamente o diâmetro da fresa, se queremos cortar por dentro ou por fora do contorno, a profundidade de corte, o numero de passagens, a velocidade de avanço e a altura de segurança.

Dos menus iremos escolher “CAM->2.5D Profile” e o CamBam abrirá um menu do lado esquerdo com diversas opções como se encontra na figura seguinte:

cambamopcoes

As opções mais importantes são:

Nome do campo Descrição do Campo Valor para o exemplo
DepthIncrement É este valor que define quanto é que a fresa vai penetrar no material a cada passagem que faz. 3 [mm]
FinalDepthIncrement Define qual o incremento de penetração da fresa a fazer na ultima passagem. Utiliza-se este campo no caso em que o “DepthIncrement” escolhido não dê número de passagens certo, por exemplo se for escolhido um valor de “DepthIncrement” de 3mm e a espessura a cortar seja de 10mm. Neste iriam ser feitas três passagens com incremento de 3mm e utilizando o “FinalDepthIncrement” igual a 1mm para completar os 10mm. No caso em que o numero de passagens dê certo este campo pode ser igual a zero. 1 [mm]
StockSurface Este valor determina a altura da peça. Por convenção é igual a zero. 0 [mm]
TargetDepth Define qual a profundidade pretendida a ser atingida pela fresa. Por convenção fresa corta quando a cota é Zero. Assim sendo este valor aparece negativo, no nosso exemplo será = a -10mm (espessura do PVC) -10 [mm]
CutFeedrate Define a velocidade de avanço (em mm/min) enquanto a fresa está a cortar. Este valor depende do tipo de material, da fresa e CNC usada, é necessária alguma experiência/testes para descobrir qual o que se adequa melhor. 300 [mm/min]
PlungeFeedrate Define a velocidade de penetração (em mm/min) da fresa no material. 250 [mm/min]
ClearancePlane Define qual a altura a que a fresa pode movimentar-se em segurança de um sitio para o outro sem embater na peça a maquinar. 5 [mm]
InsideOutside Define se desejamos que a fresa corte por dentro ou por fora do contorno. Inside
ToolDiameter Define o diametro da fresa que vai ser utilizada para cortar. 3 [mm]
ToolNumber Define qual o numero que desejamos atribuir a uma determinada fresa. Caso durante o trabalho apenas se use uma fresa não é necessário usar este campo e pode-se usar o valor default de zero. 0

De seguida selecciona-se o contorno exterior e volta-se a repetir o procedimento mostrado acima tendo atenção que no campo “InsideOutside” deve-se alterar para “Outside”.

cambamopcoes2

Terminadas as operações pode-se verificar se tudo está conforme desejado clicando com o botão do lado direito do rato em cima de “Machining” e escolher a oção “cambamgentool

Os caminhos onde a fresa passará aparecem agora junto com a peça. Utilizando a tecla “Alt” juntamente com o botão esquerdo do rato pode-se visualizar a peça e os percursos da fresa a 3D.cambam3D

Usando a tecla “Alt” e fazendo duplo clic em cima da peça faz o reset para a vista normal de visualização.

Para terminar resta gerar o código G, para isso basta clicar com o botão direito em cima de “Machining” e escolher a opção “Create GCode File” e salvar normalmente o arquivo onde se desejar como noutras aplicações.

Os ficheiros neste exemplo podem ser descarregados aqui.