ESP8266 and CircuitPython: Control a Servo Over the Internet Using UDP from Any Client
If you want remote control over the internet, then UDP is a pretty good choice.
It's clean, lightweight, relatively fast (usual caveats of hardware, signal, bandwidth, yada), and turns out it is pretty easy to implement with Micro or Circuit Python.
Here I am using the latter because I am going to drive a servo on my Adafruit Crickit Featherwing and ESP8266.
We will start with the client, it is simply asking for input strings and sending those (encoded) over UDP.
Later we can build an actual remote control interface (or two), but for now it's the server that is the main goal.
Client Code
import socket
server = ("10.0.1.29", 9999)
# create our udp socket
try:
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.error:
print("Oops, something went wrong connecting the socket")
exit()
while 1:
message = input("> ")
# encode the message
message = message.encode()
try:
# send the message
socket.sendto(message, server)
# output the response (if any)
data, ip = socket.recvfrom(1024)
print("{}: {}".format(ip, data.decode()))
except socket.error:
print("Error! {}".format(socket.error))
exit()
Client to Server
The idea for now is to just pass strings back and forth:
We do minimal validation, just checking to see if the angle is possible.
UDP Micro/Circuit Python
The UDP networking code is pretty much standard Python.
One challenge is CircuitPython does not have a decode function for unicode values.
Yeah, crazy huh?
So if you get a AttributeError: 'bytes' object has no attribute 'decode'
error, you need the line of code that does the business instead (slowly, clumsily).
datastr = ''.join([chr(b) for b in data]) # convert bytearray to string
It joins each character one by one into a string. Not elegant but it works!
We look for strings containing an angle from 0 to 180. If we get a valid angle then we pass it to the Servo code that we looked at previously.
Pretty simple, eh? :)
import socket
import network
import board
from busio import I2C
from adafruit_seesaw.seesaw import Seesaw
from adafruit_seesaw.pwmout import PWMOut
from adafruit_motor import servo
# i2c
i2c = I2C(board.SCL, board.SDA)
seesaw = Seesaw(i2c)
# servo object
pwm = PWMOut(seesaw, 17)
pwm.frequency = 50
my_servo = servo.Servo(pwm)
# network connect
sta_if = network.WLAN(network.STA_IF)
print(sta_if.ifconfig())
# set up the socket using local address
socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
socket.bind(("", 9999))
# loop until interrupted
while 1:
# get the data sent to us
data, ip = socket.recvfrom(1024)
datastr = ''.join([chr(b) for b in data]) # convert bytearray to string
# display
print("{}: {}".format(ip, str(datastr).strip()))
# angle
angle = int(datastr)
if (angle >= 0) and (angle <= 180):
my_servo.angle = angle
else:
print("Angle must be possible with a servo.")
# echo back
socket.sendto(data, ip)
Next Steps
So what use is this?
Well, many robots are based around servos. When BB8 opens a compartment to reach out and "thumbs up" with a blow torch, that would be implemented with servos.
Also there are 360 degree continuous rotation servos for movement.
Join our Discord Channel to connect with us and nominate your own or somebody else's posts in our review channel.
Help us to reward you for making it ! Join our voting trail or delegate steem power to the community account.
Your post is also presented on the community website www.steemmakers.com where you can find other selected content.
If you like our work, please consider upvoting this comment to support the growth of our community. Thank you.