The BrachioGraph class

class BrachioGraph:

  def __init__(
      servo_1_degree_ms = 10,
      servo_2_degree_ms = -10,
  • inner_arm, outer_arm need to be measured from the actual plotter. They don’t need to be equal, but some combinations are uselessly restrictive. Use the script to see how different geometries affect the plottable area.
  • virtual_mode allows you to run a BrachioGraph without hardware attached
  • bounds needs to be determined empirically. Or possibly, computed.
  • servo_1_centre and servo_2_centre: the pulse-width at which each servo arm is exactly on the plotting grid’s x or y axis. Ignored if the servo_<x>_angle_pws arguments are provided.
  • servo_1_degree_ms and servo_2_degree_ms: how many ms per degree of movement. Reverse the sign to reverse the direction.
  • arm_1_centre and arm_2_centre: the angles of the arms when the servo is at servo_1_centre/servo_1_centre respectively
  • servo_1_angle_pws and servo_2_angle_pws: lists of pulse-width/angle pairs. If provided, then numpy.polyfit will be used to produce a function for calculating required pulse-widths. If not, a more naive formula will be used.
  • pw_up and pw_down: pulse width values at which the pen is up/down. It makes more sense to attach the lifting servo horn at a different angle than to change these.

Management methods


Sends the arms to the parking position, with the inner arm at -90˚ and the outer arm at 90˚ to it. This corresponds to an x/y position:

  • x: -inner_arm
  • y: outer_arm

Image drawing methods


  • image: path to image file

Drawing utility methods


Draw a box marked out by the bounds.


Draws a grid within the box area marked out by the bounds.

Reporting methods


The BrachioGraph instance has four attributes, angles_used_1, angles_used_2, pulse_widths_used_1, pulse_widths_used_2. They are all Python sets. Each time the set_angles method is called, it records the angle and pulse-width recorded for each of the two arm servos.

This creates a running record of all the positions the arms have been in.

After the arm has finished drawing, you can find the minimums, maximums and mid-points:

               min   max   mid    min   max   mid
      angles  -124     7   -59     43   154    99
pulse-widths   771  2048  1410   1047  2063  1555

In this case, it’s good to know that the mid-points in the range both servos have covered while plotting all over the paper are not too far from 1500ms - which means that their range is reasonably well centred.

The Pen class

A BrachioGraph instance has an instance of a Pen class, as BrachioGraph.pen.

class BrachioGraph:

    def __init__(
        bg,                         # the BrachioGraph instance to which the Pen is attached
        pw_up=1500, pw_down=1100,   # pen up and pen down pulse-widths
        pin=18,                     # the GPIO pin
        transition_time=0.25        # how long to wait for up/down movements