{ "cells": [ { "cell_type": "markdown", "id": "1205c27c", "metadata": {}, "source": [ "\n", "*This notebook contains material from [cbe61622](https://jckantor.github.io/cbe61622);\n", "content is available [on Github](https://github.com/jckantor/cbe61622.git).*\n" ] }, { "cell_type": "markdown", "id": "26bab603", "metadata": {}, "source": [ "\n", "< [6.2 Coding for Device Control](https://jckantor.github.io/cbe61622/06.02-Coding-Paradigms.html) | [Contents](toc.html) | [6.4 Event Driven Programming](https://jckantor.github.io/cbe61622/06.04-Event-Driven-Programming.html) >
"
]
},
{
"cell_type": "markdown",
"id": "45d210eb-7479-4ee3-b5a5-3ea631bbcd37",
"metadata": {
"nbpages": {
"level": 1,
"link": "[6.3 Coding Paradigms for Device Control](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3-Coding-Paradigms-for-Device-Control)",
"section": "6.3 Coding Paradigms for Device Control"
}
},
"source": [
"# 6.3 Coding Paradigms for Device Control"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "594db2ba-61c9-4e32-b571-8a7fcb680a40",
"metadata": {
"nbpages": {
"level": 1,
"link": "[6.3 Coding Paradigms for Device Control](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3-Coding-Paradigms-for-Device-Control)",
"section": "6.3 Coding Paradigms for Device Control"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found serial ports: /dev/cu.usbmodem14101, /dev/cu.Bluetooth-Incoming-Port \n",
"\u001b[34mConnecting to --port=/dev/cu.usbmodem14101 --baud=115200 \u001b[0m\n",
"\u001b[34mReady.\n",
"\u001b[0m"
]
}
],
"source": [
"%serialconnect"
]
},
{
"cell_type": "markdown",
"id": "459543b9-c24e-4ae7-91fe-0cf723b5f00f",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.1 The Coding Challenge](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.1-The-Coding-Challenge)",
"section": "6.3.1 The Coding Challenge"
}
},
"source": [
"## 6.3.1 The Coding Challenge\n",
"\n",
"PD control for a Ball on beam device. The device is to sense the position of a ball on a 50cm beam, compare to a setpoint, and adjust beam position with servo motor. The setpoint and control constant is to be given by the device user. Display all relevant data. Use a button to start and stop operation.\n",
"\n",
"Devices:\n",
"\n",
"* Distance sensor - sense ball position\n",
"* Analog actuator - change beam angle\n",
"* Analog sensor - proportional gain\n",
"* Analog sensor - derivative time\n",
"* Analog sensor - setpoint\n",
"* Display - display position, angle\n",
"* Display - display control parameters\n",
"* Button - Start/Stop\n",
"\n",
"Create code to:\n",
"\n",
"* Measure the ball position\n",
"* Perform an action in response to the analog signal\n",
"* Display state on LCD\n",
"* Use on-board LED to show operational status"
]
},
{
"cell_type": "markdown",
"id": "63c19406-7f7a-46d3-9122-e279fac19490",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.2 Coding Paradigms](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.2-Coding-Paradigms)",
"section": "6.3.2 Coding Paradigms"
}
},
"source": [
"## 6.3.2 Coding Paradigms\n",
"\n",
"* Single threaded, imperative coding\n",
"\n",
"* Python classes\n",
" * further modularizes coding\n",
" * data logging classes* Python classes\n",
" * further modularizes coding\n",
" * data logging classes\n",
" \n",
"* Python generators\n",
" * separates event loop from device details\n",
" * modularizes the device coding\n",
" * each device can maintain a separate state\n",
"\n",
"* Asynchronous coding\n",
" * further abstraction the event loop\n",
" * non-blocking\n",
"* multi-threading"
]
},
{
"cell_type": "markdown",
"id": "4dee46d6-1e28-4d3f-b6f6-eff59accf5a1",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.3 Single threaded, imperative coding](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.3-Single-threaded,-imperative-coding)",
"section": "6.3.3 Single threaded, imperative coding"
}
},
"source": [
"## 6.3.3 Single threaded, imperative coding"
]
},
{
"cell_type": "code",
"execution_count": 67,
"id": "c807402f-f343-4634-b315-a2674998e756",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.3 Single threaded, imperative coding](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.3-Single-threaded,-imperative-coding)",
"section": "6.3.3 Single threaded, imperative coding"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"."
]
}
],
"source": [
"from machine import Pin, PWM\n",
"import time\n",
"\n",
"class Servo(object):\n",
" def __init__(self, gpio, freq=50):\n",
" self.gpio = gpio\n",
" self.pwm = PWM(Pin(gpio, Pin.IN))\n",
" self.pwm.freq(freq)\n",
" self.pwm.duty_ns(0)\n",
" \n",
" def set_value(self, value):\n",
" self.pulse_us = 500 + 20*max(0, min(100, value))\n",
" self.pwm.duty_ns(int(1000*self.pulse_us))\n",
" \n",
" def off(self):\n",
" self.pwm.duty_ns(0)\n",
" \n",
"\n",
"servo = Servo(16)\n",
"\n",
"servo.set_value(0)\n",
"time.sleep(2)\n",
"servo.set_value(100)\n",
"time.sleep(2)\n",
" \n",
"servo.off()"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "d0bd65f2-1d41-483a-8bfa-f7f5de0ff8d6",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.3 Single threaded, imperative coding](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.3-Single-threaded,-imperative-coding)",
"section": "6.3.3 Single threaded, imperative coding"
}
},
"outputs": [],
"source": [
"from machine import Pin, I2C\n",
"from lcd1602 import LCD1602 as LCD\n",
"\n",
"\n",
"class Screen(object):\n",
" def __init__(self, id, sda, scl):\n",
" self.sda = Pin(sda, Pin.OUT)\n",
" self.scl = Pin(scl, Pin.OUT)\n",
" self.i2c = I2C(id, sda=self.sda, scl=self.scl)\n",
" self.lcd = LCD(self.i2c, 2, 16)\n",
" self.lcd.clear()\n",
" \n",
" def print(self, lines):\n",
" for k, line in enumerate(lines):\n",
" if line is not None:\n",
" self.lcd.setCursor(0, k)\n",
" self.lcd.print(line)\n",
" \n",
" \n",
"screen0 = Screen(0, sda=8, scl=9)\n",
"screen1 = Screen(1, sda=6, scl=7)\n",
" \n",
"screen0.print((\"Hello World\", \"Go Irish!\"))\n",
"screen1.print([\"\", \"Hello\"])\n"
]
},
{
"cell_type": "code",
"execution_count": 107,
"id": "0707702e-4571-4c2c-b738-eee6d9ecbb7f",
"metadata": {
"nbpages": {
"level": 2,
"link": "[6.3.3 Single threaded, imperative coding](https://jckantor.github.io/cbe61622/06.03-Coding-Paradigms.html#6.3.3-Single-threaded,-imperative-coding)",
"section": "6.3.3 Single threaded, imperative coding"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"[missing-OK]O\n",
"[missing-OK]\n",
"[missing-OK]"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Traceback (most recent call last):\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"[missing-OK]"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
" File \" "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "MicroPython - USB",
"language": "micropython",
"name": "micropython"
},
"language_info": {
"codemirror_mode": "python",
"file_extension": ".py",
"mimetype": "text/python",
"name": "micropython"
}
},
"nbformat": 4,
"nbformat_minor": 5
}