Plotter modules#
- class Plotter#
Plotter
#
A base class for the BrachioGraph
and PantoGraph
subclasses.
This class provides all the interfaces you’ll need for the plotter in normal use.
All the classes (Plotter
, BrachioGraph
and PantoGraph
) can be
instantiated without any arguments and will work for testing.
For testing with turtle graphics, you will need to use one of the subclasses.
Methods in general#
Hierarchy#
This table shows how the methods in the class Plotter
depend on each other.
Each named method calls the method in the cell below it.
Order of arguments#
Many of these methods accept a similar set of arguments. For consistency, they always appear in the same order. Note that not all are available to all methods. They are:
what to draw:
filename
orlines
where to draw:
bounds
precision and speed:
angular_step
,wait
,resolution
whether to draw:
draw
direction and repetition:
repeat
,reverse
,both
image transformations:
flip
,rotate
Initialisation#
- Plotter.__init__(virtual=False, turtle=False, turtle_coarseness=None, bounds=[-10, 5, 10, 15], servo_1_parked_pw=1500, servo_2_parked_pw=1500, servo_1_degree_ms=-10, servo_2_degree_ms=10, servo_1_parked_angle=0, servo_2_parked_angle=0, hysteresis_correction_1=0, hysteresis_correction_2=0, servo_1_angle_pws=(), servo_2_angle_pws=(), servo_1_angle_pws_bidi=(), servo_2_angle_pws_bidi=(), pw_up=None, pw_down=None, angular_step=None, wait=None, resolution=None)#
- Parameters
virtual (bool) – A virtual plotter will run in software only, and doesn’t expect any attached hardware. This allows work and development on a machine other than a Raspberry Pi, and to run automated tests.
turtle (bool) – Produces a graphical representation of the plotter and its behaviour using Python turtle graphics, as well as or instead of a physical plotter.
turtle_coarseness – For use with
turtle
; a factor, in degrees, to represent the resolution of the servos by rounding values. Defaults to 1˚ if not specified.bounds (tuple) – Four numbers, indicating the area that the plotter should treat as its available area for drawing in. The numbers represent, in order the left, top, right and bottom boundaries. Defaults to usable values in the default subclass definitions.
servo_1_parked_pw (int) – The pulse-width of servo 1 when parked.
servo_2_parked_pw (int) – The pulse-width of servo 2 when parked.
servo_1_degree_ms (float) – Milliseconds pulse-width difference per degree of movement.
servo_2_degree_ms (float) – Milliseconds pulse-width difference per degree of movement.
servo_1_parked_angle (float) – The arm angle in the parked position.
servo_2_parked_angle (float) – The arm angle in the parked position.
hysteresis_correction_1 (float) – Servo 1 hysteresis error compensation.
hysteresis_correction_2 (float) – Servo 2 hysteresis error compensation.
servo_1_angle_pws (tuple) – Pulse-widths for various angles of servo 1.
servo_2_angle_pws (tuple) – Pulse-widths for various angles of servo 2.
servo_1_angle_pws_bidi (tuple) – Pulse-widths for various angles of servo 1, collected in both clockwise and anti-clockwise directions. This is introduced in the tutorial.
servo_2_angle_pws_bidi (tuple) – Pulse-widths for various angles of servo 2, collected in both clockwise and anti-clockwise directions.
pw_up (int) – The pulse-width for the pen’s up position.
pw_down (int) – The pulse-width for the pen’s down position.
wait (float) – A time in seconds that the plotter will rest after making a movement. If not specified, will be initialised as 0.01, or 0 for a virtual-only plotter.
angular_step (float) – An angle in degrees that determines how big each discrete step in a series of movements of the arm servos will be. If not specified, will be initialised as 0.1.
resolution (float) – A distance in centimetres. When drawing between two points, any line longer than
resolution
will be broken down into a series of points no more thanresolution
cm apart. This allows the plotter to approximate straight lines by drawing a series of shorter curved lines (all the lines the plotter naturally draws are curved). If not specified, will be initialised as 0.1.
In all the methods below, arguments that are also attributes of the plotter class need only be used to override those values (which is generally not required).
Image-plotting methods#
These methods draw an image (as a series of lines, encoded in JSON).
- Plotter.plot_file(filename='', bounds=None, angular_step=None, wait=None, resolution=None)#
Plots and image encoded as JSON lines in
filename
. Passes the lines in the supplied JSON file toplot_lines()
.
- Plotter.plot_lines(lines=[], bounds=None, angular_step=None, wait=None, resolution=None, flip=False, rotate=False)#
Passes each segment of each line in lines to
draw_line()
Pattern-drawing methods#
- Plotter.box(bounds=None, angular_step=None, wait=None, resolution=None, repeat=1, reverse=False)#
Draw a box marked out by the
bounds
.
- Plotter.test_pattern(lines=4, bounds=None, angular_step=None, wait=None, resolution=None, repeat=1, reverse=False, both=False)#
- Plotter.vertical_lines(lines=4, bounds=None, angular_step=None, wait=None, resolution=None, repeat=1, reverse=False, both=False)#
- Plotter.horizontal_lines(lines=4, bounds=None, angular_step=None, wait=None, resolution=None, repeat=1, reverse=False, both=False)#
- Plotter.draw_line(start=(0, 0), end=(0, 0), angular_step=None, wait=None, resolution=None, both=False)#
Draws a line between two points
Drawing methods using x/y co-ordinates#
All of the methods above call xy
:
- Plotter.xy(x=None, y=None, angular_step=None, wait=None, resolution=None, draw=False)#
Moves the pen to the xy position; optionally draws while doing it.
None
for x or y means that the pen will not be moved in that dimension.
Drawing methods using servo angle values#
- Plotter.move_angles(angle_1=None, angle_2=None, angular_step=None, wait=None, draw=False)#
Moves the servo motors to the specified angles step-by-step, calling
set_angles()
for each step.None
for one of the angles means that that servo will not move.
Pen-moving methods#
- Plotter.set_angles(angle_1=None, angle_2=None)#
Moves the servo motors to the specified angles immediately. Relies upon getting accurate pulse-width values.
None
for one of the angles means that that servo will not move.Calls
set_pulse_widths()
.Sets
current_x
,current_y
.
- Plotter.park()#
Angles to pulse widths#
A plotter needs to move its arms to the correct angles, by providing the appropriate pulse-width to each servo.
- Plotter.angles_to_pw_1()#
- Plotter.angles_to_pw_2()#
These methods - one for each servo - take the angle as an argument and return a pulse-width.
The methods themselves stand in for functions that do the actual calculation; which function is
assigned to the angles_to_pw_1
/angles_to_pw_2
attributes depends upon how much
information is provided about the servos when the plotter is initialised.
Naive calculation#
The default is to use “naive” functions (naive_angles_to_pulse_widths_1
and
naive_angles_to_pulse_widths_2
), that assume linearity (1˚ of movement corresponds to a 10µs
change in pulse-width), will be used.
- Plotter.naive_angles_to_pulse_widths_1(angle)#
A rule-of-thumb calculation of pulse-width for the desired servo angle
- Plotter.naive_angles_to_pulse_widths_2(angle)#
A rule-of-thumb calculation of pulse-width for the desired servo angle
Sophisticated calculation#
In practice the response of servos is not linear. If a series of
pulse-width/angle values are supplied, then numpy (numpy.poly1d(numpy.polyfit))
will provide a
polynomial funtion that matches the curve corresponding to those values.
Line processing#
- Plotter.analyse_lines(lines=[], rotate=False, bounds=None)#
Analyses the co-ordinates in
lines
, and returns:rotate
:True
if the image needs to be rotated by 90˚ in order to fit betterx_mid_point
,y_mid_point
: mid-points of the imagebox_x_mid_point
,box_y_mid_point
: mid-points of thebounds
divider
: the value by which we must divide all x and y so that they will fit safely inside the bounds.
lines
is a tuple itself containing a number of tuples, each of which contains a number of 2-tuples:[ [ [3, 4], # | [2, 4], # | [1, 5], # a single point in a line # | a list of points defining a line [3, 5], # | [3, 7], # | ], [ # all the lines [...], [...], ], [ [...], [...], ], ]
- Plotter.rotate_and_scale_lines(lines=[], rotate=False, flip=False, bounds=None)#
Rotates and scales the lines so that they best fit the available drawing
bounds
.
Physical control#
- Plotter.set_pulse_widths(pw_1=None, pw_2=None)#
Applies the supplied pulse-width values to the servos, or pretends to, if we’re in virtual mode.
- Plotter.get_pulse_widths()#
Returns the actual pulse-widths values; if in virtual mode, returns the nominal values - i.e. the values that they might be.
- Plotter.quiet(servos=[14, 15, 18])#
Stop sending pulses to the servos, so that they are no longer energised (and so that they stop buzzing).
Calibration and manual driving#
- Plotter.capture_pws()#
Helps capture angle/pulse-width data for the servos, as a dictionary to be used in a Plotter definition.
The controls are:
-10 µs
-1 µs
+ 10 µs
+ 1 µs
Shoulder
a
A
s
S
Elbow
k
K
l
L
Pen
z
x
Capture pulse-width value
c
Show captured values
v
Exit
0
Reporting methods#
- Plotter.status()#
Provides a report of the plotter status. Subclasses should override this to report on their own status.
Trigonometric methods#
- Plotter.xy_to_angles(x=0, y=0)#
Return the servo angles required to reach any x/y position. This is a dummy method in the base class; it needs to be overridden in a sub-class implementation.
- Plotter.angles_to_xy(angle_1, angle_2)#
Return the servo angles required to reach any x/y position. This is a dummy method in the base class; it needs to be overridden in a sub-class implementation.
BrachioGraph
#
- class BrachioGraph#
- __init__(virtual=False, turtle=False, turtle_coarseness=None, bounds=[-8, 4, 6, 13], inner_arm=8, outer_arm=8, servo_1_parked_pw=1500, servo_2_parked_pw=1500, servo_1_degree_ms=-10, servo_2_degree_ms=10, servo_1_parked_angle=-90, servo_2_parked_angle=90, hysteresis_correction_1=0, hysteresis_correction_2=0, servo_1_angle_pws=[], servo_2_angle_pws=[], servo_1_angle_pws_bidi=[], servo_2_angle_pws_bidi=[], pw_up=1500, pw_down=1100, wait=None, angular_step=None, resolution=None)#
Parameters are as for the
Plotter
parent class, except for:- Parameters
inner_arm (float) – The length of the inner arm, in cm.
outer_arm (float) – The length of the outer arm, in cm.
virtual (bool) –
turtle (bool) –
bounds (tuple) –
servo_1_parked_pw (int) –
servo_2_parked_pw (int) –
servo_1_degree_ms (int) –
servo_2_degree_ms (int) –
servo_1_parked_angle (int) –
servo_2_parked_angle (int) –
hysteresis_correction_1 (int) –
hysteresis_correction_2 (int) –
servo_1_angle_pws (tuple) –
servo_2_angle_pws (tuple) –
servo_1_angle_pws_bidi (tuple) –
servo_2_angle_pws_bidi (tuple) –
pw_up (int) –
pw_down (int) –
wait (float) –
angular_step (float) –
resolution (float) –