Moving object does not stop at the assigned pixel location

I think this is a case where the script is doing exactly what you tell it to, but you’re perhaps just not sure what that is. With example values you’ve provided (Poly_Velocity = -196.3515 and Img_StartPosX = 640), we can tabulate the x position of your stimulus, counting from the zeroth (i.e. first) frame onwards:

frame	 t	x	     round(x)  diff
0	0.0000	640.0000	640	
1	0.0167	636.7275	637	    -3
2	0.0333	633.4550	633	    -4
3	0.0500	630.1824	630	    -3
4	0.0667	626.9099	627	    -3
…
86	1.4333	358.5629	359	    -3
87	1.4500	355.2903	355	    -4
88	1.4667	352.0178	352	    -3
89	1.4833	348.7453	349	    -3
90	1.5000	345.4728	345	    -4
91	1.5167	342.2002	342	    -3

This is assuming a monitor with a refresh rate of 60 Hz, and hence 0.0167 seconds between successive stimulus updates.

Notice what happens when x gets into the range you are interested in (pixel values of 349, 351, 353).

  • The stimulus is actually jumping by 3.275 pixels between each screen refresh, so concerning yourself with pixel target values that are separated by only 2 pixels is not practical, as that is less than the smallest jump the stimulus makes on its successive appearances.
  • Pixels in the real world are discrete physical objects and can be counted (i.e. they should be addressed by integer values). Now I don’t know what PsychoPy does when you provide a non-integer value to a stimulus location. A reasonable guess is that it effectively gets rounded so that the stimulus appears at the closest discrete pixel to the continuous value you provided. e.g. the x value of 348.7453 above (on frame 89) would appear at pixel 349, but the stimulus will never appear at either pixel 351 or 353, because none of your generated values round to one of those integer values.

Now I really don’t know what your task is about and what the goal is, but perhaps you need to take a step back and think about the level of precision involved and exactly what you are trying to achieve. You are currently doing the right thing in your comparisons by using <= or >= instead of ==, because you can’t reliably compare floating point values for equality (that only works for integers, which computers can store exactly).

Effectively your task (at 60 Hz at least) is stepping the target by either 3 or 4 pixels per cycle (to produce an average step value of 3.2725 pixels per frame). Any calculations you do have to reflect that level of granularity in the animation. If you want more precision, run a faster monitor (e.g. gaming LCDs these days routinely run at 144 Hz) and/or one with much higher pixel resolution (say 4K). The combination of high refresh rate and high pixel density implies the need for a pretty good graphics card to handle the load. Otherwise if that level of precision is not actually required, just continue as you are but incorporate the actual level of granularity in your code’s logic.

You can certainly do that - but you just need to be aware of the level of precision in your animation and the actual pixel values involved. At the simplest level, you can just round() the output of your pixel calculation to have no decimal places, forcing it to be an integer:

round((t * Poly_Velocity) + Img_StartPosX))

and as above, perhaps tabulate the output of your function in a spreadsheet beforehand so you know which actual pixel locations it will land on, so that you don’t test against a pixel location that it actually skips over.