The aim of this project is to demonstrate how you can connect many sensor nodes to a central base station. And how to then get the data from the base station via wifi.
Required Libraries
ALSPT19 - For the analog light sensor (For the nodes)
TheoryFor this project 10 LoPy modules will be placed around the track from the PyTrack project. A bright LED will be attached to the side of the robot and a ALS PT19 analog light sensor will be added to each node. The nodes will then detect the bright light to know the robot is passing the node. Once a node detects the robot it will send a message to the central base station. This base station will then forward the ID of the node that detected the robot via wifi to some server software. This software will then visualise the robots location on the track.
NodeThe first thing we need to do on our nodes is disable the WiFI access point that run on all Pycom modules by default. WiFi is very power hungry and by disabling it we can greatly extend the battery life of our nodes.
wlan = WLAN(mode=WLAN.STA)
wlan.deinit()
Further power savings can be made by putting the CPU into deep sleep but this is outside of the scope of this tutorial.
Next we need to setup LoRa using the raw mode rather than LoRaWAN. Since the devices will be close to each other we can reduce the power down to 8dbm
. We also use tx_iq
to avoid listening to our own messages. We set blocking to False to prevent the module locking up if there is an issue with the radio.
from network import LoRa
import socket
lora = LoRa(mode=LoRa.LORA, tx_iq=True, tx_power=8)
sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
sock.setblocking(False)
Next we need to connect the sensor to the internal ADC using the library linked above. We need to provide it with the name of the pin the sensor is connected to. After this we need to calibrate the sensor. This will measure the ambient light level for 3 seconds and set the sensors threshold to 1.2 times this value.
light = ALSPT19('P18')
light.calibrate()
Note: Ensure you are not standing in front of the sensor when calibrating it, this might effect the ambient light reading causing it to trigger constantly later.
When the light has been detected we need to send a message to the base station with our ID to inform it that we detected the robot.
_PKG_FORMAT = "B"
while(True):
# If the light is on, send a packet
if light.is_on():
print("Got light")
# Send packet to gateway
pkg = struct.pack(_PKG_FORMAT, DEVICE_ID)
sock.setblocking(True)
sock.send(pkg)
sock.setblocking(False)
While sending a packet to the base station we temporarily enable block to ensure that we only move on once the message has been transmitted.
GatewayThe first thing the gateway needs to do is to setup the LoRa radio. This procedure is very similar to the nodes. The only difference is we need to set rx_iq
this time.
from network import LoRa
import socket
lora = LoRa(mode=LoRa.LORA, rx_iq=True, tx_power=8)
sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
sock.setblocking(False)
Next we need to connect to the same local WiFi network as the computer running the sever software. You could also connect your computer to the access point created by the Pycom module if you prefer but your computer will not be able to access the internet.
import machine
from network import WLAN
import pycom
# WiFi client mode
wlan = WLAN(mode=WLAN.STA)
pycom.rgbled(0x0000FF)
nets = wlan.scan()
for net in nets:
if net.ssid == 'SSID':
print('Network found!')
wlan.connect(net.ssid, auth=(net.sec, 'PASSWORD'), timeout=5000)
while not wlan.isconnected():
machine.idle() # save power while waiting
print('WLAN connection succeeded!')
break
else:
pycom.rgbled(0xFF0000)
raise Exception("Could not find network")
Note: In this piece of code we change the colour of the on-board LED depending on what state it is in. This is a very useful technique to debug projects, especially when you are testing several device at once and it is not practical to remain connected to all of them at once.
Once we are connected to the network we need to connect to the server. You will need to adjust the IP address to match the IP of the machine running the server software, the port should also match the one set in the code below in the server section.
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
s.connect(('192.168.1.144', 8080))
print("Connected to server")
pycom.rgbled(0x00FF00)
Finally the basestation needs to wait for incoming data and forward it to the server software via WiFi
while True:
recv_pkg = sock.recv(512)
# Got a packet
if (len(recv_pkg) > 0):
try:
# Unpack packet
device_id = struct.unpack(_PKG_FORMAT, recv_pkg)[0]
# Print which node the packet is from
print('Device: %d - Got Packet' % (device_id))
# Send node ID to laptop
out = "{}\n".format(device_id).encode()
s.send(out)
except Exception as e:
# most likely struck.unpack failed due
# to two packets being buffered
print(e)
ServerThe server software is written using Python mode for Processing but the code can easily be adapted to use native python using sockets. The first thing we need to do is include the networking library for processing like so:
add_library('net')
We then need to begin the server, on port 8080
in our case
server = Server(this, 8080)
Note: this
is a processing specific variable needed by the underlying java libraries. Next we get the next available client connection (if any) and read the data until a newline (ASCII 10). We can then turn the received value into an integer which is the ID of the base station that detected the robot
client = server.available()
if client is not None:
incomingMessage = client.readStringUntil(10)
print("MSG:{}".format(incomingMessage))
loc = int(incomingMessage)
Once we have the node ID (and thus location) we can visualise the data.
Comments