I'm using a simple NumericProperties and looking for a way to (quasi-)simultaneously change two property values without an intermediate event dispatch.
Here is a minimal example (all are NumericProperty).
motor: offset + delta
Imagine this is some kind of devices (say a motor attached to a larger CNC machinery). The motor physically moves whenever the value changes, say on an "on_motor" event. The user usually moves the motor by updating the "delta" value, while the "offset" value is some calibration.
Once in a while the motor needs recalibration. It needs to update the "offset" value without physically changing the motor (and giving a new "delta" value). An assignment like
(offset, delta) = (offset + delta, 0)
would provide all correct values, except inbetween this assignment on_motor is called with the intermediate values that would correspond to
offset = offset + delta # motor changes by the relative amount +delta
delta = 0 # motor changes by the relative amount -delta
Is there a more general way to have two assignments of properties atomically (without intermediate change events?)
Should i try to unbind the motor NumericProperty from the offset EventDispatcher, at least during calibration ?
If all three of those values are Properties, then an event will be generated for every change to offset or delta, and a resulting event will be generated by the motor property each time. So, even if you simultaneously change offset and delta, two separate events will be generated.
If you have a method on_motor() that responds to changes to the motor Property, you could create a BooleanProperty, maybe named isCalibrating. Then in your on_motor() you could have (at the start of that method):
if self.isCalibrating:
return
Then you could just set isCalibrating to True during calibration.
Related
my character sprite moves faster if my game is in window mode. to set the velocity i used ROOTwidth, in theory the velocity should be scaled...
this is my code (simplified)
#MAIN CODE
#ROOT dimension don't change (window can't be resized while playing,
#only in main menu function where ROOTwidth, ROOTheight are obtained)
ROOTwidth, ROOTheight = pygame.display.get_surface().get_size()
velocity = ROOTheight/450
playertopx = ROOTwidth/2.2
playertopy = ROOTwidth/2
playermovement = PlayerMovement(playertopx, playertopy)
while True:
key = pygame.key.get_pressed()
if key[pygame.K_w]:
playermovement.human_moveup(velocity)
#PLAYER MOVEMENT CLASS
import pygame
class PlayerMovement:
#init
def __init__(self, playertopx, playertopy):
self.x = playertopx
self.y = playertopy
#movement
def human_moveup(self, velocity):
self.y -= velocity
#MAIN CODE
ROOT.blit(playermovement.spritesheet_human, (playermovement.x, playermovement.y), (0, 50, 25, 18))
I don't know what to do... for every element in my game, using ROOT dimensions works fine, only in velocity I have problems
I guess it might be a case of your main event loop's looping speed being dependent on the time it takes to draw on the window and that main event's code not accounting for that.
Execution speed
Assuming you have this code as your main event loop:
while NotExited:
doGameLogic() # Your velocity computations and other stuff
drawOnWindow() # Filling entire window with background, drawing sprites over, refreshing it, etc
Now, imagine doGameLogic() always takes 1ms (0.001 seconds) of time, and drawOnWindow() always takes 50ms. While this loop is running, therefore, the loop will take up 51 milliseconds total, and hence doGameLogic() will be called once every 51ms.
Then you perform your velocity computation in there. Let's, for simplicity, say you do playermovement.x += 5 in there every time.
As a result, your player's X coordinate is increased by 5 units every 51 milliseconds. That amounts to an increase of about 98 units in one second.
Variance in execution speed
Now imagine that drawOnWindow() starts taking 20ms of time instead. Then the loop takes 21ms of time total to run, which causes doGameLogic() to run every 21ms aswell. In that case the X coordinate increases by 5 units every 21 milliseconds instead, amounting to increasing by 238 units every second.
That is way faster than the previous 98 units every second. Because drawing takes less time now, your character ends up moving way faster.
This is what I assume is happening in your case. As you make the window smaller, drawing calls (like drawing a background/filling it with a color) take less time as there's less pixels to draw on, and therefore change how long drawOnWindow() takes time, and therefore the frequency at which doGameLogic() is run changes.
Fixing
There are many different ways to fix this. Here are some:
Enforcing loop speed
One of them is to ensure that your loop always takes the exact same amount of time to run regardless of how much time the calls take:
import time
while NotExited:
startTime = time.time() # Record when the loop was started
doGameLogic()
drawOnWindow()
# Calculate how long did it take the loop to run.
HowLong = time.time() - startTime
# Sleep until this loop takes exactly 0.05 seconds.
# The "max" call is to ensure we don't try to sleep
# for a negative value if the loop took longer than that.
time.sleep(max(0, 0.05-HowLong))
Or alternatively, the library you are using for rendering may allow you to set an upper limit to FPS (frames per second), which can also work to make sure the time it takes to draw is constant.
This method has a disadvantage in that it becomes ineffective if the loop takes longer than the designated time, and restricts how fast your game runs in the opposite case, but it is very easy to implement.
Scaling with speed
Instead of making sure playermovement.x += 5 and the rest of the logic is ran exactly once every 50 milliseconds, you can make sure that it is run with values scaled proportionally to how often it is run, producing the same results.
In other words, running playermovement.x += 5 once every 50ms is fully equivalent to running playermovement.x += 1 once every 10ms: as a result of either, every 50ms the value is increased by 5 units.
We can calculate how long it took to render the last frame, and then adjust the values in the calculations proportionally to that:
import time
# This will store when was the last frame started.
# Initialize with a reasonable value for now.
previousTime = time.time()
while NotExited:
# Get how long it took to run the loop the last time.
difference = time.time() - previousTime
# Get a scale value to adjust for the delay.
# The faster the game runs, the smaller this value is.
# If difference is 50ms, this returns 1.
# If difference is 100ms, this returns 2.
timeScale = difference / 0.05
doGameLogic(timeScale)
drawOnWindow()
previousTime = time.time()
# ... in the game logic:
def doGameLogic(timeScale):
# ...
# Perform game logic proportionally to the loop speed.
playermovement.x += 5 * timeScale
This method is more adaptable depending on the speed, but requires to be taken in account whereever time dependent actions like this one are done.
It can also be a source of unique problems: for example, if your game runs very very slowly even for one frame, the time scale value might get disproportionally large, causing playermovement.x to be incremented by 5*100000, teleporting your player character very far away. It can also produce jerky results if the loop speed is unstable, and provide more problems since it is performed with floating point math.
Decoupling logic and rendering
Another more reliable than the other ones but harder to implement way is to decouple doGameLogic() from drawOnWindow(), allowing one to be run independently from the other. This is most often implemented with use of multithreading.
You could make two loops running concurrently: one that runs doGameLogic() on a fixed interval, like 10ms, with the aforementioned "Enforcing loop speed" method, and another one that runs drawOnWindow() as fast as it can to render on the window at any arbitrary speed.
This method also involves questions of interpolation (if drawOnWindow() runs twice as fast as doGameLogic(), you probably don't want every second time to draw an identical image, but an intermediate one that appears smoother), and threading management (make sure you don't draw on the window while doGameLogic() is still running, as you might draw an incomplete game state in the middle of processing).
Unfortunately I am not knowledgeable enough to provide an example of code for that, nor I am even sure if that is doable in Python or PyGame.
I'm pretty new to coding and I need to create a code that generates an object along the normal of a selected geo surface.
Anything to start me on the right path would be appreciated.
I initially tried to use duplicate, but I was told that command instancer is the better option.
def ChainmailSurfaceGenerator():
thing = MC.ls(sl=True)
print thing
if not thing:
MC.error("select a torus")
#create a group for your chainmail*
grp = MC.group(empty=True, name=thing[0] + '_grp#'
#create hierarchy of grouped toruses
MC.polyTorus( radius=1, n = 'chainmail_link')
MC.duplicate('chainmail_link')
#query the direction of UV normals off the face
#lessen the amount of geometry if its too dense
#try it out on a plane surface first
#keep things simple early
#what if chains don't connect perfectly? add a randomizer so that the chains aren't all completely symmetrical
#don't use MC.duplicate; use Instancer
You might not actually need to query the UV direction of the target geometry.
Try looking into the commands for constraints like cmds.normalConstraint or cmds.geometryConstraint. As for the number of objects to make, consider using a for loop in a range of how many objects you want. If you want to apply a random rotation, I would recommend using a group or a locator as an offset for transforming the group around (either with setAttr or xform) so that you can move the group while maintaining the ability to rotate the duplicate in it's y axis. If you go the route of normal constraints, be sure to use the aim flag to point the object up in its y axis! Googling the commands should come up with documentation on what flags to use.
The first combobox holds a number in a currency A and the second one holds the same amount but in currency B. What I want : When I enter a number in the 1st one, the 2nd one must be set automatically to the number converted in the other currency and vice-versa.
I use Ubuntu 16.04, Python 3.5.1, Qt 4.8.7. The 2 QComboBox are created with Qt Designer
Code :
#pyqtSignature("double")
def on_dspPuAchEur_valueChanged(self, double):
""" updaye prAchatDT according to prAchatEur"""
self.dspPuAchDT.setValue(2.2*self.dspPuAchEur.value())
#pyqtSignature("double")
def on_dspPuAchDT_valueChanged(self, double):
""" update prAchatEur according to prAchatDT"""
self.dspPuAchEur.setValue(self.dspPuAchDT.value()/2.2)
2.2 is the conversion factor which will be a variable in the future.
min is 0 for the 2 combobox, max is 50000 (far above the real max), step is 1.0.
It works fine from dspPuAchEur to dspPuAchDT but it does not work in the opposite sense : the step is 0.99 in place of 1. When I try to edit manually the field, the displayed digit is not the one I've just entered. It's always minus 1 (If I press the '5' key, I get a '4').
Does somebody have any idea about this behavior ? Thanks.
I think this could be due to both spin boxes playing "ping pong". A change of value of dspPuAchDT causes it's valueChanged() singal to be emitted, which in turn updates dspPuAchEur, which in turn emits it's valueChanged() signal with in turn leads to an update of dspPuAchDT. Due to rounding, the value you enter seems to change immediately.
As a workaround, you could block emitting signals while updating the peer widget:
#pyqtSignature("double")
def on_dspPuAchEur_valueChanged(self, double):
""" updaye prAchatDT according to prAchatEur"""
self.dspPuAchDT.blockSignals(True);
self.dspPuAchDT.setValue(2.2*self.dspPuAchEur.value())
self.dspPuAchDT.blockSignals(False);
#pyqtSignature("double")
def on_dspPuAchDT_valueChanged(self, double):
""" update prAchatEur according to prAchatDT"""
self.dspPuAchEur.blockSignals(True);
self.dspPuAchEur.setValue(self.dspPuAchDT.value()/2.2)
self.dspPuAchEur.blockSignals(False);
I am having the problem, that I am not able to control any of my servos I have. I have two servos, one is a normal servo used in model planes and the second one is a micro sized servo.
I wired both of them separately (The signal cable to a GPIO pin and the other two cables first directly to the board and after to a external power source).
When I try to run them via the similar python code
...
GPIO.setmode(GPIO.BCM)
GPIO.setup(11, GPIO.OUT)
pwm = GPIO.PWM(11, 50)
pwm.start(2)
timelib.sleep(2)
pwm.ChangeDutyCycle(3)
timelib.sleep(2)
...
the servos sometimes just turn for a bit but then stop on one side. After that you can still hear the servo making noises like it is trying to run further. After it turned to the end I can not make it work or make it turn in any way. It will just stay there whatever input I will make. It will just turn to the same end again if I am manually turn them back to the start position. I can not figure it out what I am doing wrong or where I need to change my way of doing it.
Does anyone have any tips or had a similar problem?
I'm thankful for every further tip and further step I will make.
Thanks in advance!
The servos position is controlled by the pulsewidth of a 50 Hz PWM signal. Hence, we need to turn the PWM sequence on at 50 Hz. Note that for a 50 Hz signal, the Period of the signal is 1/50=.02 seconds, or 20 milliseconds. Keep this Period in mind as we will come back to it later. We start by creating a PWM object on Pin 11 with a 50 Hz signal with the command:
pwm=GPIO.PWM(11,50)
We can now start the pwm sequence by giving a command to specify the DutyCycle of the signal. Before we do this, we need to talk a little bit about how servos work. A typical servo wants to see a frequency of 50 Hz on the control line. The position it moves to depends on the pulse width of the signal. Most servos behave roughly as such, but you will need to tweak these numbers for your particular servo. Typically, the servo will go to the full left position when it sees a pulse width of 1 millisecond, it will go the middle position when it sees a pulse width of 1.5 millisecond, and it will go to the full right position when it sees a pulse width of 2 millisecond. Note however, that on the Raspberry Pi we do not specify a pulse width, but we specify a DutyCycle. So, we can use the following relationship:
DutyCycle =PulseWidth/Period
Remember that Period = 1/frequency, so:
DutyCycle = PulseWidth/(1/frequency) = PulseWidth * frequency
The PulseWidth that will give us a full left position is 1 milllisecond. We now calculate the applied DutyCycle to give us the desired position:
DutyCycle = PulseWidth*frequency=.001 *50 = .05 = 5%
So, for a 50 Hz signal, if we set the DutyCycle to 5, then we should see the servo move to the full left position. Similarly, if we set DutyCycle to 7.5, we should get the middle position, and if we set it to 10 we should be in the full right position. You can get all the intermediate positions by linearly scaling between 5 and 10. Note that these values will vary between brands, and between individual servos, so play around with your servo to get it calibrated. We are now ready to apply a command to position the servo. If we want the servo in the full left position, we should set the DutyCycle to 5%. We do that with the command:
pwm.start(5)
This will start the PWM signal, and will set it at 5%. Remember, we already specified the 50 Hz signal when we created the pwm object in our earlier commands. Now if we want to change the position, we can change the DutyCycle. For example, if we want to go to the middle position, we want a DutyCycle of 7.5, which we can get with the command:
pwm.ChangeDutyCycle(7.5)
Now if we want the full right position, we want a duty cycle of 10, which we would get with the command:
pwm.ChangeDutyCycle(10)
Remember, it is not DutyCycle that actually controls servo position, it is PulseWidth. We are creating DutyCycles to give us the desired PulseWidth.
Now, play around with your particular servo and then find the specific DutyCycles that lead to full left and full right positions. For my servo, I find that full left is at DutyCycle=2, and full right is at DutyCycle=12. With these values, I can create a linear equation that will give me any angle I want between 0 and 180. This will make the Raspberry Pi behave much more like the simple and intuitive operation of the Arduino.
To do the linear equation I need two points. Well, I know that for a desired angle of 0, I should apply a DutyCycle of 2. This would be the point (0,2). Now I also know that for a desired angle of 180, I should apply a DutyCycle of 12. This would be the point (180,12). We now have two points and can calculate the equation of the line. (Remember, play with your servo . . . your numbers might be slightly different than mine, but the methodology below will work if you use your two points)
Remember slope of a line will be:
m=(y2-y1)/(x2-x1)=(12-2)/180-0)=10/180 = 1/18
We can now get the equation of the line using the point slope formula.
y-y1=m(x-x1)
y-2=1/18*(x-0)
y = 1/18*x + 2
Putting in our actual variables, we get
DutyCycle = 1/18* (DesiredAngle) + 2
Now to change to that position, we simply use the command:
pwm.ChangeDutyCycle(DutyCycle)
See more at: http://www.toptechboy.com/raspberry-pi/raspberry-pi-lesson-28-controlling-a-servo-on-raspberry-pi-with-python/#sthash.LRmf7708.dpuf
Alternately, you can use my library which hides most of the pwm and GPIO board complexity. Sample code:
from RaspberryMotors.motors import servos
s1 = servos.servo(11) #create the servo objects , connected to GPIO board pin #11
s1.setAngleAndWait(45) # move S1 position of 45 degrees
s1.shutdown() #will clean up the GPIO board as well`
You can view download the code or the library via any of the two links:
https://github.com/vikramdayal/RaspberryMotors or
https://pypi.org/project/RaspberryMotors/#description
I am writing an application in Python using Qt (currently PyQt) that receives telemetry (position data) over UDP and displays that data. It can handle several packet types each with several data fields each. I have a separate thread that handles receiving and decoding packets and they emits a signal to send that data to the Qt GUI for display. The data get displayed in several ways: a current value display, scrolling log display, and a 3D view display. All this runs great and in real time with each packet updating at up to about 30Hz.
I want to add another tab that shows a live plot. The user can select which data streams to plot and it will update in real time, showing a sliding window of the last 60sec of data (maybe configurable at some point). However my first approach is particularly slow. It is barely keeping up plotting only one line with our emulator that runs much slower than 30Hz.
I am using pyqtgraph to do the plotting. I have a PlotWidget instantiated in my .ui file and create a PlotDataItem for each data line that could be drawn on the plot. I am using deques to store the data to be plotted, both the value and the time. This way I can quickly add data as it comes in and remove it as it falls outside of the sliding window. I am storing all this in a dict for each packet type and field:
self.plotData[pktType][field] = {}
self.plotData[pktType][field]['curve'] = self.pwPlot.plot()
self.plotData[pktType][field]['starttime'] = time
self.plotData[pktType][field]['data'] = coll.deque()
self.plotData[pktType][field]['realtime'] = coll.deque()
self.plotData[pktType][field]['time'] = coll.deque()
'starttime' stores an initial datetime value for computing elapsed seconds. 'realtime' stores datetime values of when each packet was received (I am not currently using this, so I could drop it if it would save time). 'time' stores elapsed seconds from the 'starttime' for easier plotting and 'data' stores the values.
When a packet that comes in, I store data in the deques for each field I might want to parse. I then trim off any data outside the sliding window. Finally, the deque gets packaged in a numpy array and passed to the PlotDataItem setData method. Here's a simplified version of the code that runs for each received packet:
def updatePlot(self, time, pktData):
pktType = pktData['ptype']
keys = self.getPlottableFromType(pktType) # list of fields that can be plotted
if keys == None:
return
for k in keys:
self.plotData[pktType][k]['data'].append(pktData[k])
self.plotData[pktType][k]['realtime'].append(time)
runtime = (time - self.plotData[pktType][k]['starttime']).total_seconds()
if self.plotRate == 0:
self.plotData[pktType][k]['time'].append(runtime)
else:
if self.plotData[pktType][k]['time']: # has items
nexttime = self.plotData[pktType][k]['time'][-1] + 1. / self.plotRate
else:
nexttime = 0
self.plotData[pktType][k]['time'].append(nexttime)
while (self.plotData[pktType][k]['time'][-1] - self.plotData[pktType][k]['time'][0]) > self.plotRangeSec:
self.plotData[pktType][k]['data'].popleft()
self.plotData[pktType][k]['realtime'].popleft()
self.plotData[pktType][k]['time'].popleft()
self.drawPlot(pktType, k)
def drawPlot(self, pktType, k):
if self.plotIsEnabled(pktType, k) and self.plotData[pktType][k]['time']: # has items
npt = np.array(self.plotData[pktType][k]['time'])
npd = np.array(self.plotData[pktType][k]['data'])
self.plotData[pktType][k]['curve'].setData(npt, npd)
else:
self.plotData[pktType][k]['curve'].clear()
self.plotRate can be used to plot the data either using wall time or force the time axis to a fixed update rate. This is useful for using with the emulator since it runs slower than the real system.
First thing I should probably do is not call .clear() every time for plots that are not being plotted (just complicates the logic a little bit). Other than that, anyone have any tips for improving performance? Is the deque to numpy array a good strategy? Is there a better way to update the data since I am only changing a few values per line (adding a point and possibly removing a point or two)?