Is there a Bug in motor.run_target command? - micropython

MicroPython 1.0.0,
ev3dev Linux echo 4.14.96-ev3dev-2.3.2-ev3 #1 PREEMPT Sun Jan 27 21:27:35 CST 2019 armv5tejl GNU/Linux
#!/usr/bin/env pybricks-micropython
from pybricks import ev3brick as brick
from pybricks.ev3devices import Motor
from pybricks.parameters import Port, Stop
from pybricks.tools import print, wait
leftMotor = Motor(Port.B)
rightMotor = Motor(Port.C)
# speed range -100 to 100
def leftWheel():
leftMotor.run_target(50, 360, Stop.COAST, True)
def rightWheel():
rightMotor.run_target(50, -360, Stop.COAST, True)
leftWheel()
rightWheel()
This works if I use True, so it runs left then right. But if I set it false it does nothing. [should run both in parallel]

When you choose wait=False, the run_target command is initiated and your program continues with the rest of your program right away. The motor completes its command in the background.
But if there is nothing else in your program, the program ends right away. And when the program ends, the motors are stopped so you don't see any movement in this case.
You will see the motors move if there is something else in your program like a wait:
#!/usr/bin/env pybricks-micropython
from pybricks import ev3brick as brick
from pybricks.ev3devices import Motor
from pybricks.parameters import Port, Stop
from pybricks.tools import print, wait
left_motor = Motor(Port.B)
right_motor = Motor(Port.C)
# Initiate the run target commands, without waiting for completion.
left_motor.run_target(50, 360, Stop.COAST, False)
right_motor.run_target(50, -360, Stop.COAST, False)
# Do something else while the motors are moving, like waiting.
wait(10000)
If your goal is to wait until both motors have reached their target, you could instead wait until the angle values of each motor equal your given targets:
#!/usr/bin/env pybricks-micropython
from pybricks import ev3brick as brick
from pybricks.ev3devices import Motor
from pybricks.parameters import Port, Stop
from pybricks.tools import print, wait
left_motor = Motor(Port.B)
right_motor = Motor(Port.C)
target_left = 360
target_right = -360
tolerance = 2
left_motor.run_target(50, target_left, Stop.COAST, False)
right_motor.run_target(50, target_right, Stop.COAST, False)
# Wait until both motors have reached their targets up to a desired tolerance.
while abs(left_motor.angle()-target_left) > tolerance or abs(right_motor.angle()-target_right) > tolerance:
wait(10)
# Make a sound when we're done.
brick.sound.beep()

Related

Get current position of servo with MicroPython on a Raspberry Pi Pico

I am running MicroPython on a Raspberry Pi Pico. I can set the position of the servo by changing the duty cycles:
from machine import Pin, PWM
servo = PWM(Pin(0))
servo.freq(50)
servo.duty_u16(1350) # sets position to 0 degrees
I may have missed something, but I have read through the docs and couldn't find any way to read the current position of the servo. Is there any way to do this?
Most servos do not provide any sort of position information. You know what the position is because you set it. You can write code that will keep track of this value for you. For example, something like:
from machine import Pin, PWM
class Servo:
min_duty = 40
max_duty = 1115
def __init__(self, pin):
servo = PWM(Pin(pin))
servo.freq(50)
self.servo = servo
self.setpos(90)
def setpos(self, pos):
'''Scale the angular position to a value between self.min_duty
and self.max_duty.'''
if pos < 0 or pos > 180:
raise ValueError(pos)
self.pos = pos
duty = int((pos/180) * (self.max_duty - self.min_duty) + self.min_duty)
self.servo.duty(duty)
You would use the Servo class like this:
>>> s = Servo(18)
>>> s.pos
90
>>> s.setpos(180)
>>> s.pos
180
>>> s.setpos(0)
>>> s.pos
0
>>>
In your question, you have:
servo.duty_u16(1350)
I'm suspicious of this value: at 50Hz, the duty cycle is typically between 40 and 115 (+/1 some small amount at either end), corresponding to ≈ 1ms (duty=40) to 2ms (duty=115).

Micropython error : OSError: [Errno 19] ENODEV

I am trying to use pressure sensors and a LOLIN D32 pro microcontroller to measure water level. The two pressure sensors are MS5803 and BME280 below is my code
'''
import machine
from machine import Pin, I2C
import bme280, ms5803
import time
i2c= I2C(scl=Pin(22), sda=Pin(21), freq=10000)
bme1 = bme280.BME280(i2c=i2c, address = 119)
BuiltinLED = machine.Pin(5, Pin.OUT)
BuiltinLED.value(1)
WaterLevelDifference=0
def depth():
[T1,P1,H1] = bme1.raw_values #T in degrees C, P in hPa
[P2,T2] = ms5803.read(i2c=i2c, address = 118)
WaterLevelDifference = ((P2-P1)*100/9810)
return WaterLevelDifference
depth()
while WaterLevelDifference<100:
if WaterLevelDifference > 0.1:
BuiltinLED.value(0) #turns LED on
else:
depth()
time.sleep(0.5)
print(WaterLevelDifference)
'''
I have done i2c.scan() and it shows [118,119] but sometimes intermittently. What does this error mean?

Can I use celery for every-second task?

I'm running a task every second, and it seems celery doesn't actually perform the task every second.
I guess celery might be a good scheduler for every 1 minute task, but might not be adequte for every second task.
Here's the picture which illustrates what I mean.
I'm using the following options
'schedule': 1.0,
'args': [],
'options': {
'expires': 3
}
And I'm using celery 4.0.0
Yes, Celery actually handles times as low as 1 second, and possibly lower since it takes a float. See this entry of periodic tasks in the docs http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html:
from celery import Celery
from celery.schedules import crontab
app = Celery()
#app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
# Calls test('hello') every 10 seconds.
sender.add_periodic_task(10.0, test.s('hello'), name='add every 10')
# Calls test('world') every 30 seconds
sender.add_periodic_task(30.0, test.s('world'), expires=10)
# Executes every Monday morning at 7:30 a.m.
sender.add_periodic_task(
crontab(hour=7, minute=30, day_of_week=1),
test.s('Happy Mondays!'),
)
#app.task
def test(arg):
print(arg)
A better written example can be found 1/3 the way down https://github.com/celery/celery/issues/3589:
# file: tasks.py
from celery import Celery
celery = Celery('tasks', broker='pyamqp://guest#localhost//')
#celery.task
def add(x, y):
return x + y
#celery.on_after_configure.connect
def add_periodic(**kwargs):
celery.add_periodic_task(10.0, add.s(2,3), name='add every 10')
So sender is the actual Celery broker, i.e. app = Celery()

Raspberry Pi PWM control becomes affected when I combine it with FLASK

Im trying to implement a control using Raspberry Pi's PWM. I had success controlling the intensity of a LED with the following code:
# Pin Definitons:
pwmPin = 18 # Broadcom pin 18 (P1 pin 12)
# Pin Setup:
GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme
GPIO.setup(pwmPin, GPIO.OUT) # PWM pin set as output
pwm = GPIO.PWM(pwmPin, 50) # Initialize PWM on pwmPin 100Hz frequency
# Initial state for LEDs:
pwm.start(10)
try:
while 1:
cycle = raw_input("Introduce Duty Cycle")
dc = int(cycle)
pwm.ChangeDutyCycle(dc)
except KeyboardInterrupt: # If CTRL+C is pressed, exit cleanly:
pwm.stop() # stop PWM
GPIO.cleanup() # cleanup all GPIO
Then I wanted to control the LED brightness through a web page. For that I used FLASK and the previous code. When I set the Duty Cycle from the web page the LED brightness change accordingly but it fluctuates randomly.
It's a strange behavior and I dont know why it is happening. Right here the code implemented on FLASK:
# Pin Definitons:
pwmPin = 18 # Broadcom pin 18 (P1 pin 12)
# Pin Setup:
GPIO.setmode(GPIO.BCM) # Broadcom pin-numbering scheme
GPIO.setup(pwmPin, GPIO.OUT) # PWM pin set as output
pwm = GPIO.PWM(pwmPin, 50) # Initialize PWM on pwmPin 100Hz frequency
# Initial state for LEDs:
pwm.start(10)
app = Flask(__name__)
#app.route('/')
def index():
return render_template('motor.html')
#app.route('/motor', methods=['POST'])
def motor():
dc = int(request.form['valor'])
pwm.ChangeDutyCycle(dc)
return redirect(url_for('index'))
if __name__ == "__main__":
app.run(host='0.0.0.0', port=81, debug=True)
pwm.stop() # stop PWM
GPIO.cleanup() # cleanup all GPIO

Simpy: How can I represent failures in a train subway simulation?

New python user here and first post on this great website. I haven't been able to find an answer to my question so hopefully it is unique.
Using simpy I am trying to create a train subway/metro simulation with failures and repairs periodically built into the system. These failures happen to the train but also to signals on sections of track and on plaforms. I have read and applied the official Machine Shop example (which you can see resemblance of in the attached code) and have thus managed to model random failures and repairs to the train by interrupting its 'journey time'.
However I have not figured out how to model failures of signals on the routes which the trains follow. I am currently just specifying a time for a trip from A to B, which does get interrupted but only due to train failure.
Is it possible to define each trip as its own process i.e. a separate process for sections A_to_B and B_to_C, and separate platforms as pA, pB and pC. Each one with a single resource (to allow only one train on it at a time) and to incorporate random failures and repairs for these section and platform processes? I would also need to perhaps have several sections between two platforms, any of which could experience a failure.
Any help would be greatly appreciated.
Here's my code so far:
import random
import simpy
import numpy
RANDOM_SEED = 1234
T_MEAN_A = 240.0 # mean journey time
T_MEAN_EXPO_A = 1/T_MEAN_A # for exponential distribution
T_MEAN_B = 240.0 # mean journey time
T_MEAN_EXPO_B = 1/T_MEAN_B # for exponential distribution
DWELL_TIME = 30.0 # amount of time train sits at platform for passengers
DWELL_TIME_EXPO = 1/DWELL_TIME
MTTF = 3600.0 # mean time to failure (seconds)
TTF_MEAN = 1/MTTF # for exponential distribution
REPAIR_TIME = 240.0
REPAIR_TIME_EXPO = 1/REPAIR_TIME
NUM_TRAINS = 1
SIM_TIME_DAYS = 100
SIM_TIME = 3600 * 18 * SIM_TIME_DAYS
SIM_TIME_HOURS = SIM_TIME/3600
# Defining the times for processes
def A_B(): # returns processing time for journey A to B
return random.expovariate(T_MEAN_EXPO_A) + random.expovariate(DWELL_TIME_EXPO)
def B_C(): # returns processing time for journey B to C
return random.expovariate(T_MEAN_EXPO_B) + random.expovariate(DWELL_TIME_EXPO)
def time_to_failure(): # returns time until next failure
return random.expovariate(TTF_MEAN)
# Defining the train
class Train(object):
def __init__(self, env, name, repair):
self.env = env
self.name = name
self.trips_complete = 0
self.broken = False
# Start "travelling" and "break_train" processes for the train
self.process = env.process(self.running(repair))
env.process(self.break_train())
def running(self, repair):
while True:
# start trip A_B
done_in = A_B()
while done_in:
try:
# going on the trip
start = self.env.now
yield self.env.timeout(done_in)
done_in = 0 # Set to 0 to exit while loop
except simpy.Interrupt:
self.broken = True
done_in -= self.env.now - start # How much time left?
with repair.request(priority = 1) as req:
yield req
yield self.env.timeout(random.expovariate(REPAIR_TIME_EXPO))
self.broken = False
# Trip is finished
self.trips_complete += 1
# start trip B_C
done_in = B_C()
while done_in:
try:
# going on the trip
start = self.env.now
yield self.env.timeout(done_in)
done_in = 0 # Set to 0 to exit while loop
except simpy.Interrupt:
self.broken = True
done_in -= self.env.now - start # How much time left?
with repair.request(priority = 1) as req:
yield req
yield self.env.timeout(random.expovariate(REPAIR_TIME_EXPO))
self.broken = False
# Trip is finished
self.trips_complete += 1
# Defining the failure
def break_train(self):
while True:
yield self.env.timeout(time_to_failure())
if not self.broken:
# Only break the train if it is currently working
self.process.interrupt()
# Setup and start the simulation
print('Train trip simulator')
random.seed(RANDOM_SEED) # Helps with reproduction
# Create an environment and start setup process
env = simpy.Environment()
repair = simpy.PreemptiveResource(env, capacity = 1)
trains = [Train(env, 'Train %d' % i, repair)
for i in range(NUM_TRAINS)]
# Execute
env.run(until = SIM_TIME)
# Analysis
trips = []
print('Train trips after %s hours of simulation' % SIM_TIME_HOURS)
for train in trains:
print('%s completed %d trips.' % (train.name, train.trips_complete))
trips.append(train.trips_complete)
mean_trips = numpy.mean(trips)
std_trips = numpy.std(trips)
print "mean trips: %d" % mean_trips
print "standard deviation trips: %d" % std_trips
it looks like you are using Python 2, which is a bit unfortunate, because
Python 3.3 and above give you some more flexibility with Python generators. But
your problem should be solveable in Python 2 nonetheless.
you can use sub processes within in a process:
def sub(env):
print('I am a sub process')
yield env.timeout(1)
# return 23 # Only works in py3.3 and above
env.exit(23) # Workaround for older python versions
def main(env):
print('I am the main process')
retval = yield env.process(sub(env))
print('Sub returned', retval)
As you can see, you can use Process instances returned by Environment.process()
like normal events. You can even use return values in your sub proceses.
If you use Python 3.3 or newer, you don’t have to explicitly start a new
sub-process but can use sub() as a sub routine instead and just forward the
events it yields:
def sub(env):
print('I am a sub routine')
yield env.timeout(1)
return 23
def main(env):
print('I am the main process')
retval = yield from sub(env)
print('Sub returned', retval)
You may also be able to model signals as resources that may either be used
by failure process or by a train. If the failure process requests the signal
at first, the train has to wait in front of the signal until the failure
process releases the signal resource. If the train is aleady passing the
signal (and thus has the resource), the signal cannot break. I don’t think
that’s a problem be cause the train can’t stop anyway. If it should be
a problem, just use a PreemptiveResource.
I hope this helps. Please feel welcome to join our mailing list for more
discussions.