Pulse width modulation, known as PWM, is a technique that makes it possible to generate an analog result with digital means through the usage of a digital on-off pattern. The pins that provide PWM capabilities use a digital control to create a square wave and it can simulate voltages between the configured IOREF voltage (5V in the default board configuration) and 0V by controlling the amount of time that the signal spends in the ON status (IOREF voltage) and the time the signal spends in the OFF status (0V). The pulse width is the duration of the signal in the ON status (IOREF voltage), and therefore, pulse width modulation means changing the pulse width to get perceived analog values.
When you repeat the signal in the ON status and the signal in the OFF status hundreds of times per second with a LED connected to the PWM pin, we can generate the same result as if the signal is a steady voltage between 0V and the IOREF voltage to control the LED's brightness level.
We can write floating point values from 0 to 1 to the PWM enabled pins configured as analog output, that is, from 0% duty cycle (always signal in the OFF status) to 100% duty cycle (always signal in the ON status). We want to represent 256 brightness values (from 0 to 255 inclusive), and therefore, the following graph shows the brightness values in the abscissa axis (x-axis) and the corresponding floating point values that have to be written to the pin in the ordinate axis (y-axis).
The equation for the previous graph is the following: y = x / 255, specifically value = brightness / 255. We can run the following code in our Python interpreter to see the output with all the values that will be written for each brightness level from 0 to 255 inclusive.
for brightness in range(0, 256):
print(brightness / 255.0)
We can multiply the floating point values by 5 to calculate the voltage value for each brightness level. As we are working with the default settings for the board, the IOREF jumper is set to 5V, and therefore, a 1.0 value in the output means 5V (1.0 x 5 = 5). A value of 0.5 in the output means 2.5V (0.5 x 5 = 2.5). The following graph shows the brightness values in the abscissa axis (x-axis) and the corresponding voltage values in the output that will generate the corresponding brightness value in the LEDs in the ordinate axis (y-axis).
The equation for the previous graph is the following: y = x / 255 * 5, specifically voltage = brightness / 255 * 5. We can run the following code in our Python interpreter to see the output with all the voltages that will be generated for each brightness level from 0 to 255 inclusive.
for brightness in range(0, 256):
print(brightness / 255.0 * 5)
We will create a new AnalogLed class to represent an LED connected to our board that can have a brightness level from 0 to 255 inclusive. The following lines show the code for the new AnalogLed class. The code file for the sample is iot_python_
chapter_04_02.py. import mraa
from datetime import date import tornado.escape import tornado.ioloop
Chapter 4
def set_brightness(self, value):
brightness_value = value
self.brightness_value = brightness_value
print("{0} LED connected to PWM Pin #{1} set to brightness {2}.".format(self.name, self.pin, brightness_value))
We have to specify the pin number to which the LED is connected when we create an instance of the AnalogLed class in the pin required argument, and a name for the LED in the name required argument. The constructor, that is, the __init__ method, creates a new mraa.Pwm instance with the received pin as its pin argument, saves its reference in the pwm attribute and calls its period_us method to configure the PWM period in 700 microseconds (700 µs). Thus, the output duty cycle will determine the percentage of the 700 microsecond period during which the signal is in the ON status. For example, a 0.5 (50%) output duty cycle means that the signal will be ON during 350 microseconds of the 700 microseconds period (700 * 0.5 = 350).
Then, the the code calls the pwm.enable method with True as a parameter to set the enable status of the PWM pin and allow us to start setting the output duty-cycle percentage for the PWM pin with calls to the pwm.write method.
The next line creates a brightness_value attribute initialized with 0 that will allow us to easily retrieve the last brightness value set to the LED connected to the pin.
Finally, the constructor calls the set_brightness method with 0 as the value for the value argument to set the brightness level for the LED connected to the configured pin to 0.
The class defines a set_brightness method that receives a brightness level value in the value argument. The first lines of code make sure that we always set a brightness level between 0 and 255 (inclusive). In case the value argument has a value that isn't included in that range, the code assigns the lower-level (0) or upper-level value (255) to the brightness_value variable.
Then, the code calculates the necessary output duty-cycle percentage for the PWM pin to represent the brightness level as a floating point value between 1.0f (100%) and 0.0f (0%). The code saves the value in the led_value variable and then calls the self.pwm.write method with this variable for the percentage argument to set the output duty-cycle for the pin configured as PWM output to led_value. The next line saves the valid brightness level to the brightness_value attribute.
Finally, the code prints details about the LED name, the pin number and the
brightness level that has been set. This way, the method translates a brightness level from 0 to 255 (inclusive) into the appropriate output duty-cycle value for the pin and writes the output to control the connected LED's brightness level.
Now, we can write code that uses the new AnalogLed class to create one instance for each of the three LEDs and easily control their brightness levels. The following lines show the code for the BoardInteraction class. The code file for the sample is iot_python_chapter_04_02.py.
class BoardInteraction:
# The Red LED is connected to pin ~6 red_led = AnalogLed(6, 'Red')
# The Green LED is connected to Pin ~5 green_led = AnalogLed(5, 'Green') # The Blue LED is connected to Pin ~3 blue_led = AnalogLed(3, 'Blue')
The BoardInteraction class just declares three class attributes: red_led, green_led and blue_led. The three class attributes save new instances of the previously created AnalogLed class and represent the red, green and blue LEDs connected to pins ~6, ~5 and ~3. Now, we will create other classes that define methods that work with these class attributes to access common AnalogLed instances.
The next lines show the code that adds the following classes: VersionHandler, PutRedBrightnessHandler, PutGreenBrightnessHandler and
PutBlueBrightnessHandler. The code file for the sample is iot_python_chapter_04_02.py.
class VersionHandler(tornado.web.RequestHandler):
def get(self):
response = {'version': '1.0',
Chapter 4
BoardInteraction.red_led.set_brightness(int_value)
response = {'red': BoardInteraction.red_led.brightness_value}
self.write(response)
class PutGreenBrightnessHandler(tornado.web.RequestHandler):
def put(self, value):
int_value = int(value)
BoardInteraction.green_led.set_brightness(int_value)
response = {'green': BoardInteraction.green_led.brightness_
value}
self.write(response)
class PutBlueBrightnessHandler(tornado.web.RequestHandler):
def put(self, value):
int_value = int(value)
BoardInteraction.blue_led.set_brightness(int_value) response = {'blue': BoardInteraction.blue_led.brightness_
value}
self.write(response)
The code declares the following four subclasses of tornado.web.RequestHandler:
• VersionHandler: Defines the parameter less get method that returns a response with the version number and the last build date.
• PutRedBrightnessHandler: Defines the put method that requires a value argument that specifies the desired brightness level for the red LED. The method calls the set_brightness method for the AnalogNumber instance stored in the BoardInteraction.red_led class attribute with the desired brightness level specified in the value argument. Then, the code returns a response with the brightness level that has been translated to an output duty cycle percentage in the PWM pin to which the red LED is connected to.
• PutGreenBrightnessHandler: Defines the put method to set the desired brightness level for the green LED. It works as the previously described PutRedBrightnessHandler method but instead of using the BoardInteraction.red_led class attribute, the code uses BoardInteraction.green_led class attribute to control the brightness level for the green LED.
• PutBlueBrightnessHandler: Defines the put method to set the desired brightness level for the blue LED. It works as the previously described PutRedBrightnessHandler method but instead of using the BoardInteraction.red_led class attribute, the code uses BoardInteraction.blue_led class attribute to control the brightness level for the blue LED.
The next lines show the code that adds the following classes:
GetRedBrightnessHandler, GetGreenBrightnessHandler and GetBlueBrightnessHandler. The code file for the sample is iot_python_chapter_04_02.py.
class GetRedBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'red': BoardInteraction.red_led.brightness_value}
self.write(response)
class GetGreenBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'green': BoardInteraction.green_led.brightness_
value}
self.write(response)
class GetBlueBrightnessHandler(tornado.web.RequestHandler):
def get(self):
response = {'blue': BoardInteraction.blue_led.brightness_
value}
self.write(response)
Chapter 4 The code declares the following three subclasses of tornado.web.RequestHandler:
• GetRedBrightnessHandler: Defines the parameter less get method that returns a response with the value of the BoardInteraction.red_led.
brightness_value attribute, that is, the brightness value set to the red LED
• GetGREENBrightnessHandler: Defines the parameter less get method that returns a response with the value of the BoardInteraction.green_led.
brightness_value attribute, that is, the brightness value set to the green LED
• GetBlueBrightnessHandler: Defines the parameter less get method that returns a response with the value of the BoardInteraction.blue_led.
brightness_value attribute, that is, the brightness value set to the blue LED The following lines use the previously declared subclasses of tornado.web.
RequestHandler to make up the web application with Tornado that represents a new RESTful API and the new __main__ method. The code file for the sample is iot_python_chapter_04_02.py.
application = tornado.web.Application([
(r"/putredbrightness/([0-9]+)", PutRedBrightnessHandler), (r"/putgreenbrightness/([0-9]+)", PutGreenBrightnessHandler), (r"/putbluebrightness/([0-9]+)", PutBlueBrightnessHandler), (r"/getredbrightness", GetRedBrightnessHandler),
(r"/getgreenbrightness", GetGreenBrightnessHandler), (r"/getbluebrightness", GetBlueBrightnessHandler), (r"/version", VersionHandler)])
if __name__ == "__main__":
print("Listening at port 8888") application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
As happened in our previous example, the code creates an instance of the tornado.
web.Application class named application with the list of request handlers that make up the web application, that is, the tuples of regular expressions and subclasses of tornado.web.RequestHandler.
The following table shows some HTTP requests that match the regular expressions defined in the preceding code. In this case, the HTTP requests use 192.168.1.107 because they are executed from a computer connected to our LAN. Don't forget to replace 192.168.1.107 with your board's IP address in the next requests.
HTTP verb and request URL Tuple (regexp, request_class)
that matches the request path RequestHandler subclass and method that is called
The following line will start the HTTP server and our RESTful API that allows us to control the brightness level for red, green and blue LEDs in the Yocto Linux running on the board. Don't forget that you need to transfer the Python source code file to the Yocto Linux with an SFTP client, as explained in the previous chapter.
python iot_python_chapter_04_02.py
After we start the HTTP server, we will see the following output and all the red, green and blue LEDs are going to be turned off.
Red LED connected to PWM Pin #6 set to brightness 0.
Green LED connected to PWM Pin #5 set to brightness 0.
Blue LED connected to PWM Pin #3 set to brightness 0.
Listening at port 8888