I would like to ask some help from you. I'm trying to connect a distance sensor to my microbit but when I use the command "time_pulse_us" it always gives -2 or -1. I read the documentation, I understand the meaning of those numbers but I think there's a problem with the command or probably I'm using it the wrong way.
In that regard, I wrote a simple snippet to test the command. Could you tell me what's wrong with it?
from microbit import * //to import microbit modules
from machine import * //to import the time_pulse_us command
while True:
pin1.write_digital(0)
time = time_pulse_us(pin2, 1) //to begin the timing
pin1.write_digital(1) //this pin is connected to an LED
sleep(1000)
value = pin2.read_digital() //gives 1, as this pin is reading the voltage from the led
pin1.write_digital(0) //this will make the time_pulse command to end timing
display.scroll(time) //it should display the duration of the pulse.
//Displays -2 instead.
display.scroll(value) //gives 1, as expected
Why is this not working?
time_pulse_us() runs sequentially, not in the background, so at the call it will wait 1 second for the pin to reach 1, which it will not do, hence time will be set to -2, before the program goes on to the next command write_digital(1).
Related
If I use the makecode editor to create the code, it generates:
pins.touch_set_mode(TouchTarget.P0, TouchTargetMode.CAPACITIVE)
However, if I try and run this, it can't find 'pins'.
Note: I then investigated further and found out how to do this before submitting my question...
Capacitive mode can be set for each pin, e.g.
from microbit import *
...
pin0.set_touch_mode(pin0.CAPACITIVE)
...
if pin0.is_touched():
...
The last line checks whether the pin is touched - usually in a loop.
Hope this saves other people some time...
I am new to pybricks and have found very little documentation to help answer my own query. I have written what I thought would be a simple program to spin my robot on the spot until the UltrasonicSensor sees something. It will then push forwards. If it is pushed backwards and sees a black line, it should try and swing out of the way.
The following code "works", but it's response to the Ultrasonic and Light sensors is significantly delayed:
#!/usr/bin/env pybricks-micropython
from pybricks.hubs import EV3Brick
from pybricks.ev3devices import Motor, ColorSensor, UltrasonicSensor
from pybricks.parameters import Port
from pybricks.tools import wait
ev3 = EV3Brick()
eyes = UltrasonicSensor(Port.S2)
left_motor = Motor(Port.B)
right_motor = Motor(Port.A)
right_light = ColorSensor(Port.S1)
left_light = ColorSensor(Port.S4)
while True:
if right_light.reflection() < 50:
ev3.speaker.say('black')
left_motor.run(500)
right_motor.run(-100)
wait(2000)
left_motor.run(500)
right_motor.run(500)
wait(1000)
if eyes.distance() > 200:
left_motor.run(500)
right_motor.run(-500)
else:
left_motor.run(-500)
right_motor.run(-500)
I can see in the (limited) documentation that you can apparently change motor settings but I can't find direction on how to do this (or even if it would be useful). Any help would be appreciated.
ev3.speaker.say(text) synthesizes speech as it goes. This is fun, but it is very slow. This is especially noticeable in a control loop like yours.
I'd recommend using ev3.speaker.beep() instead. You could even select the frequency based on the reflection value so you can "hear" what the sensor "sees".
So the problem was that I used the "run" command to move the motors. Run appears to have an acceleration and deceleration component.
I used "dc" instead of "run" and the motors instantly respond to the sensor data now.
MicroPython 2.0 beta 5
Trying to understand how the stalled() function on the motor works. I run a motor at dc of 100, and hold the wheel so that it cannot move.
But the stalled function doesn't fire, indeed whatever I do I don't seem able to get it to return True?
I tried with less power, but still not able to get anything out of this function.
#!/usr/bin/env pybricks-micropython
from pybricks import ev3brick as brick
from pybricks.ev3devices import Motor
from pybricks.parameters import Port, Stop
left_motor = Motor(Port.B)
speed = 800
# option 1
left_motor.dc(100)
# option 2
#left_motor.run_until_stalled(speed, Stop.HOLD, 100)
while True:
if left_motor.stalled():
print("stalled")
If I use option 1: the motor runs, I hold it until it stops, nothing reported. I let go and off it goes again.
If I use option 2: the motor runs, I hold it, it stops. But at no point do I see a report saying it stalled.
A motor is stalled when it can't reach its target speed or angle, despite applying the maximum duty cycle.
Your example can be adapted like this:
#!/usr/bin/env pybricks-micropython
from pybricks.ev3devices import Motor
from pybricks.parameters import Port
from pybricks.tools import wait
# Initialize the motor
left_motor = Motor(Port.B)
# Start running the motor at 500 deg/s
left_motor.run(500)
# Do nothing until we are stalled
while not left_motor.stalled():
wait(10)
# Stop the motor
left_motor.stop()
This example is equivalent to the one-liner left_motor.run_until_stalled(500). The manual approach can be useful if you want to extend it to multiple motors.
The dc() method in the question does not set a target speed or angle; it sets the duty cycle directly, so there is no stall information.
Note: the left_motor.stalled() method is instead accessible through left_motor.control.stalled() as of Pybricks version Pybricks 2.0. It is in public beta only as of March 2020, so I'm not sure the version reported in the original post in August 2019 is correct.
I have this code ipython code:
import ipywidgets as widgets
from IPython.display import display
import time
w = widgets.Dropdown(
options=['Addition', 'Multiplication', 'Subtraction'],
value='Addition',
description='Task:',
)
def on_change(change):
print("changed to %s" % change['new'])
w.observe(on_change)
display(w)
It works as expected. When the value of the widget changes, the on_change function gets triggered. However, I want to run a long computation and periodically check for updates to the widget. For example:
for i in range(100):
time.sleep(1)
# pull for changes to w here.
# if w.has_changed:
# print(w.value)
How can I achieve this?
For reference, I seem to be able to do the desired polling with
import IPython
ipython = IPython.get_ipython()
ipython.kernel.do_one_iteration()
(I'd still love to have some feedback on whether this works by accident or design.)
I think you need to use threads and hook into the ZMQ event loop. This gist illustrates an example:
https://gist.github.com/maartenbreddels/3378e8257bf0ee18cfcbdacce6e6a77e
Also see https://github.com/jupyter-widgets/ipywidgets/issues/642.
To elaborate on the OP's self answer, this does work. It forces the widgets to sync with the kernel at an arbitrary point in the loop. This can be done right before the accessing the widget.value.
So the full solution would be:
import IPython
ipython = IPython.get_ipython()
last_val = 0
for i in range(100):
time.sleep(1)
ipython.kernel.do_one_iteration()
new_val = w.value
if new_val != old_val:
print(new_val)
old_val = new_val
A slight improvement to the ipython.kernel.do_one_iteration call used
# Max iteration limit, in case I don't know what I'm doing here...
for _ in range(100):
ipython.kernel.do_one_iteration()
if ipython.kernel.msg_queue.empty():
break
In my case, I had a number of UI elements, that could be clicked multiple times between do_one_iteration calls, which will process them one at a time, and with a 1 second time delay, that could get annoying. This will process at most 100 at a time. Tested it by mashing a button multiple times, and now they all get processes as soon as the sleep(1) ends.
I have a question. I have a Raspberry Pi connected to PiFace Relay Plus and PiFace Motor Extra. Is it possible to run two or more motors at the same time?
I have no problem with running one motor:
import pifacerelayplus
import time
pfr = pifacerelayplus.PiFaceRelayPlus(pifacerelayplus.MOTOR_DC)
pfr.motors[0].forward()
time.sleep(5)
pfr.motors[0].coast()
I also managed to run one motor and than next one:
import pifacerelayplus
import time
pfr = pifacerelayplus.PiFaceRelayPlus(pifacerelayplus.MOTOR_DC)
pfr.motors[0].forward()
time.sleep(5)
pfr.motors[0].coast()
time.sleep(2)
pfr.motors[1].forward()
time.sleep(5)
time.motors[1].coast()
But I can't find out how to make both motors run at the same time. I tried this code, but that only runs the first motor, than the program ends and the first motor still runs and never stops. The second motor never starts to run.
import pifacerelayplus
import time
pfr = pifacerelayplus.PiFaceRelayPlus(pifacerelayplus.MOTOR_DC)
pfr.motors[0].forward()
pfr.motors[1].forward()
time.sleep(5)
pfr.motors[0].coast()
pfr.motors[1].coast()
I even tried to create another variable "prf2" for second motor, but it didn't help neither. I'm glad for any help.
Are you getting any error when running the program? Looking at the source code of pifacerelayplus, it is INTENDED to fail if you give two motor commands within 0.15 seconds, on the grounds that the startup surge of two motors at once is likely to be more than your power supply can handle. A couple of short sleep()s should avoid this issue.