Last active
March 11, 2022 10:12
-
-
Save idriszmy/243931f88d4dd21b94764cfd1d55498f to your computer and use it in GitHub Desktop.
Hungry Robot, powered by Maker Pi RP2040 and CircuitPython.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Hungry Robot, powered by Maker Pi RP2040 and CircuitPython. | |
Items: | |
- Maker Pi RP2040 | |
https://my.cytron.io/p-maker-pi-rp2040-simplifying-robotics-with-raspberry-pi-rp2040 | |
- Analog Micro Servo 9g (3V-6V) | |
https://my.cytron.io/p-analog-micro-servo-9g-3v-6v | |
- Grove - Ultrasonic Ranger | |
https://my.cytron.io/p-grove-ultrasonic-ranger | |
- LiPo Rechargeable Battery 3.7V 1300mAH | |
https://my.cytron.io/p-lipo-rechargeable-battery-3.7v-1300mah | |
- 3D Printing products | |
https://my.cytron.io/c-3d-modeling | |
Libraries required from bundle (https://circuitpython.org/libraries): | |
- adafruit_motor | |
- simpleio.mpy | |
References: | |
- https://tutorial.cytron.io/2021/06/29/build-a-hungry-robot-using-rekabit-in-1-minute/ | |
Last update: 21 Feb 2022 | |
""" | |
import time | |
import board | |
import digitalio | |
import simpleio | |
import pwmio | |
from adafruit_motor import servo | |
import grove_ultrasonic_ranger | |
button1 = digitalio.DigitalInOut(board.GP20) | |
button1.direction = digitalio.Direction.INPUT | |
buzzer = board.BUZZER | |
NOTE_C4 = 261 | |
NOTE_G4 = 392 | |
sonar = grove_ultrasonic_ranger.GroveUltrasonicRanger(sig_pin=board.GP3) | |
pwm = pwmio.PWMOut(board.GP12, duty_cycle=2 ** 15, frequency=50) | |
my_servo = servo.Servo(pwm) | |
time.sleep(1) | |
my_servo.angle = 140 | |
time.sleep(0.25) | |
my_servo.angle = 160 | |
time.sleep(0.25) | |
pwm.deinit() | |
simpleio.tone(buzzer, NOTE_C4, duration=0.1) | |
simpleio.tone(buzzer, NOTE_G4, duration=0.15) | |
distance = 0 | |
while True: | |
distance = sonar.distance | |
print(distance) | |
if distance < 5: | |
time.sleep(1) | |
while distance < 5: | |
distance = sonar.distance | |
print(distance) | |
time.sleep(0.1) | |
pass | |
simpleio.tone(buzzer, NOTE_C4, duration=0.1) | |
pwm = pwmio.PWMOut(board.GP12, duty_cycle=2 ** 15, frequency=50) | |
my_servo = servo.Servo(pwm) | |
my_servo.angle = 160 | |
time.sleep(1) | |
my_servo.angle = 40 | |
time.sleep(0.25) | |
my_servo.angle = 160 | |
time.sleep(0.25) | |
pwm.deinit() | |
time.sleep(0.1) | |
if button1.value == False: | |
pwm.deinit() | |
break |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The MIT License (MIT) | |
# | |
# Copyright (c) 2017 Mike Mabey | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in | |
# all copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
# THE SOFTWARE. | |
""" | |
`grove_ultrasonic` | |
==================================================== | |
A CircuitPython library for the Grove ultrasonic range sensor. | |
Based on the CircuitPython library for the HC-SR04 ultrasonic range sensor. | |
The HC-SR04 functions by sending an ultrasonic signal, which is reflected by | |
many materials, and then sensing when the signal returns to the sensor. Knowing | |
that sound travels through dry air at `343.2 meters per second (at 20 °C) | |
<https://en.wikipedia.org/wiki/Speed_of_sound>`_, it's pretty straightforward | |
to calculate how far away the object is by timing how long the signal took to | |
go round-trip and do some simple arithmetic, which is handled for you by this | |
library. | |
* Original authors: | |
- Mike Mabey | |
- Jerry Needell - modified to add timeout while waiting for echo (2/26/2018) | |
- ladyada - compatible with `distance` property standard, renaming, Pi compat | |
""" | |
import time | |
from digitalio import DigitalInOut, Direction | |
# Took this idea from adafruit_debouncer.py | |
# Find out whether the current CircuitPython supports time.monotonic_ns(), | |
# which doesn't have the accuracy limitation. | |
if hasattr(time, "monotonic_ns"): | |
TICKS_PER_SEC = 1_000_000_000 | |
MONOTONIC_TICKS = time.monotonic_ns | |
else: | |
TICKS_PER_SEC = 1 | |
MONOTONIC_TICKS = time.monotonic | |
_USE_PULSEIO = False | |
try: | |
from pulseio import PulseIn | |
_USE_PULSEIO = True | |
except ImportError: | |
pass # This is OK, we'll try to bitbang it! | |
__version__ = "1.0.0" | |
__repo__ = "https://github.com/derhexenmeister/GroveUltrasonicRanger.git" | |
class GroveUltrasonicRanger: | |
"""Control a Grove ultrasonic range sensor. | |
Example use: | |
:: | |
import time | |
import board | |
import grove_ultrasonic_ranger | |
sonar = grove_ultrasonic_ranger.GroveUltrasonicRanger(sig_pin=board.D2) | |
while True: | |
try: | |
print((sonar.distance,)) | |
except RuntimeError as e: | |
print("Retrying due to exception =", e) | |
pass | |
time.sleep(0.1) | |
""" | |
def __init__(self, sig_pin, unit=1.0, timeout=1.0): | |
""" | |
:param sig_pin: The pin on the microcontroller that's connected to the | |
``Sig`` pin on the GroveUltrasonicRanger. | |
:type sig_pin: microcontroller.Pin | |
:param float unit: pass in conversion factor for unit conversions from cm | |
for example 2.54 would convert to inches. | |
:param float timeout: Max seconds to wait for a response from the | |
sensor before assuming it isn't going to answer. Should *not* be | |
set to less than 0.05 seconds! | |
""" | |
self._unit = unit | |
self._timeout = timeout*TICKS_PER_SEC | |
if _USE_PULSEIO: | |
self._sig = PulseIn(sig_pin) | |
self._sig.pause() | |
self._sig.clear() | |
else: | |
self._sig = DigitalInOut(sig_pin) | |
self._sig.direction = Direction.OUTPUT | |
self._sig.value = False # Set trig low | |
def __enter__(self): | |
"""Allows for use in context managers.""" | |
return self | |
def __exit__(self, exc_type, exc_val, exc_tb): | |
"""Automatically de-initialize after a context manager.""" | |
self.deinit() | |
def deinit(self): | |
"""De-initialize the sig pin.""" | |
self._sig.deinit() | |
@property | |
def distance(self): | |
"""Return the distance measured by the sensor in cm (or user specified units.) | |
This is the function that will be called most often in user code. The | |
distance is calculated by timing a pulse from the sensor, indicating | |
how long between when the sensor sent out an ultrasonic signal and when | |
it bounced back and was received again. | |
If no signal is received, we'll throw a RuntimeError exception. This means | |
either the sensor was moving too fast to be pointing in the right | |
direction to pick up the ultrasonic signal when it bounced back (less | |
likely), or the object off of which the signal bounced is too far away | |
for the sensor to handle. In my experience, the sensor can detect | |
objects over 460 cm away. | |
:return: Distance in centimeters (can be divided by a unit conv factor.) | |
:rtype: float | |
""" | |
return self._dist_one_wire() | |
def _dist_one_wire(self): | |
if _USE_PULSEIO: | |
self._sig.pause() | |
self._sig.clear() # Discard any previous pulse values | |
else: | |
#self._sig.direction = Direction.OUTPUT | |
self._sig.value = True # Set trig high | |
time.sleep(0.00001) # 10 micro seconds 10/1000/1000 | |
self._sig.value = False # Set trig low | |
self._sig.direction = Direction.INPUT | |
pulselen = None | |
timestamp = MONOTONIC_TICKS() | |
if _USE_PULSEIO: | |
self._sig.resume(10) | |
while not self._sig: | |
# Wait for a pulse | |
if (MONOTONIC_TICKS() - timestamp) > self._timeout: | |
self._sig.pause() | |
raise RuntimeError("Timed out (pulseio waiting for a pulse)") | |
self._sig.pause() | |
pulselen = self._sig[0] | |
else: | |
# OK no hardware pulse support, we'll just do it by hand! | |
# hang out while the pin is low | |
while not self._sig.value: | |
if MONOTONIC_TICKS() - timestamp > self._timeout: | |
self._sig.direction = Direction.OUTPUT | |
raise RuntimeError("Timed out (gpio, waiting for pulse leading edge)") | |
timestamp = MONOTONIC_TICKS() | |
# track how long pin is high | |
while self._sig.value: | |
if MONOTONIC_TICKS() - timestamp > self._timeout: | |
self._sig.direction = Direction.OUTPUT | |
raise RuntimeError("Timed out (gpio, waiting for pulse trailing edge)") | |
pulselen = MONOTONIC_TICKS() - timestamp | |
self._sig.direction = Direction.OUTPUT | |
pulselen *= (1000000/TICKS_PER_SEC) # convert to us to match pulseio | |
if pulselen >= 65535: | |
raise RuntimeError("Timed out (unreasonable pulse length)") | |
# positive pulse time, in seconds, times 340 meters/sec, then | |
# divided by 2 gives meters. Multiply by 100 for cm | |
# 1/1000000 s/us * 340 m/s * 100 cm/m * 2 = 0.017 | |
# Divide by the supplied unit conversion factor | |
return (pulselen * 0.017)/self._unit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment