`ValueError: math domain error` triggered in drive_xy
willprice opened this issue · 9 comments
Using the following testing script
from brachiograph import BrachioGraph
from time import sleep
# The servo_x_degree_ms signs need flipping as my motors
# go in the opposite direction to those in the article
plotter = BrachioGraph(
inner_arm=8.2,
outer_arm=8.85,
servo_1_degree_ms=10,
servo_2_degree_ms=-10,
)
print("Resetting arm position")
plotter.set_angles(angle_1=-90, angle_2=90)
print("Set up complete")
plotter.drive_xy()
and moving around with a,d,l,k I can consistently trigger a math domain error. I think this happens when the hypotenuse
becomes very small or perhaps negative?
Here's the stack trace
Traceback (most recent call last):
File "test.py", line 23, in <module>
plotter.drive_xy()
File "/home/pi/branchiograph/brachiograph.py", line 698, in drive_xy
self.xy(self.current_x, self.current_y)
File "/home/pi/branchiograph/brachiograph.py", line 434, in xy
(angle_1, angle_2) = self.xy_to_angles(x, y)
File "/home/pi/branchiograph/brachiograph.py", line 590, in xy_to_angles
(hypotenuse**2+self.INNER_ARM**2-self.OUTER_ARM**2)/(2*hypotenuse*self.INNER_ARM)
ValueError: math domain error
and here are the values printed during driving the plotter
Resetting arm position
Set up complete
-9.2 8.85
-10.2 8.85
-11.2 8.85
-12.2 8.85
-13.2 8.85
-14.2 8.85
-13.2 8.85
-12.2 8.85
-11.2 8.85
-12.2 8.85
-13.2 8.85
-14.2 8.85
-13.2 8.85
-12.2 8.85
-11.2 8.85
-11.2 9.85
-11.2 10.85
-11.2 11.85
-11.2 12.85
-11.2 13.85
I have the same problem. Did you solved it?
@moe5k, well I think the idea is that you use bg.drive_xy()
to figure out the min/max x/y values before this is triggered, although I'm not certain about that. I've not had much success yet, as when I try the bg.box()
test, the plotter draws nothing like a box! It's more like two squashed circles.
@willprice i thought using bg.drive_xy()
for define the physical limits of the hardware. At least bg.box()
should drive along these points. I got also a similar behavior while starting bg.box()
.
@moe5k Yes, I think you're probably right. It doesn't seem particularly user friendly for the app to crash, instead, an error should be raised. I've not quite pinned down the cause of the issue. At first, I thought it was when the hypotenuse went to 0 causing a div by 0 error, but I tried to catch this issue but still observed the domain error. I think I need to log the values going to the trigonometric functions as this is where I suspect the exception is being raised.
OK, figured out why this happens. When (hypotenuse**2+self.INNER_ARM**2-self.OUTER_ARM**2)/(2*hypotenuse*self.INNER_ARM)
(derived from the cosine rule) is less than -1 or greater than 1 then arccos
will throw a math domain error since cos
can only produce values in the range [-1, 1]
. I need to think about this a bit more, but my intuition is that it's not possible to produce a triangle with its tip at (x, y)
given the inner and outer arm lengths.
This looks reasonable to me.
>>> import math
>>> math.sqrt(11.2 **2 + 13.85 **2) < (8.2 + 8.85)
False
The distance to the point is further than arms can reach.
A better message would be useful though.
I've added a bit of code to catch this issue and inform the user.
willprice@c8d764d
In that branch I've turned all the return str messages into exceptions too.