Why does it take so long for background color to change? - sockets

I am running into a problem with a simple program that changes the color of the background when it receives a command from a different machine through TCP. It takes like thirty seconds to change the color. I am running this through the local network so it should be near instant response. I am using wxPython for the frame. I don't think I have overly complicated code. Relevant code:
threader=threading.Thread(target=self.threading)
threader.start()
def threading(self):
host="192.168.1.122"
port=4100
s=socket.socket()
s.bind((host,port))
s.listen(1)
c,addr=s.accept()
print "Connected"
while 1:
data=c.recv(1024)
if not data:
break
data=data.split("_")
reading=int(data[1])
pin=int(data[0])
if pin == 1:
if reading<20:
self.front_left.SetBackgroundColour("red")
elif pin == 2:
if reading<20:
self.front_right.SetBackgroundColour("red")
elif pin == 3:
if reading<20:
self.bottom_left.SetBackgroundColour("red")
elif pin == 4:
if reading<20:
self.bottom_right.SetBackgroundColour("red")
else:
pass
c.close()
I need this code to be instant as this will be going on a robot that will tell if objects are too close(which is why there is red background when it gets within 20 cm of object). Any help will be greatly appreciated!

It appears that you are attempting to update wxPython code from a thread. This action is unsupported / undefined in wxPython. You need to use thread-safe methods to update the wxPython UI, such as wx.CallAfter or wx.PostEvent. See the following wxPython wiki page for some examples:
http://wiki.wxpython.org/LongRunningTasks
Basically, you'll want to do something like this in your if statements:
wx.CallAfter(self.bottom_right.SetBackgroundColour, "red")

Related

How to write correct transitions?

I have a bot code that needs to be connected to a state machine, how to implement it correctly, please help me, I understand in theory how to do this, but in practice, it does not work
states.py
from transitions import Machine, State
from main import *
states = ['START',
'WAITING_YES',
'CHOOSE SIZE',
'GO PAY'
'CHOOSE PAY METHOD',
'REPEATING ORDER',
'FINISH']
machine = Machine(states=states, initial='START')
machine.add_transition('melt', source='START', dest='WAITING_YES')
if start:
print('-------------------',machine.state,'-------------------')
machine.add_ordered_transitions()
if waiting_yes:
machine.to_WAITING_YES()
print('-------------------',machine.state,'-------------------')
machine.next_state()
elif choose_size:
print('-------------------',machine.state,'-------------------')
machine.next_state()
elif choose_pay_method:
print('-------------------',machine.state,'-------------------')
machine.next_state()
elif repeating_order:
print('-------------------',machine.state,'-------------------')
machine.next_state()
elif finish:
print('-------------------',machine.state,'-------------------')
(In theory, the code should display the status if a person uses a bot, but later I want to remove this)
full code
A common use case for the application of state machines is to get rid of huge 'if-then-else'-constructs and process events 'context-sensitive', meaning that what happens when an event is received depends on the current state of the machine/model.
While this is probably not of interest for maria_hoffman any longer, google might lead someone here with the same intention:
Let's assume we want to build a simple bot that is capable of adding two numbers. We start with defining the necessary states.
states = ["INIT", "WAITING", "ADD_1", "ADD_2", "QUIT"]
We start from INIT and have a WAITING state where operation instruction are received. We could skip this one but our bot might be extended in the future to also support multiplication. In ADD_1 we expect the first number and in ADD_2 the second number for our sum. When in state QUIT we want the system to shutdown.
Next, we need to define the actual transitions that should happen:
transitions = [
dict(trigger='next', source='WAITING', dest='ADD_1', conditions=lambda x: x == "add"),
dict(trigger='next', source='WAITING', dest='QUIT', conditions=lambda x: x == "quit"),
dict(trigger='next', source='WAITING', dest='WAITING', before="show_error"),
dict(trigger='next', source='ADD_1', dest='ADD_2', before="store_value"),
dict(trigger='next', source='ADD_2', dest='WAITING', before="get_result"),
dict(trigger='reset', source='*', dest='WAITING'),
]
First, we see that we have just two events: next and reset. What happens when next is triggered, depends on the current state. In WAITING we process three possibilities: First, when the parameter passed with event next is equal to add, we transition to ADD_1 and wait for the first number to proces. If the parameter is equal to quit, we transition to QUIT and shutdown the system. If both condition checks fail we will use the third transition which will exit and re-enter WAITING and call a method called show_error before doing so. When transitioning from ADD_1 to ADD_2 we call a function to store the passed value. We need to remember it for get_result which is called when next is received in state ADD_2. Lastly, we have a reset event to roll back things if something did not work out.
Now we are almost done, we just need to define some prompts and the aforementioned methods show_error, store_value and get_result. We create a simple model for this. The idea is to show prompts depending on the state that has been entered. on_enter_<state> is the right tool for this job. We also intialize self.first in __init__ as a field to store the value of the first number that is passed in ADD_1:
class Model:
def __init__(self):
self.first = 0
def on_enter_WAITING(self, *args):
print("Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program:", end=' ')
def on_enter_ADD_1(self, *args):
print("Please enter the first value:", end=' ')
def on_enter_QUIT(self, *args):
print("Goodbye!")
def store_value(self, value):
self.first = int(value)
print("Please enter the second value:", end=' ')
def get_result(self, value):
val = int(value)
print(f"{self.first} + {val} = {self.first + val}")
def show_error(self, *args):
print("Sorry, I cannot do that.")
Note that when we want to pass arguments to callbacks, all callbacks need to be able to deal with it. The documentation of transitions states:
There is one important limitation to this approach: every callback function triggered by the state transition must be able to handle all of the arguments. This may cause problems if the callbacks each expect somewhat different data.
So, when we don't need the actual input value, we just put *args in the signature to communicate this.
That's it. Now we tie everything together and implement some rudimentary error checks and we are good to go. We create a model instance and pass it to the machine. When we receive input we pass it to the model via next and let the model do the heavy lifting. While the model is not in state QUIT we will wait for the next input:
model = Model()
machine = Machine(model, states=states, transitions=transitions, initial='INIT')
model.to_WAITING()
while not model.is_QUIT():
inp = input()
try:
model.next(inp)
except ValueError:
print("Oh no! Something went wrong. Let's try again!")
model.reset()
This could be a conversation with the bot:
Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program: add
Please enter the first value: 123
Please enter the second value: 4
123 + 4 = 127
Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program: call
Sorry, I cannot do that.
Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program: add
Please enter the first value: foo
Oh no! Something went wrong. Let's try again!
Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program: add
Please enter the first value: 123
Please enter the second value: baz
Oh no! Something went wrong. Let's try again!
Hello, if you want to add two numbers enter 'add'. Enter 'quit' to close the program: quit
Goodbye!

How do I get immediate response between motors and sensors?

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.

Best way to catch Low State of GPIO in an endless script

Can you please tell me what's the best way to catch a low state (or falling-edge more precisely) of GPIO in an endless script?
To be clear I will run this script at boot (in the bg) and everytime when a user will push a button (connected to this GPIO) this will put this pin at LOW state. I want to detect each one of them and perform actions at every push.
I already have this code but it will consume to much CPU I think... I need sth like an interrupt in my mind :
import RPi.GPIO as GPIO
#Set GPIO numbering scheme to pinnumber
GPIO.setmode(GPIO.BCM)
#setup pin 4 as an input
GPIO.setup(4,GPIO.IN)
# To read the state
While true:
state = GPIO.input(4)
if state:
print('on')
else:
print('off')
EDIT
Here the pinout by BCM or BOARD, I will work with BCM
As you can the the pin number is 4 because my push button is on GPIO4.
Still get off all the time with your code or constant detection of edge event with the code of #jp-jee
EDIT
#!/usr/bin/env python3
import time
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(4,GPIO.IN)
def Callback(channel):
print('pushed')
GPIO.add_event_detect(4, GPIO.FALLING, callback = Callback, bouncetime = 300)
while(True):
time.sleep(1)
Now my code print always pushed when the button is released and print nothing when I push it...
Take a look at the documentation of raspberry-gpio-python.
What you want is GPIO.add_event_detect(channel, GPIO.RISING) in combination with a callback function.
Since you're using a button, you also need to consider bouncing.
In the end, you will end up with something like this (taken from the linked website):
def my_callback(channel):
print('This is a edge event callback function!')
GPIO.add_event_detect(channel, GPIO.FALLING, callback=my_callback, bouncetime=200)
Have you tried to use interrupts?
import time
import RPi.GPIO as GPIO
GPIO.setup(4, GPIO.IN)
def Callback(channel):
state = GPIO.input(channel)
if state:
print('on')
else:
print('off')
GPIO.add_event_detect(4, GPIO.FALLING, callback = Callback, bouncetime = 300)
while(True):
time.sleep(1)

How to add conditional statement to a flame sensor?

I wanted to output 'flame detected' or 'no flame detected' but I don't know how to implement this in a code. I've seen codes from google but they are using
GPIO.add_event_detect(17,GPIO.RISING, callback = mycallback, bouncetime = 600)
which only works when it is detecting flame.
In your example you are detecting a rising edge (the pin goes from low to high). A falling edge is the opposite so you could fire a separate callback with:
GPIO.add_event_detect(17, GPIO.FALLING, callback=other_callback, bouncetime=600)
However, I'd suggest you use GPIO Zero instead of RPi.GPIO as you may find it more intuitive:
from gpiozero import InputDevice
sensor = InputDevice(17)
while True:
sensor.wait_for_active()
print("Fire!")
sensor.wait_for_inactive()
print("No fire")
You might find that the logic is reversed (says "fire" when there's no fire) in which case use InputDevice(17, pull_up=True)
Alternatively to the code above you could use if sensor.is_active or use the callbacks mechanism sensor.when_activated = callback. See the gpiozero docs for more info.

Color coding tasks in a Microsoft Project Macro

This seems like it should be straight forward, but I'm seeing some strange behavior. I'm attempting to color code my tasks based on a flag. It appears to be correctly coloring the tasks, but at some point in the processing the initial tasks that were colored are getting reset to black. The task that it happens on seems to be fairly inconsistent too. Here's how I'm trying to perform this task (simplified to it's barest form):
Sub ColorTasks()
Dim t As Task
For Each t In ActiveProject.Tasks
SelectRow t.ID, RowRelative:=False
Font32Ex Color:=2366701
Next
End Sub
This code seems to work just fine for smaller data sets, but this project contains around 2,000 tasks. Any ideas?
Yes I too am having a similar problem::
For Each t In tsks
Select Case t.Text1
Case "COMPLETE"
SelectRow Row:=t.ID, RowRelative:=False
Font32Ex CellColor:=&659B59
Case "NOT STARTED"
SelectRow Row:=t.ID, RowRelative:=False
Font32Ex CellColor:=&862525
Case "IN PROGRESS"
SelectRow Row:=t.ID, RowRelative:=False
Font32Ex CellColor:=&3A3AD4
End Select
Next t
According to: http://msdn.microsoft.com/en-us/library/ff863572.aspx this should work, yet I get syntax errors every time. Only way I can get this to work is if I use the FontEx method which limits me to only 16 colors....
I know that this is an old question but I hope it may be useful for someone with similar problem.
The mistake is that you've forgotten to add 'H' before hexadecimal number, so properly there should be:
Font32Ex CellColor:=&H3A3AD4
etc
I find it easier to use RGB values.
Font32Ex CellColor:=RGB(255, 199, 206) 'Changes fill
Font32Ex Color:=RGB(156, 0, 6) ' Changes font color
Using your code, I turned my entire sheet to red on pink, 350 tasks. I don't have a means to test it on 2000 though without a lot of extra work.