Self Join Exercise. Have I over-complicated it?
You have a bug. Change the row ('u3', 100, 500, 125) to ('u3', 99, 500, 125), and try again. You will see that u3 row disappears.

You can fix it with the following minimal change:

rm.reading_time = (SELECT MAX(r2.reading_time) 
  FROM Readings r2 
  WHERE  r2.user_id=r.user_id -- you have to join on ids first
  and r2.reading_time &lt; r.reading_time)

There is another bug here:
r.x-rm.y should have been r.y-rm.y.
user_id, reading_time is a unique key by problem definition. Having it declared will enable us to detect some invalid inputs. What is the average speed of an object that can be at more than one place?
I would go along with something like this for the intermediate script:

SELECT t.*, t2.*
FROM (SELECT r.user_id,r.reading_time, 
         max(r.x) AS x1, max(r.y) AS y1, 
         max(rm.reading_time) AS prev
FROM Readings r
JOIN Readings rm ON (r.user_id = rm.user_id AND rm.reading_time &lt; r.reading_time)
GROUP BY r.user_id,r.reading_time) t
INNER JOIN Readings t2
ON t.user_id = t2.user_id AND t2.reading_time = t.prev;