diff --git a/docs/api.rst b/docs/api.rst index 9fe63d8..214a6dc 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -56,6 +56,21 @@ Speaker :inherited-members: :members: +Motor +----- + +.. autoclass:: Motor + :show-inheritance: + :inherited-members: + :members: + +Robot / Rover +------------- + +.. autoclass:: Robot + :show-inheritance: + :inherited-members: + :members: DigitalOutputDevice ------------------- @@ -87,22 +102,30 @@ Switch :inherited-members: :members: -Potentiometer -------------- +Potentiometer / Pot +------------------- .. autoclass:: Potentiometer :show-inheritance: :inherited-members: :members: -TemperatureSensor ------------------ +TemperatureSensor / TempSensor / Thermistor +------------------------------------------- .. autoclass:: TemperatureSensor :show-inheritance: :inherited-members: :members: +DistanceSensor +-------------- + +.. autoclass:: DistanceSensor + :show-inheritance: + :inherited-members: + :members: + DigitalInputDevice ------------------ diff --git a/docs/changelog.rst b/docs/changelog.rst index 9545d05..57416ff 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,7 +6,7 @@ Change log 0.2.0 - 2022-06-29 ~~~~~~~~~~~~~~~~~~ -+ Compatibility fix LED ++ Pico W compatibility fix for onboard LED 0.1.1 - 2022-06-08 ~~~~~~~~~~~~~~~~~~ diff --git a/docs/conf.py b/docs/conf.py index b2531ed..939fda6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,6 +38,7 @@ def __getattr__(cls, name): # add the ticks_ms function to time (as it is in micropython) import time setattr(time, 'ticks_ms', lambda x: None) +setattr(time, 'ticks_us', lambda x: None) # -- Project information ----------------------------------------------------- diff --git a/docs/developing.rst b/docs/developing.rst index 9117c88..37b53d7 100644 --- a/docs/developing.rst +++ b/docs/developing.rst @@ -38,13 +38,13 @@ Install sphinx using :: pip3 install sphinx -To build the documentation, run the following command from the docs directory :: +To test the documentation build, run the following command from the docs directory :: $ make html The website will be built in the directory docs/_build/html. -Documentation can be viewed at `picozero.readthedocs.io`_. +Documentation can be viewed at `picozero.readthedocs.io`_ and is automatically built and deployed on commit. .. _picozero.readthedocs.io: https://picozero.readthedocs.io @@ -59,4 +59,16 @@ The tests are design to be run on a Raspberry Pi Pico. 3. Copy the ``test_picozero.py`` to the pico. -4. Run the ``test_picozero.py`` file. \ No newline at end of file +4. Run the ``test_picozero.py`` file. + +If a test fails it is helpful to be able to see verbose error messages. To see error messages you need to modify the ``lib/unittest.py`` file on the pico. + +Locate the following code in the ``run_class`` function:: + + # Uncomment to investigate failure in detail + #raise + +Uncomment ``raise``:: + + # Uncomment to investigate failure in detail + raise \ No newline at end of file diff --git a/docs/examples/motor_move.py b/docs/examples/motor_move.py new file mode 100644 index 0000000..1a97ac0 --- /dev/null +++ b/docs/examples/motor_move.py @@ -0,0 +1,8 @@ +from picozero import Motor +from time import sleep + +motor = Motor(14, 15) + +motor.move() +sleep(1) +motor.stop() \ No newline at end of file diff --git a/docs/examples/robot_rover_forward.py b/docs/examples/robot_rover_forward.py new file mode 100644 index 0000000..8944ecc --- /dev/null +++ b/docs/examples/robot_rover_forward.py @@ -0,0 +1,9 @@ +from picozero import Robot +from time import sleep + +robot_rover = Robot(left=(14,15), right=(12,13)) + +# move forward +robot_rover.forward() +sleep(1) +robot_rover.stop() diff --git a/docs/examples/robot_rover_square.py b/docs/examples/robot_rover_square.py new file mode 100644 index 0000000..0b16ba7 --- /dev/null +++ b/docs/examples/robot_rover_square.py @@ -0,0 +1,10 @@ +from picozero import Robot +from time import sleep + +robot_rover = Robot(left=(14,15), right=(12,13)) + +for i in range(4): + # move forward for 1 second + robot_rover.forward(t=1, wait=True) + # rotate to the left for 1 second + robot_rover.left(t=1, wait=True) diff --git a/docs/examples/ultrasonic_distance_sensor.py b/docs/examples/ultrasonic_distance_sensor.py new file mode 100644 index 0000000..b2190df --- /dev/null +++ b/docs/examples/ultrasonic_distance_sensor.py @@ -0,0 +1,8 @@ +from picozero import DistanceSensor +from time import sleep + +ds = DistanceSensor(echo=4, trigger=5) + +while True: + print(ds.distance) + sleep(0.1) diff --git a/docs/images/distance_sensor_bb.svg b/docs/images/distance_sensor_bb.svg new file mode 100644 index 0000000..9aab5aa --- /dev/null +++ b/docs/images/distance_sensor_bb.svg @@ -0,0 +1,817 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + E + + + B + + + U + + + G + + + B + + + O + + + O + + + T + + + S + + + E + + + L + + + L + + + E + + + D + + + 1 + + + 2 + + + 3 + + + 9 + + + U + + + S + + + B + + + + R + + + a + + + s + + + p + + + b + + + e + + + r + + + r + + + y + + + + + + P + + + i + + + + + + P + + + i + + + c + + + o + + + + + + © + + + 2 + + + 0 + + + 2 + + + 0 + + + R + + + P + + + 2 + + + - + + + 8 + + + 0 + + + + + + + + + + + + + + + 2 + + + 0 + + + / + + + 2 + + + 1 + + + P + + + 6 + + + 4 + + + M + + + 1 + + + 5 + + + . + + + 0 + + + 0 + + + + + + T + + + T + + + T + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HC-SR04-P 3.3v version + + + \ No newline at end of file diff --git a/docs/images/robot_bb.svg b/docs/images/robot_bb.svg new file mode 100644 index 0000000..b41b7e4 --- /dev/null +++ b/docs/images/robot_bb.svg @@ -0,0 +1,8150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + E + + + B + + + U + + + G + + + B + + + O + + + O + + + T + + + S + + + E + + + L + + + L + + + E + + + D + + + 1 + + + 2 + + + 3 + + + 9 + + + U + + + S + + + B + + + + R + + + a + + + s + + + p + + + b + + + e + + + r + + + r + + + y + + + + + + P + + + i + + + + + + P + + + i + + + c + + + o + + + + + + © + + + 2 + + + 0 + + + 2 + + + 0 + + + R + + + P + + + 2 + + + - + + + 8 + + + 0 + + + + + + + + + + + + + + + 2 + + + 0 + + + / + + + 2 + + + 1 + + + P + + + 6 + + + 4 + + + M + + + 1 + + + 5 + + + . + + + 0 + + + 0 + + + + + + T + + + T + + + T + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + layer 21 + + + + + + + + + layer 21 + + + + + + + + + element:BR1 + + + + + + + + + package:J0402 + + + + + + + + + element:C1 + + + + + + + + + package:SMC_B + + + + + + + + + element:C2 + + + + + + + + + package:SMC_B + + + + + + + + + element:C3 + + + + + + + + + package:SMC_B + + + + + + + + + element:C4 + + + + + + + + + package:C0402 + + + + + + + + + element:C5 + + + + + + + + + package:C0402 + + + + + + + + + element:C6 + + + + + + + + + package:C0402 + + + + + + + + + element:C7 + + + + + + + + + package:C0402 + + + + + + + + + element:C8 + + + + + + + + + package:C0402 + + + + + + + + + element:C9 + + + + + + + + + package:C0402 + + + + + + + + + element:C10 + + + + + + + + + package:C0402 + + + + + + + + + element:C11 + + + + + + + + + package:SMC_B + + + + + + + + + element:C12 + + + + + + + + + package:C0402 + + + + + + + + + element:C13 + + + + + + + + + package:C0402 + + + + + + + + + element:C14 + + + + + + + + + package:C0402 + + + + + + + + + element:C15 + + + + + + + + + package:C0402 + + + + + + + + + element:C16 + + + + + + + + + package:C0402 + + + + + + + + + element:C17 + + + + + + + + + package:C0402 + + + + + + + + + element:C18 + + + + + + + + + package:C0402 + + + + + + + + + element:C19 + + + + + + + + + package:C0402 + + + + + + + + + element:C20 + + + + + + + + + package:C0402 + + + + + + + + + element:C21 + + + + + + + + + package:C0402 + + + + + + + + + element:C22 + + + + + + + + + package:C0402 + + + + + + + + + element:C23 + + + + + + + + + package:C0402 + + + + + + + + + element:C24 + + + + + + + + + package:C0402 + + + + + + + + + element:C25 + + + + + + + + + package:C0402 + + + + + + + + + element:C26 + + + + + + + + + package:C0402 + + + + + + + + + element:C27 + + + + + + + + + package:SMC_B + + + + + + + + + element:C28 + + + + + + + + + package:C0402 + + + + + + + + + element:C29 + + + + + + + + + package:SMC_B + + + + + + + + + element:C30 + + + + + + + + + package:C0402 + + + + + + + + + element:C31 + + + + + + + + + package:C0402 + + + + + + + + + element:C32 + + + + + + + + + package:C0402 + + + + + + + + + element:C33 + + + + + + + + + package:SMC_B + + + + + + + + + element:C34 + + + + + + + + + package:C0402 + + + + + + + + + element:C35 + + + + + + + + + package:SMC_B + + + + + + + + + element:C36 + + + + + + + + + package:C0402 + + + + + + + + + element:C37 + + + + + + + + + package:C0402 + + + + + + + + + element:C38 + + + + + + + + + package:C0402 + + + + + + + + + element:C39 + + + + + + + + + package:C0402 + + + + + + + + + element:C40 + + + + + + + + + package:C0402 + + + + + + + + + element:C41 + + + + + + + + + package:SMC_B + + + + + + + + + element:C42 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:F1 + + + + + + + + + package:L1812 + + + + + + + + + element:F2 + + + + + + + + + package:L1812 + + + + + + + + + element:FID1 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID2 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID3 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID4 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:JR1 + + + + + + + + + package:R0402 + + + + + + + + + element:L + + + + + + + + + text:L + + + + + + + + + element:ON + + + + + + + + + text:ON + + + + + + + + + element:Q2 + + + + + + + + + package:SOT23 + + + + + + + + + element:R1 + + + + + + + + + package:R0402 + + + + + + + + + element:R2 + + + + + + + + + package:R0402 + + + + + + + + + element:R3 + + + + + + + + + package:R0402 + + + + + + + + + element:R4 + + + + + + + + + package:R0402 + + + + + + + + + element:R5 + + + + + + + + + package:R0402 + + + + + + + + + element:R6 + + + + + + + + + package:R0402 + + + + + + + + + element:R7 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R8 + + + + + + + + + package:R0402 + + + + + + + + + element:R9 + + + + + + + + + package:R0402 + + + + + + + + + element:R10 + + + + + + + + + package:R0402 + + + + + + + + + element:R11 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R12 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R13 + + + + + + + + + package:R0402 + + + + + + + + + element:R14 + + + + + + + + + package:R0402 + + + + + + + + + element:R15 + + + + + + + + + package:R0402 + + + + + + + + + element:R18 + + + + + + + + + package:R0402 + + + + + + + + + element:R19 + + + + + + + + + package:R0402 + + + + + + + + + element:R20 + + + + + + + + + package:R0402 + + + + + + + + + element:R21 + + + + + + + + + package:R0402 + + + + + + + + + element:R23 + + + + + + + + + package:R0402 + + + + + + + + + element:RN1 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN2 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN3 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN4 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN5 + + + + + + + + + package:CAT16 + + + + + + + + + element:RX + + + + + + + + + text:RX + + + + + + + + + element:RX1 + + + + + + + + + text:RX1 + + + + + + + + + element:TX + + + + + + + + + text:TX + + + + + + + + + element:TX1 + + + + + + + + + text:TX1 + + + + + + + + + element:Z1 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z2 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z3 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z4 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z5 + + + + + + + + + package:CT/CN0603 + + + + + + + + + layer 25 + + + + + + + + + text:1 + + + + + + + + + text:MADE IN + + + + + + + + + text:ITALY + + + + + + + + + text:5V + + + + + + + + + text:5V + + + + + + + + + text:M.Banzi + + + + + + + + + text:D.Cuartielles + + + + + + + + + text:D.Mellis + + + + + + + + + text:G.Martino + + + + + + + + + text:T.Igoe + + + + + + + + + element:ADCH + + + + + + + + + package:1X08 + + + + + + + + + element:ADCL + + + + + + + + + package:1X08 + + + + + + + + + element:BR1 + + + + + + + + + package:J0402 + + + + + + + + + element:C1 + + + + + + + + + package:SMC_B + + + + + + + + + element:C2 + + + + + + + + + package:SMC_B + + + + + + + + + element:C3 + + + + + + + + + package:SMC_B + + + + + + + + + element:C4 + + + + + + + + + package:C0402 + + + + + + + + + element:C5 + + + + + + + + + package:C0402 + + + + + + + + + element:C6 + + + + + + + + + package:C0402 + + + + + + + + + element:C7 + + + + + + + + + package:C0402 + + + + + + + + + element:C8 + + + + + + + + + package:C0402 + + + + + + + + + element:C9 + + + + + + + + + package:C0402 + + + + + + + + + element:C10 + + + + + + + + + package:C0402 + + + + + + + + + element:C11 + + + + + + + + + package:SMC_B + + + + + + + + + element:C12 + + + + + + + + + package:C0402 + + + + + + + + + element:C13 + + + + + + + + + package:C0402 + + + + + + + + + element:C14 + + + + + + + + + package:C0402 + + + + + + + + + element:C15 + + + + + + + + + package:C0402 + + + + + + + + + element:C16 + + + + + + + + + package:C0402 + + + + + + + + + element:C17 + + + + + + + + + package:C0402 + + + + + + + + + element:C18 + + + + + + + + + package:C0402 + + + + + + + + + element:C19 + + + + + + + + + package:C0402 + + + + + + + + + element:C20 + + + + + + + + + package:C0402 + + + + + + + + + element:C21 + + + + + + + + + package:C0402 + + + + + + + + + element:C22 + + + + + + + + + package:C0402 + + + + + + + + + element:C23 + + + + + + + + + package:C0402 + + + + + + + + + element:C24 + + + + + + + + + package:C0402 + + + + + + + + + element:C25 + + + + + + + + + package:C0402 + + + + + + + + + element:C26 + + + + + + + + + package:C0402 + + + + + + + + + element:C27 + + + + + + + + + package:SMC_B + + + + + + + + + element:C28 + + + + + + + + + package:C0402 + + + + + + + + + element:C29 + + + + + + + + + package:SMC_B + + + + + + + + + element:C30 + + + + + + + + + package:C0402 + + + + + + + + + element:C31 + + + + + + + + + package:C0402 + + + + + + + + + element:C32 + + + + + + + + + package:C0402 + + + + + + + + + element:C33 + + + + + + + + + package:SMC_B + + + + + + + + + element:C34 + + + + + + + + + package:C0402 + + + + + + + + + element:C35 + + + + + + + + + package:SMC_B + + + + + + + + + element:C36 + + + + + + + + + package:C0402 + + + + + + + + + element:C37 + + + + + + + + + package:C0402 + + + + + + + + + element:C38 + + + + + + + + + package:C0402 + + + + + + + + + element:C39 + + + + + + + + + package:C0402 + + + + + + + + + element:C40 + + + + + + + + + package:C0402 + + + + + + + + + element:C41 + + + + + + + + + package:SMC_B + + + + + + + + + element:C42 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:D1 + + + + + + + + + package:SMB + + + + + + + + + element:D2 + + + + + + + + + package:MINIMELF + + + + + + + + + element:D3 + + + + + + + + + package:MINIMELF + + + + + + + + + element:D4 + + + + + + + + + package:DO220AAL + + + + + + + + + element:DEBUG + + + + + + + + + package:1X04 + + + + + + + + + element:F1 + + + + + + + + + package:L1812 + + + + + + + + + element:F2 + + + + + + + + + package:L1812 + + + + + + + + + element:FID1 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID2 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID3 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FID4 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:IC1 + + + + + + + + + package:MSOP08 + + + + + + + + + element:IC2 + + + + + + + + + package:SOT23-6 + + + + + + + + + element:IC6 + + + + + + + + + package:MLF32 + + + + + + + + + element:IC10 + + + + + + + + + package:SC70-5 + + + + + + + + + element:ICSP1 + + + + + + + + + package:2X03 + + + + + + + + + element:JR1 + + + + + + + + + package:R0402 + + + + + + + + + element:JTAG + + + + + + + + + package:PINHEAD_2X05_127 + + + + + + + + + element:L + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:L1 + + + + + + + + + package:0805 + + + + + + + + + element:L2 + + + + + + + + + package:0805 + + + + + + + + + element:L3 + + + + + + + + + package:0805 + + + + + + + + + element:L4 + + + + + + + + + package:SRR0604 + + + + + + + + + element:L5 + + + + + + + + + package:0805 + + + + + + + + + element:L6 + + + + + + + + + package:0805 + + + + + + + + + element:ON + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:PC1 + + + + + + + + + package:PANASONIC_D + + + + + + + + + element:PC2 + + + + + + + + + package:PANASONIC_D + + + + + + + + + element:PWMH + + + + + + + + + package:1X10 + + + + + + + + + element:PWML + + + + + + + + + package:1X08 + + + + + + + + + element:Q2 + + + + + + + + + package:SOT23 + + + + + + + + + element:R1 + + + + + + + + + package:R0402 + + + + + + + + + element:R2 + + + + + + + + + package:R0402 + + + + + + + + + element:R3 + + + + + + + + + package:R0402 + + + + + + + + + element:R4 + + + + + + + + + package:R0402 + + + + + + + + + element:R5 + + + + + + + + + package:R0402 + + + + + + + + + element:R6 + + + + + + + + + package:R0402 + + + + + + + + + element:R7 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R8 + + + + + + + + + package:R0402 + + + + + + + + + element:R9 + + + + + + + + + package:R0402 + + + + + + + + + element:R10 + + + + + + + + + package:R0402 + + + + + + + + + element:R11 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R12 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R13 + + + + + + + + + package:R0402 + + + + + + + + + element:R14 + + + + + + + + + package:R0402 + + + + + + + + + element:R15 + + + + + + + + + package:R0402 + + + + + + + + + element:R18 + + + + + + + + + package:R0402 + + + + + + + + + element:R19 + + + + + + + + + package:R0402 + + + + + + + + + element:R20 + + + + + + + + + package:R0402 + + + + + + + + + element:R21 + + + + + + + + + package:R0402 + + + + + + + + + element:R23 + + + + + + + + + package:R0402 + + + + + + + + + element:RESET + + + + + + + + + package:TS42 + + + + + + + + + element:RN1 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN2 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN3 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN4 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN5 + + + + + + + + + package:CAT16 + + + + + + + + + element:RX + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:RX1 + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:SPI + + + + + + + + + text:SPI + + + + + + + + + package:2X03 + + + + + + + + + element:T1 + + + + + + + + + package:SOT-23 + + + + + + + + + element:T2 + + + + + + + + + package:SOT-23 + + + + + + + + + element:T3 + + + + + + + + + package:SOT-23 + + + + + + + + + element:TX + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:TX1 + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:U1 + + + + + + + + + package:LQFP144 + + + + + + + + + element:XIO + + + + + + + + + text:XIO + + + + + + + + + package:2X18 + + + + + + + + + element:Y1 + + + + + + + + + package:CRYSTAL-3.2-2.5 + + + + + + + + + element:Y2 + + + + + + + + + package:RESONATOR_EPSON_FC_145 + + + + + + + + + element:Y4 + + + + + + + + + package:CRYSTAL-3.2-2.5 + + + + + + + + + element:Z1 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z2 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z3 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z4 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z5 + + + + + + + + + package:CT/CN0603 + + + + + + + + + text:Arduino + + + + + + + + + text:TM + + + + + + + + + text:DUE + + + + + + + + + layer 21 + + + + + + + + + text:0 + + + + + + + + + text:1 + + + + + + + + + text:2 + + + + + + + + + text:3 + + + + + + + + + text:4 + + + + + + + + + text:5 + + + + + + + + + text:6 + + + + + + + + + text:7 + + + + + + + + + text:8 + + + + + + + + + text:9 + + + + + + + + + text:10 + + + + + + + + + text:11 + + + + + + + + + text:12 + + + + + + + + + text:13 + + + + + + + + + text:14 + + + + + + + + + text:15 + + + + + + + + + text:22 + + + + + + + + + text:24 + + + + + + + + + text:26 + + + + + + + + + text:28 + + + + + + + + + text:30 + + + + + + + + + text:31 + + + + + + + + + text:32 + + + + + + + + + text:33 + + + + + + + + + text:34 + + + + + + + + + text:35 + + + + + + + + + text:36 + + + + + + + + + text:37 + + + + + + + + + text:38 + + + + + + + + + text:39 + + + + + + + + + text:41 + + + + + + + + + text:40 + + + + + + + + + text:43 + + + + + + + + + text:42 + + + + + + + + + text:45 + + + + + + + + + text:47 + + + + + + + + + text:49 + + + + + + + + + text:51 + + + + + + + + + text:44 + + + + + + + + + text:46 + + + + + + + + + text:50 + + + + + + + + + text:48 + + + + + + + + + text:53 + + + + + + + + + text:52 + + + + + + + + + element:C1 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C2 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C3 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C4 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C5 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C6 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C7 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C8 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C9 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C10 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C11 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C12 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C13 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C14 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C15 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:F1 + + + + + + + + + package:L1812 + + + + + + + + + element:FD1 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD2 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD3 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD4 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:GROUND + + + + + + + + + package:SJ + + + + + + + + + element:R1 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R2 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:RN1 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN2 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN3 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN4 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN5 + + + + + + + + + package:CAT16 + + + + + + + + + element:XIO + + + + + + + + + package:2X18 + + + + + + + + + element:Z1 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z2 + + + + + + + + + package:CT/CN0603 + + + + + + + + + layer 25 + + + + + + + + + text:ANALOG IN + + + + + + + + + text:ANALOG IN + + + + + + + + + text:VIN + + + + + + + + + text:GND + + + + + + + + + text:GND + + + + + + + + + text:TX3 + + + + + + + + + text:DIGITAL + + + + + + + + + text:M.Banzi + + + + + + + + + text:D.Cuartielles + + + + + + + + + text:D.Mellis + + + + + + + + + text:G.Martino + + + + + + + + + text:T.Igoe + + + + + + + + + text:SDA + + + + + + + + + text:SCL + + + + + + + + + element:C1 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C2 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C3 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C4 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C5 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C6 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C7 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C8 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C9 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C10 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C11 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C12 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C13 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C14 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:C15 + + + + + + + + + package:C0603-ROUND + + + + + + + + + element:D1 + + + + + + + + + package:SMB + + + + + + + + + element:D2 + + + + + + + + + package:MINIMELF + + + + + + + + + element:D3 + + + + + + + + + package:MINIMELF + + + + + + + + + element:F1 + + + + + + + + + package:L1812 + + + + + + + + + element:FD1 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD2 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD3 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:FD4 + + + + + + + + + package:FIDUCIA-MOUNT + + + + + + + + + element:GROUND + + + + + + + + + package:SJ + + + + + + + + + element:IC3 + + + + + + + + + package:TQFP100 + + + + + + + + + element:IC4 + + + + + + + + + package:MLF32 + + + + + + + + + element:IC6 + + + + + + + + + package:SOT23-DBV + + + + + + + + + element:IC7 + + + + + + + + + package:MSOP08 + + + + + + + + + element:L + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:L1 + + + + + + + + + package:0805 + + + + + + + + + element:R1 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:R2 + + + + + + + + + package:R0603-ROUND + + + + + + + + + element:RN1 + + + + + + + + + package:CAT16 + + + + + + + + + element:RN2 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN3 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN4 + + + + + + + + + package:CAY16 + + + + + + + + + element:RN5 + + + + + + + + + package:CAT16 + + + + + + + + + element:RX + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:T1 + + + + + + + + + package:SOT-23 + + + + + + + + + element:TX + + + + + + + + + package:CHIP-LED0805 + + + + + + + + + element:XIO + + + + + + + + + package:2X18 + + + + + + + + + text:XIO + + + + + + + + + element:Y1 + + + + + + + + + package:RESONATOR + + + + + + + + + element:Y2 + + + + + + + + + package:QS + + + + + + + + + element:Z1 + + + + + + + + + package:CT/CN0603 + + + + + + + + + element:Z2 + + + + + + + + + package:CT/CN0603 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/recipes.rst b/docs/recipes.rst index 5551529..4ceab28 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -154,7 +154,6 @@ Print the value, voltage and percent reported by a potentiometer: In the Thonny Python editor, choose View->Plotter to plot the output of :meth:`print`. - Buzzer ------ @@ -169,6 +168,29 @@ Control a passive buzzer or speaker that can play different tones or frequencies .. literalinclude:: examples/speaker.py +Motor +----- + +Move a motor which is connected via 2 pins (forward / backward) and a motor controller board + +.. literalinclude:: examples/motor_move.py + +Robot rover +------------- + +Make a simple 2 wheeled robot rover. + +.. image:: images/robot_bb.svg + :alt: A diagram of the Raspberry Pi Pico connected to 2 motors via a motor controller board powered by a battery pack + +Move the rover forward for 1 second and stop. + +.. literalinclude:: examples/robot_rover_forward.py + +Move the rover *roughly* in a square: + +.. literalinclude:: examples/robot_rover_square.py + Play a tune ~~~~~~~~~~~ @@ -188,4 +210,14 @@ Internal Temperature Sensor Check the internal temperature of the Raspberry Pi Pico in degrees Celcius: -.. literalinclude:: examples/pico_temperature.py \ No newline at end of file +.. literalinclude:: examples/pico_temperature.py + +Ultrasonic Distance Sensor +-------------------------- + +Get the distance in metres from an ultrasonic distance sensor (HC-SR04). + +.. image:: images/distance_sensor_bb.svg + :alt: A diagram of the Raspberry Pi Pico connected to HC-SR04 distance sensor + +.. literalinclude:: examples/ultrasonic_distance_sensor.py \ No newline at end of file diff --git a/docs/sketches/distance_sensor.fzz b/docs/sketches/distance_sensor.fzz new file mode 100644 index 0000000..6e26c36 Binary files /dev/null and b/docs/sketches/distance_sensor.fzz differ diff --git a/docs/images/pico_led_14.fzz b/docs/sketches/pico_led_14.fzz similarity index 100% rename from docs/images/pico_led_14.fzz rename to docs/sketches/pico_led_14.fzz diff --git a/docs/sketches/robot.fzz b/docs/sketches/robot.fzz new file mode 100644 index 0000000..7546c4d Binary files /dev/null and b/docs/sketches/robot.fzz differ diff --git a/examples/motor.py b/examples/motor.py new file mode 100644 index 0000000..2116b54 --- /dev/null +++ b/examples/motor.py @@ -0,0 +1,14 @@ +from picozero import Motor +from time import sleep + +m = Motor(12, 13) + +# turn the motor for 1 second +print("the motor is turning") +m.move() +sleep(1) +m.stop() + +# or alternatively turn it at half speed for 2 seconds +m.move(speed=0.5, t=2) +print("the motor will turn at half speed and stop after 2 seconds") \ No newline at end of file diff --git a/examples/ultrasonic_distance_sensor.py b/examples/ultrasonic_distance_sensor.py new file mode 100644 index 0000000..54c3e7c --- /dev/null +++ b/examples/ultrasonic_distance_sensor.py @@ -0,0 +1,8 @@ +from picozero import DistanceSensor +from time import sleep + +ds = DistanceSensor(5, 4) + +while True: + print(ds.distance) + sleep(0.1) \ No newline at end of file diff --git a/picozero/__init__.py b/picozero/__init__.py index 4847bf0..52e38f5 100644 --- a/picozero/__init__.py +++ b/picozero/__init__.py @@ -19,6 +19,8 @@ Speaker, RGBLED, + Motor, + Robot, DigitalInputDevice, Switch, @@ -32,4 +34,6 @@ pico_temp_sensor, TempSensor, Thermistor, + + DistanceSensor, ) diff --git a/picozero/picozero.py b/picozero/picozero.py index 608f573..3e58d24 100644 --- a/picozero/picozero.py +++ b/picozero/picozero.py @@ -1,6 +1,6 @@ from machine import Pin, PWM, Timer, ADC from micropython import schedule -from time import ticks_ms, sleep +from time import ticks_ms, ticks_us, sleep ############################################################################### # EXCEPTIONS @@ -41,7 +41,7 @@ def pins(self): """ Returns a tuple of pins used by the device """ - self._pin_nums + return self._pin_nums def __str__(self): return "{} (pins - {})".format(self.__class__.__name__, self._pin_nums) @@ -170,11 +170,27 @@ def value(self, value): self._stop_change() self._write(value) - def on(self): + def on(self, value=1, t=None, wait=False): """ Turns the device on. + + :param float value: + The value to set when turning on. Defaults to 1. + + :param float t: + The time in seconds the device should be on. If None is + specified, the device will stay on. The default is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the device will turn on in + the background. Defaults to False. Only effective if `t` is not + None. """ - self.value = 1 + if t is None: + self.value = value + else: + self._start_change(lambda : iter([(value, t), ]), 1, wait) def off(self): """ @@ -222,7 +238,10 @@ def blink(self, on_time=1, off_time=None, n=None, wait=False): off_time = on_time if off_time is None else off_time self.off() - self._start_change(lambda : iter([(1,on_time), (0,off_time)]), n, wait) + + # is there anything to change? + if on_time > 0 or off_time > 0: + self._start_change(lambda : iter([(1,on_time), (0,off_time)]), n, wait) def _start_change(self, generator, n, wait): self._value_changer = ValueChange(self, generator, n, wait) @@ -449,7 +468,7 @@ def blink_generator(): for i in range(int(fps * fade_in_time)) ]: yield s - + if on_time > 0: yield (1, on_time) @@ -459,11 +478,13 @@ def blink_generator(): for i in range(int(fps * fade_out_time)) ]: yield s - - if off_time > 0: - yield (0, off_time) - self._start_change(blink_generator, n, wait) + if off_time > 0: + yield (0, off_time) + + # is there anything to change? + if on_time > 0 or off_time > 0 or fade_in_time > 0 or fade_out_time > 0: + self._start_change(blink_generator, n, wait) def pulse(self, fade_in_time=1, fade_out_time=None, n=None, wait=False, fps=25): """ @@ -529,10 +550,10 @@ class PWMLED(PWMOutputDevice): """ PWMLED.brightness = PWMLED.value -def LED(pin, use_pwm=True, active_high=True, initial_value=False): +def LED(pin, pwm=True, active_high=True, initial_value=False): """ Returns an instance of :class:`DigitalLED` or :class:`PWMLED` depending on - the value of `use_pwm` parameter. + the value of `pwm` parameter. :: @@ -540,14 +561,14 @@ def LED(pin, use_pwm=True, active_high=True, initial_value=False): my_pwm_led = LED(1) - my_digital_led = LED(2, use_pwm=False) + my_digital_led = LED(2, pwm=False) :param int pin: The pin that the device is connected to. :param int pin: - If `use_pwm` is :data:`True` (the default), a :class:`PWMLED` will be - returned. If `use_pwm` is :data:`False`, a :class:`DigitalLED` will be + If `pwm` is :data:`True` (the default), a :class:`PWMLED` will be + returned. If `pwm` is :data:`False`, a :class:`DigitalLED` will be returned. A :class:`PWMLED` can control the brightness of the LED but uses 1 PWM channel. @@ -560,7 +581,7 @@ def LED(pin, use_pwm=True, active_high=True, initial_value=False): If :data:`False` (the default), the device will be off initially. If :data:`True`, the device will be switched on initially. """ - if use_pwm: + if pwm: return PWMLED( pin=pin, active_high=active_high, @@ -572,10 +593,10 @@ def LED(pin, use_pwm=True, active_high=True, initial_value=False): initial_value=initial_value) try: - pico_led = LED("LED", use_pwm=False) + pico_led = LED("LED", pwm=False) except TypeError: # older version of micropython before "LED" was supported - pico_led = LED(25, use_pwm=False) + pico_led = LED(25, pwm=False) class PWMBuzzer(PWMOutputDevice): """ @@ -867,19 +888,11 @@ def __init__(self, red=None, green=None, blue=None, active_high=True, for pin in (red, green, blue)) super().__init__(active_high, initial_value) - def __del__(self): - if getattr(self, '_leds', None): - self._stop_blink() - for led in self._leds: - led.__del__() - self._leds = () - super().__del__() - def _write(self, value): if type(value) is not tuple: value = (value, ) * 3 for led, v in zip(self._leds, value): - led.brightness = v + led.value = v @property def value(self): @@ -890,7 +903,7 @@ def value(self): For example, red would be ``(1, 0, 0)`` and yellow would be ``(1, 1, 0)``, while orange would be ``(1, 0.5, 0)``. """ - return tuple(led.brightness for led in self._leds) + return tuple(led.value for led in self._leds) @value.setter def value(self, value): @@ -1088,8 +1101,306 @@ def cycle(self, fade_times=1, colors=((1, 0, 0), (0, 1, 0), (0, 0, 1)), n=None, on_times = 0 self.blink(on_times, fade_times, colors, n, wait, fps) + def close(self): + super().close() + for led in self._leds: + led.close() + self._leds = None + RGBLED.colour = RGBLED.color +class Motor(PinsMixin): + """ + Represents a motor connected to a motor controller which has a 2 pin + input. One pin drives the motor "forward", the other drives the motor + "backward". + + :type forward: int + :param forward: + The GP pin that controls the "forward" motion of the motor. + + :type backward: int + :param backward: + The GP pin that controls the "backward" motion of the motor. + + :param bool pwm: + If :data:`True` (the default), PWM pins are used to drive the motor. + When using PWM pins values between 0 and 1 can be used to set the + speed. + + """ + def __init__(self, forward, backward, pwm=True): + self._pin_nums = (forward, backward) + self._forward = PWMOutputDevice(forward) if pwm else DigitalOutputDevice(forward) + self._backward = PWMOutputDevice(backward) if pwm else DigitalOutputDevice(backward) + + def on(self, speed=1, t=None, wait=False): + """ + Turns the motor on and makes it turn. + + :param float speed: + The speed as a value between -1 and 1. 1 turns the motor at + full speed direction, -1 turns the motor at full speed in + the opposite direction. Defaults to 1. + + :param float t: + The time in seconds the motor should run for. If None is + specified, the motor will stay on. The default is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + if speed > 0: + self._backward.off() + self._forward.on(speed, t, wait) + + elif speed < 0: + self._forward.off() + self._backward.on(-speed, t, wait) + + else: + self.off() + + def off(self): + """ + Stops the motor turning. + """ + self._backward.off() + self._forward.off() + + @property + def value(self): + """ + Sets or returns the motor speed as a value between -1 and 1. -1 is full + speed "backward", 1 is full speed "forward", 0 is stopped. + """ + return self._forward.value + (-self._backward.value) + + @value.setter + def value(self, value): + if value != 0: + self.on(value) + else: + self.stop() + + def forward(self, speed=1, t=None, wait=False): + """ + Makes the motor turn "forward". + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the motor should turn for. If None is + specified, the motor will stay on. The default is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self.on(speed, t, wait) + + def backward(self, speed=1, t=None, wait=False): + """ + Makes the motor turn "backward". + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the motor should turn for. If None is + specified, the motor will stay on. The default is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self.on(-speed, t, wait) + + def close(self): + """ + Closes the device and releases any resources. Once closed, the device + can no longer be used. + """ + self._forward.close() + self._backward.close() + +Motor.start = Motor.on +Motor.stop = Motor.off + +class Robot: + """ + Represent a generic dual-motor robot / rover / buggy. + + Alias for :class:`Rover` + + This class is constructed with two tuples representing the forward and + backward pins of the left and right controllers respectively. For example, + if the left motor's controller is connected to pins 12 and 13, while the + right motor's controller is connected to pins 14 and 15 then the following + example will drive the robot forward:: + + from picozero import Robot + + robot = Robot(left=(12, 13), right=(14, 15)) + robot.forward() + + :param tuple left: + A tuple of two pins representing the forward and backward inputs of the + left motor's controller. + + :param tuple right: + A tuple of two pins representing the forward and backward inputs of the + left motor's controller. + + :param bool pwm: + If :data:`True` (the default), pwm pins will be used, allowing ariable + speed control. + + """ + def __init__(self, left, right, pwm=True): + self._left = Motor(left[0], left[1], pwm) + self._right = Motor(right[0], right[1], pwm) + + @property + def left_motor(self): + """ + Returns the left :class:`Motor`. + """ + return self._left + + @property + def right_motor(self): + """ + Returns the right :class:`Motor`. + """ + return self._right + + @property + def value(self): + """ + Represents the motion of the robot as a tuple of (left_motor_speed, + right_motor_speed) with ``(-1, -1)`` representing full speed backwards, + ``(1, 1)`` representing full speed forwards, and ``(0, 0)`` + representing stopped. + """ + return (self._left.value, self._right.value) + + @value.setter + def value(self, value): + self._left.value, self._right.value = value + + def forward(self, speed=1, t=None, wait=False): + """ + Makes the robot move "forward". + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the robot should move for. If None is + specified, the robot will continue to move until stopped. The default + is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self._left.forward(speed, t, False) + self._right.forward(speed, t, wait) + + def backward(self, speed=1, t=None, wait=False): + """ + Makes the robot move "backward". + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the robot should move for. If None is + specified, the robot will continue to move until stopped. The default + is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self._left.backward(speed, t, False) + self._right.backward(speed, t, wait) + + def left(self, speed=1, t=None, wait=False): + """ + Makes the robot turn "left" by turning the left motor backward and the + right motor forward. + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the robot should turn for. If None is + specified, the robot will continue to turn until stopped. The default + is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self._left.backward(speed, t, False) + self._right.forward(speed, t, wait) + + def right(self, speed=1, t=None, wait=False): + """ + Makes the robot turn "right" by turning the left motor forward and the + right motor backward. + + :param float speed: + The speed as a value between 0 and 1. 1 is full speed. Defaults to 1. + + :param float t: + The time in seconds the robot should turn for. If None is + specified, the robot will continue to turn until stopped. The default + is None. + + :param bool wait: + If True the method will block until the time `t` has expired. + If False the method will return and the motor will turn on in + the background. Defaults to False. Only effective if `t` is not + None. + """ + self._left.forward(speed, t, False) + self._right.backward(speed, t, wait) + + def stop(self): + """ + Stops the robot. + """ + self._left.stop() + self._right.stop() + + def close(self): + """ + Closes the device and releases any resources. Once closed, the device + can no longer be used. + """ + self._left.close() + self._right.close() + +Rover = Robot + + ############################################################################### # INPUT DEVICES ############################################################################### @@ -1387,6 +1698,8 @@ class Potentiometer(AnalogInputDevice): Represents a Potentiometer which outputs with a variable voltage between 0 and 3.3V. + Alias for :class:`Pot`. + :param int pin: The pin that the device is connected to. @@ -1416,6 +1729,8 @@ class TemperatureSensor(AnalogInputDevice): can be converted to a temperature using a `conversion` function passed as a parameter. + Alias for :class:`Thermistor` and :class:`TempSensor`. + :param int pin: The pin that the device is connected to. @@ -1474,4 +1789,82 @@ def conversion(self, value): TempSensor = TemperatureSensor Thermistor = TemperatureSensor +class DistanceSensor(PinsMixin): + """ + Represents a HC-SR04 ultrasonic distance sensor. + + :param int echo: + The pin which the ECHO pin is connected to. + + :param int trigger: + The pin which the TRIG pin is connected to. + + :param float max_distance: + The :attr:`value` attribute reports a normalized value between 0 (too + close to measure) and 1 (maximum distance). This parameter specifies + the maximum distance expected in meters. This defaults to 1. + """ + def __init__(self, echo, trigger, max_distance=1): + self._pin_nums = (echo, trigger) + self._max_distance = max_distance + self._echo = Pin(echo, mode=Pin.IN, pull=Pin.PULL_DOWN) + self._trigger = Pin(trigger, mode=Pin.OUT, value=0) + + def _read(self): + echo_on = None + echo_off = None + timed_out = False + + self._trigger.off() + sleep(0.000005) + self._trigger.on() + sleep(0.00001) + self._trigger.off() + + # if an echo isnt measured in 100 milliseconds, it should + # be considered out of range the maximum length of the + # echo is 38 milliseconds but its not known how long the + # transmission takes after the trigger + stop = ticks_ms() + 100 + while echo_off is None and not timed_out: + if self._echo.value() == 1 and echo_on is None: + echo_on = ticks_us() + if echo_on is not None and self._echo.value() == 0: + echo_off = ticks_us() + if ticks_ms() > stop: + timed_out = True + + if echo_off is None or timed_out: + return None + else: + distance = ((echo_off - echo_on) * 0.000343) / 2 + distance = min(distance, self._max_distance) + return distance + + @property + def value(self): + """ + Returns a value between 0, indicating the reflector is either touching + the sensor or is sufficiently near that the sensor can’t tell the + difference, and 1, indicating the reflector is at or beyond the + specified max_distance. A return value of None indicates that the + echo was not received before the time out. + """ + distance = self.distance + return distance / self._max_distance if distance is not None else None + + @property + def distance(self): + """ + Returns the current distance measured by the sensor in meters. Note + that this property will have a value between 0 and max_distance. + """ + return self._read() + + @property + def max_distance(self): + """ + Returns the maximum distance that the sensor will measure in metres. + """ + return self._max_distance diff --git a/tests/test_picozero.py b/tests/test_picozero.py index 8da37dd..9b216f1 100644 --- a/tests/test_picozero.py +++ b/tests/test_picozero.py @@ -63,6 +63,10 @@ def reset(self): class Testpicozero(unittest.TestCase): + ########################################################################### + # OUTPUT DEVICES + ########################################################################### + def test_digital_output_device_default_values(self): d = DigitalOutputDevice(1) @@ -122,7 +126,7 @@ def test_digital_LED(self): d = DigitalLED(1) self.assertFalse(d.is_lit) d.close() - + def test_pwm_output_device_default_values(self): d = PWMOutputDevice(1) @@ -221,16 +225,148 @@ def test_pwm_output_device_pulse(self): self.fail(f"{len(values)} values were generated, {len(expected)} were expected.") d.close() + + def test_motor_default_values(self): + d = Motor(1,2) + + self.assertEqual(d.value, 0) + + d.on() + self.assertEqual(d.value, 1) + + d.stop() + self.assertEqual(d.value, 0) + + d.forward() + self.assertEqual(d.value, 1) + + d.backward() + self.assertEqual(d.value, -1) + + d.value = 0.5 + self.assertAlmostEqual(d.value, 0.5, places=2) + + d.value = -0.5 + self.assertAlmostEqual(d.value, -0.5, places=2) + + d.forward(1, t=0.5) + values = log_device_values(d, 0.6) + self.assertEqual(values, [1,0]) + self.assertEqual(d.value, 0) + + d.backward(1, t=0.5) + values = log_device_values(d, 0.6) + self.assertEqual(values, [-1,0]) + self.assertEqual(d.value, 0) + + d.close() + + def test_motor_alt_values(self): + d = Motor(1,2,pwm=False) + + d.value = 0.5 + self.assertEqual(d.value, 1) + + d.value = -0.5 + self.assertEqual(d.value, -1) + + d.value = 0 + self.assertEqual(d.value, 0) + + d.close() + + def test_robot(self): + d = Robot(left=(1,2), right=(3,4)) + + d.forward() + self.assertEqual(d.value, (1,1)) + + d.left() + self.assertEqual(d.value, (-1,1)) + + d.right() + self.assertEqual(d.value, (1,-1)) + + d.value = (0.5, -0.5) + self.assertAlmostEqual(d.left_motor.value, 0.5, places=2) + self.assertAlmostEqual(d.right_motor.value, -0.5, places=2) + + d.stop() + self.assertEqual(d.value, (0,0)) + + d.close() def test_LED_factory(self): d = LED(1) self.assertIsInstance(d, PWMLED) d.close() - d = LED(1, use_pwm=False) + d = LED(1, pwm=False) self.assertIsInstance(d, DigitalLED) d.close() + def test_pico_led(self): + + self.assertIsInstance(pico_led, DigitalLED) + + self.assertEqual(pico_led.value, 0) + + pico_led.on() + self.assertEqual(pico_led.value, 1) + + pico_led.off() + self.assertEqual(pico_led.value, 0) + + ########################################################################### + # INPUT DEVICES + ########################################################################### + + def test_rgb_led_default_values(self): + d = RGBLED(1,2,3) + + self.assertEqual(d.value, (0,0,0)) + + d.on() + self.assertEqual(d.value, (1,1,1)) + + d.off() + self.assertEqual(d.value, (0,0,0)) + + d.value = (0.25, 0.5, 0.75) + self.assertAlmostEqual(d.value[0], 0.25, places=2) + self.assertAlmostEqual(d.value[1], 0.5, places=2) + self.assertAlmostEqual(d.value[2], 0.75, places=2) + + d.red = 200 + self.assertAlmostEqual(d.value[0], 0.78, places=2) + + d.green = 100 + self.assertAlmostEqual(d.value[1], 0.39, places=2) + + d.blue = 50 + self.assertAlmostEqual(d.value[2], 0.20, places=2) + + d.close() + + def test_rgb_led_alt_values(self): + d = RGBLED(1,2,3, initial_value=(1,1,1), pwm=False) + + self.assertEqual(d.value, (1,1,1)) + + d.on() + self.assertEqual(d.value, (1,1,1)) + + d.off() + self.assertEqual(d.value, (0,0,0)) + + d.value = (1, 1, 1) + self.assertEqual(d.value, (1,1,1)) + + d.value = (0, 0.5, 1) + self.assertEqual(d.value, (0,1,1)) + + d.close() + def test_digital_input_device_default_values(self): d = DigitalInputDevice(1) @@ -375,5 +511,29 @@ def test_adc_input_device_threshold(self): d.close() + def test_temp_sensory(self): + + def temp_conversion(voltage): + return voltage + 2 + + t = TemperatureSensor(4, conversion=temp_conversion) + + adc = MockADC() + t._adc = adc + + adc.write(65535) + self.assertEqual(t.temp, 3.3 + 2) + + adc.write(0) + self.assertEqual(t.temp, 2) + + t.close() + + def test_pico_temp_sensor(self): + + self.assertIsInstance(pico_temp_sensor, TemperatureSensor) + self.assertEqual(pico_temp_sensor.pin, 4) + self.assertIsNotNone(pico_temp_sensor.temp) unittest.main() +