micropython conversion
parent
3bc8093a18
commit
5f0ff276e9
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 91 KiB |
239
index.html
239
index.html
|
|
@ -41,26 +41,23 @@
|
|||
|
||||
<!-- Lesson 1 -->
|
||||
<section id="lesson1" class="lesson-content">
|
||||
<h1 class="text-3xl font-bold mt=0 mb-6">Setting up our Circuitpython toolchain</h1>
|
||||
<h1 class="text-3xl font-bold mt=0 mb-6">Setting up our MicroPython toolchain</h1>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="prose">
|
||||
<h2>Step 1: Setting up the IDE</h2>
|
||||
<p>There are many IDEs that we can use to program CircuitPython robot, we can even just use a text
|
||||
editor.</p>
|
||||
<p>However we'll be using one called "Mu Editor". So let's begin by downloading it.</p>
|
||||
<p>There are many IDEs that we can use to program MicroPython robot, we'll be using one called "Thonny". So let's begin by downloading it.</p>
|
||||
<h3>Download</h3>
|
||||
<ul class="ml-6 list-disc">
|
||||
<li><a href="files/MuEditor-win64-1.2.0.msi" class="text-blue-600 hover:underline">Windows</a>
|
||||
<li><a href="https://github.com/thonny/thonny/releases/download/v4.1.7/thonny-4.1.7.exe" class="text-blue-600 hover:underline">Windows</a>
|
||||
</li>
|
||||
<li><a href="files/MuEditor-Linux-1.2.0-x86_64.tar"
|
||||
class="text-blue-600 hover:underline">Linux</a></li>
|
||||
<li><a href="files/MuEditor-OSX-1.2.0.dmg" class="text-blue-600 hover:underline">Mac</a></li>
|
||||
|
||||
<li><a href="https://github.com/thonny/thonny/releases/download/v4.1.7/thonny-4.1.7.pkg" class="text-blue-600 hover:underline">Mac</a></li>
|
||||
</ul>
|
||||
<p>You can also get it from the Mu website, <a
|
||||
href="https://codewith.mu/en/">https://codewith.mu/en/</a></p>
|
||||
<p>You can also get it from the Thonny website, <a
|
||||
href="https://thonny.org/">https://thonny.org/</a></p>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
|
|
@ -68,21 +65,23 @@
|
|||
|
||||
<!-- Step 2: Image -->
|
||||
<div class="prose">
|
||||
<h2>Step 2: Install Circuitpython on board</h2>
|
||||
<h2>Step 2: Install MicroPython firmware on board</h2>
|
||||
<ol class="list-decimal ml-6">
|
||||
<li>Download the CircuitPython firmware UF2 file for the RP2040 Zero <a
|
||||
href="files/adafruit-circuitpython-waveshare_rp2040_zero-en_GB-9.2.8.uf2">here</a>.</li>
|
||||
<li>Connect your RP2040 Zero to your computer using a USB cable.</li>
|
||||
<li>Hold down the BOOT button, press and release the RST button.</li>
|
||||
<li>A new USB drive appears in your file explorer called <b>RPI-RP2</b>.</li>
|
||||
<li>Drag the downloaded CircuitPython firmware file into the <b>RPI-RP2</b> drive.</li>
|
||||
<li>The firmware will install, and after a moment, the drive should be called <b>CIRCUITPY</b>.
|
||||
</li>
|
||||
<li>Open the drive and examine the different files in there. The "code.py" file is our main
|
||||
file, but we won't open it here.</li>
|
||||
<li>Open the MU Editor, and we can start coding!</li>
|
||||
<li>In Thonny, click on the Run->Configure Interpreter buttons at the top of the window.</li>
|
||||
<li>Choose "MicroPython (Raspberry Pi Pico) from the first dropdown menu.</li>
|
||||
<li>Click the "<u>Install or update MicroPython</u>" button down the bottom-right of the window.</li>
|
||||
<li>You need to put your device in FLASH mode, hold down the BOOT button, press and release the RESET button.</li>
|
||||
<li>You should now find a drive called "RPI-RP2". in the Target volume dropdown, shoose it.</li>
|
||||
<li>Choose the variant "Raspberry Pi Pico - Pico / Pico H"</li>
|
||||
<li>Press Install button to install the firmware.</li>
|
||||
<li>Reset the device again with the RESET button.</li>
|
||||
<li>Press the cancel button to close the firmware update panel, then press OK to officially begin coding.</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div>
|
||||
<img src="images/thonny_firmware.png" alt="Robot moving further"
|
||||
class="rounded shadow w-full max-w-xs md:max-w-full" />
|
||||
</div>
|
||||
<div>
|
||||
<img src="images/rp2040zero.png" alt="Robot moving further"
|
||||
class="rounded shadow w-full max-w-xs md:max-w-full" />
|
||||
|
|
@ -94,15 +93,15 @@
|
|||
|
||||
<!-- Lesson 2 (hidden initially) -->
|
||||
<section id="lesson2" class="lesson-content hidden">
|
||||
<h1 class="text-3xl font-bold mb-6">The MU IDE</h1>
|
||||
<h1 class="text-3xl font-bold mb-6">The Thonny IDE</h1>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
|
||||
<!-- Step 1 -->
|
||||
<div class="prose">
|
||||
<h2>Step 1: Open the CIRCUITPY/code.py file</h2>
|
||||
<p>When your device is plugged into your computer, you should be able to find the CIRCUITPY drive in
|
||||
your list of drives. Open the code.py file on that drive using the "Load" button.</p>
|
||||
<h2>Step 1: Open/Create the main.py file</h2>
|
||||
<p>When your device is plugged into your computer, you should be able to press the File->Load button, and choose "Raspberry Pi Pico" to load from.</p>
|
||||
<p>If no such file exists we need to make it, press File->New, and then save it to the Raspberry Pi Pico as "main.py"</p>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
|
|
@ -111,15 +110,16 @@
|
|||
<!-- Step 2: Image -->
|
||||
<div class="prose">
|
||||
<h2>Step 2: Open the Serial Monitor</h2>
|
||||
<p>To get messages back from your device, and to read errors, press the "Serial" button nd make sure
|
||||
you have the "CircuitPython REPL" window open at the bottom.</p>
|
||||
<p>To get messages back from your device, and to read errors, press the view->shellbutton and make sure
|
||||
you have the shell window open at the bottom.</p>
|
||||
|
||||
</br>
|
||||
<h2>Step 3: Hello World</h2>
|
||||
<p>Your code is only updated on your device when you press "Save". If you write the code
|
||||
<p>Your code is only updated on your device when you press "Run". If you write the code
|
||||
<code>print("Hello World")</code> and then save, yuou should see the message appear in the
|
||||
Serial monitor.
|
||||
</p>
|
||||
<p>Note that the code won't persist on the robot after a reset unless you also SAVE it to the device, RUN just runs it once</p>
|
||||
|
||||
</br>
|
||||
<h2>Step 4: Code all the things!</h2>
|
||||
|
|
@ -129,22 +129,10 @@
|
|||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<img src="images/mu_editor.jpg" alt="Robot turning right"
|
||||
<img src="images/thonny_code.png" alt="Robot turning right"
|
||||
class="rounded shadow w-full max-w-xs md:max-w-full" />
|
||||
</div>
|
||||
<div class="prose">
|
||||
<h2>Note: Common Problems</h2>
|
||||
<p>If you see the ">>>" at the bottom of your serial monitor, and your code isn't running, that's
|
||||
because you've accidentally put the monitor into a special mode that lets you write code
|
||||
directly into serial. In this case your saved code won't run. To escape this mode, select the
|
||||
serial monitor, press "enter/return" a few times, and press CTRL-D.</p>
|
||||
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<img src="images/mu_editor_serialmode.jpg" alt="Robot turning right"
|
||||
class="rounded shadow w-full max-w-xs md:max-w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -196,27 +184,25 @@
|
|||
</div>
|
||||
<div>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm"><code class="language-python">
|
||||
import board
|
||||
import pwmio
|
||||
from machine import Pin, PWM
|
||||
import time
|
||||
|
||||
motorIN1 = pwmio.PWMOut(board.GP8, frequency=1000, duty_cycle=0)
|
||||
motorIN2 = pwmio.PWMOut(board.GP9, frequency=1000, duty_cycle=0)
|
||||
|
||||
motorIN1 = PWM(Pin(8))
|
||||
motorIN2 = PWM(Pin(9))
|
||||
|
||||
# DRIVE FORWARD
|
||||
motorIN1.duty_cycle = 65535 # This is the maximum value
|
||||
motorIN2.duty_cycle = 0 # This is the minimum value
|
||||
motorIN1.duty_u16(65535) # This is the maximum value
|
||||
motorIN2.duty_u16(0) # This is the minimum value
|
||||
time.sleep(1)
|
||||
|
||||
# DRIVE BACKWARD
|
||||
motorIN1.duty_cycle = 0
|
||||
motorIN2.duty_cycle = 65535
|
||||
motorIN1.duty_u16(0)
|
||||
motorIN2.duty_u16(65535)
|
||||
time.sleep(1)
|
||||
|
||||
# STOP
|
||||
motorIN1.duty_cycle = 0
|
||||
motorIN2.duty_cycle = 0 </code></pre>
|
||||
motorIN1.duty_u16(0)
|
||||
motorIN2.duty_u16(0) </code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
|
|
@ -228,13 +214,11 @@ motorIN2.duty_cycle = 0 </code></pre>
|
|||
</div>
|
||||
<div>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm"><code class="language-python">
|
||||
import board
|
||||
import pwmio
|
||||
import time
|
||||
from machine import Pin, PWM
|
||||
|
||||
# Initialize motor PWM pins
|
||||
motorIN1 = pwmio.PWMOut(board.GP8, frequency=1000, duty_cycle=0)
|
||||
motorIN2 = pwmio.PWMOut(board.GP9, frequency=1000, duty_cycle=0)
|
||||
motorIN1 = PWM(Pin(8))
|
||||
motorIN2 = PWM(Pin(9))
|
||||
|
||||
def motor(power):
|
||||
# Make sure power is never greater than 100 or less than -100
|
||||
|
|
@ -248,14 +232,14 @@ def motor(power):
|
|||
|
||||
# Apply power to the correct motor pin
|
||||
if power > 0:
|
||||
motorIN1.duty_cycle = duty
|
||||
motorIN2.duty_cycle = 0
|
||||
motorIN1.duty_u16(duty)
|
||||
motorIN2.duty_u16(0)
|
||||
elif power < 0:
|
||||
motorIN1.duty_cycle = 0
|
||||
motorIN2.duty_cycle = duty
|
||||
motorIN1.duty_u16(0)
|
||||
motorIN2.duty_u16(duty)
|
||||
else:
|
||||
motorIN1.duty_cycle = 0
|
||||
motorIN2.duty_cycle = 0
|
||||
motorIN1.duty_u16(0)
|
||||
motorIN2.duty_u16(0)
|
||||
|
||||
# TESTS
|
||||
motor(100) # FULL FORWARD
|
||||
|
|
@ -283,27 +267,26 @@ for i in range(-100, 100):
|
|||
<p>Now all we need to do from the main code is:</p>
|
||||
</br>
|
||||
<p>Import the module</p>
|
||||
<p><code>import motors</code></p>
|
||||
<p><code>from motor import Motor</code></p>
|
||||
</br>
|
||||
<p>Initialize a motor object</p>
|
||||
<p><code>left_motor = motor.Motor(board.GP8, board.GP9)</code></p>
|
||||
<p><code>left_motor = Motor(8, 9)</code></p>
|
||||
</br>
|
||||
<p>Set the power</p>
|
||||
<p><code>left_motor.move(100)</code></p>
|
||||
</br>
|
||||
<p>You can also add a second, third, or 20th motor at any time just by initializing another
|
||||
motor.Motor object.</p>
|
||||
<p><code>right_motor = motor.Motor(board.GP10, board.GP11)</code></p>
|
||||
Motor object.</p>
|
||||
<p><code>right_motor = Motor(10, 11)</code></p>
|
||||
</div>
|
||||
<div>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm">
|
||||
<code class="language-python">
|
||||
# code.py
|
||||
import board
|
||||
import time
|
||||
import motor
|
||||
|
||||
left_motor = motor.Motor(board.GP8, board.GP9)
|
||||
left_motor = motor.Motor(9,8)
|
||||
|
||||
# TESTS
|
||||
left_motor.move(100) # FULL FORWARD
|
||||
|
|
@ -321,15 +304,20 @@ for i in range(-100, 100):
|
|||
</code></pre>
|
||||
</br>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm">
|
||||
<code class="language-python"></code>
|
||||
<code class="language-python">
|
||||
# motor.py
|
||||
import pwmio
|
||||
from machine import Pin, PWM
|
||||
|
||||
class Motor:
|
||||
def __init__(self, in1, in2, frequency=1000):
|
||||
# Set up PWM outputs on the specified pins
|
||||
self.in1 = pwmio.PWMOut(in1, frequency=frequency, duty_cycle=0)
|
||||
self.in2 = pwmio.PWMOut(in2, frequency=frequency, duty_cycle=0)
|
||||
self.in1 = PWM(Pin(in1))
|
||||
self.in2 = PWM(Pin(in2))
|
||||
self.in1.freq(frequency)
|
||||
self.in2.freq(frequency)
|
||||
# Initialize duty to 0
|
||||
self.in1.duty_u16(0)
|
||||
self.in2.duty_u16(0)
|
||||
|
||||
def move(self, power):
|
||||
# Constrain power to -100 to 100
|
||||
|
|
@ -338,18 +326,18 @@ class Motor:
|
|||
elif power < -100:
|
||||
power = -100
|
||||
|
||||
# Scale to duty cycle
|
||||
# Scale to duty cycle (0–65535 for RP2040)
|
||||
duty = abs(power) * 65535 // 100
|
||||
|
||||
if power > 0:
|
||||
self.in1.duty_cycle = duty
|
||||
self.in2.duty_cycle = 0
|
||||
self.in1.duty_u16(duty)
|
||||
self.in2.duty_u16(0)
|
||||
elif power < 0:
|
||||
self.in1.duty_cycle = 0
|
||||
self.in2.duty_cycle = duty
|
||||
self.in1.duty_u16(0)
|
||||
self.in2.duty_u16(duty)
|
||||
else:
|
||||
self.in1.duty_cycle = 0
|
||||
self.in2.duty_cycle = 0
|
||||
self.in1.duty_u16(0)
|
||||
self.in2.duty_u16(0)
|
||||
|
||||
</code></pre>
|
||||
</div>
|
||||
|
|
@ -920,75 +908,68 @@ while True:
|
|||
<!-- Step 2 -->
|
||||
<div class="prose">
|
||||
<h2>Step 2: Coding</h2>
|
||||
<p>We'll use a library to handle sending and listening for the pulses. Put this module in your
|
||||
CIRCUITPY/lib folder.</p>
|
||||
<p>We'll use a library to handle sending and listening for the pulses. Put this module on your device.</p>
|
||||
</br>
|
||||
<p><a href="files/adafruit_hcsr04.py">adafruit_hcsr04.py</a></p>
|
||||
</br>
|
||||
<p>Note the <code>timeout=0.005</code>, this is important as it tells the code how long to wait for
|
||||
an ECHO. If we don't have that, our code could be blocked for quite a lot of time if the only
|
||||
obstacles are a long way away.</p>
|
||||
<p>When the "distance()" function is called, it sends a short pulse on the trigger pin, then waits for a response on the echo pin. The time it takes for the echo to return is used to calculate the distance.</p>
|
||||
|
||||
</br>
|
||||
<p>Even though all we really need is to get the distance with <code>sonar.distance</code>, when no
|
||||
echo is received in time an error will occur that will stop your code from running.</p>
|
||||
</br>
|
||||
<p>With our <code>try-except</code> block, any errors will just run whatever is in the
|
||||
<code>except</code> part. In this case, nothing.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm"><code class="language-python">
|
||||
import board
|
||||
import adafruit_hcsr04
|
||||
# sonar.py
|
||||
import machine
|
||||
import time
|
||||
|
||||
# Initialize the sonar device
|
||||
sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP26, echo_pin=board.GP28, timeout=0.005)
|
||||
class Sonar:
|
||||
def __init__(self, trigger_pin, echo_pin):
|
||||
self.trigger = machine.Pin(trigger_pin, machine.Pin.OUT)
|
||||
self.echo = machine.Pin(echo_pin, machine.Pin.IN)
|
||||
|
||||
while True:
|
||||
distance = 99
|
||||
def distance(self):
|
||||
# Send a 10µs pulse to trigger
|
||||
self.trigger.off()
|
||||
time.sleep_us(2)
|
||||
self.trigger.on()
|
||||
time.sleep_us(10)
|
||||
self.trigger.off()
|
||||
|
||||
# The try-except block catches errors that
|
||||
# occur when no signal returns in time
|
||||
try:
|
||||
distance = sonar.distance
|
||||
print(distance)
|
||||
except RuntimeError as e:
|
||||
pass
|
||||
# Wait for echo start
|
||||
while self.echo.value() == 0:
|
||||
pass
|
||||
start = time.ticks_us()
|
||||
|
||||
# Wait for echo end
|
||||
while self.echo.value() == 1:
|
||||
pass
|
||||
end = time.ticks_us()
|
||||
|
||||
# Calculate duration
|
||||
duration = time.ticks_diff(end, start)
|
||||
|
||||
# Convert to distance (speed of sound ~343 m/s)
|
||||
distance = (duration / 2) * 0.0343
|
||||
return int(distance)
|
||||
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div class="prose">
|
||||
<h2>Step 3: Clean it up a bit</h2>
|
||||
<p>To tidy up our main loop, we can move all that to a function so the main loop just needs
|
||||
<code>get_distance()</code>.
|
||||
</p>
|
||||
</br>
|
||||
<p>If your code is getting quite long, you might even take functions like this and put them in your
|
||||
own module to keep your main code easy to read.</p>
|
||||
<h2>Step 3: Call it in the main.py</h2>
|
||||
<p>Now all we need to do is create the object and call the distance function in the main.py file.</p>
|
||||
</div>
|
||||
<div>
|
||||
<pre class="bg-gray-100 p-4 rounded shadow text-sm"><code class="language-python">
|
||||
import board
|
||||
# main.py
|
||||
import time
|
||||
import adafruit_hcsr04
|
||||
import sonar
|
||||
|
||||
# Initialize the sonar device
|
||||
sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP26, echo_pin=board.GP28, timeout=0.005)
|
||||
|
||||
def get_distance():
|
||||
distance = 99
|
||||
try:
|
||||
distance = sonar.distance
|
||||
except RuntimeError as e:
|
||||
pass
|
||||
return distance
|
||||
# Create sonar object with trigger on GP3 and echo on GP2
|
||||
sonar = sonar.Sonar(trigger_pin=26, echo_pin=28)
|
||||
|
||||
while True:
|
||||
print(get_distance())
|
||||
time.sleep(0.1)
|
||||
dist = sonar.distance()
|
||||
print("Distance:", dist, "cm")
|
||||
time.sleep(1)
|
||||
</code></pre>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue