After FormLabs stoped supporting the Form 1/1+ printers, they released a set of tools collectively called OpenFL letting people play with the hardware. We can either stay within the realm of laser resin 3D printing or come up with something entirely different. After I successfully installed the toolset and established Python communication with the printer, I wanted to explore the laser module.

At the top of Printer.py I see two references to laser power: an audit toggle and a power ceiling of 64mW.

    AUDIT_LASER_POWER = True
    LASER_POWER_MAX_MW = 64

Looking for where the ceiling is used, I found this method:

    def check_laser_ticks(self, power):
        """ Raises if the power (in laser ticks) is above our safe threshold
        """
        mW = self.ticks_to_mW(power)
        if mW > self.LASER_POWER_MAX_MW:
            raise LaserPowerError('Requested power is dangerously high.')

From this method I learned laser power is measured in two different ways: "ticks", which is a hardware-specific measure, and the more general units of "mW" (milliwatts). There are two methods to convert between them. The ticks_to_mW seen here, and its inverse mW_to_ticks. Reading those methods, I see that ticks is an uint16 (unsigned 16-bit integer) value so valid range is 0 to 65535. So what's the maximum possible power via this API?

>>> p.ticks_to_mW(65535)
80.71

So 64mW is the recommended maximum, any higher may raise LaserPowerError but if we have the option to ignore that and turn the dial up to 80.71mW.

I also see that the conversion depends on a laser power lookup table presumably established with factory calibration and saved in nonvolatile memory. Using OpenFL we can see that table.

>>> p.read_laser_table()
[[0, 0, 0], [0.1, 0.02, 9.0], [0.2, 0.03, 12.0], [0.3, 0.03, 14.0], [0.4, 0.04, 16.0], [0.5, 0.05, 18.0], [0.6, 0.06, 19.0], [0.7, 0.07, 22.0], [0.8, 0.1, 24.0], [0.9, 0.23, 25.0], [1.0, 3.77, 26.0], [1.1, 8.22, 28.0], [1.2, 12.76, 29.0], [1.3, 17.34, 30.0], [1.4, 22.06, 32.0], [1.5, 26.73, 33.0], [1.6, 31.53, 34.0], [1.7, 36.33, 35.0], [1.8, 41.11, 36.0], [1.9, 46.0, 37.0], [2.0, 50.92, 38.0], [2.1, 55.92, 39.0], [2.2, 60.72, 40.0], [2.3, 65.81, 41.0], [2.4, 70.8, 41.0], [2.5, 75.79, 42.0], [2.6, 80.71, 43.0]]

Actually powering up the laser requires calling one of several methods, which accept input in some combination of machine coordinates or real dimensions. I chose to experiment using set_laser_mm_mW() which simultaneously updates galvanometer position and laser power. For my first test I set the laser to 1 milliwatt.

>>> p.set_laser_mm_mW(0, 0, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\users\me\openfl\OpenFL\Printer.py", line 502, in set_laser_mm_mW
    return self.set_laser_uint16(x, y, self.mW_to_ticks(mW))
  File "c:\users\me\openfl\OpenFL\Printer.py", line 485, in set_laser_uint16
    expect_success=True)
  File "c:\users\me\openfl\OpenFL\Printer.py", line 180, in _command
    r = self._wait_for_packet(wait, verbose=verbose)
  File "c:\users\me\openfl\OpenFL\Printer.py", line 195, in _wait_for_packet
    p = self.poll()
  File "c:\users\me\openfl\OpenFL\Printer.py", line 220, in poll
    self._process_raw(raw)
  File "c:\users\me\openfl\OpenFL\Printer.py", line 150, in _process_raw
    cmd = Command(self.packet[1])
  File "C:\Users\me\miniconda3\envs\openfl\lib\site-packages\enum\__init__.py", line 348, in __call__
    return cls.__new__(cls, value)
  File "C:\Users\me\miniconda3\envs\openfl\lib\site-packages\enum\__init__.py", line 663, in __new__
    raise ValueError("%s is not a valid %s" % (value, cls.__name__))
ValueError: 147 is not a valid Command

Hmm. There's a problem with OpenFL Printer API class processing response packet from the printer. But the outgoing command apparently works, because I got a dim glow from the laser. Following that with p.set_laser_mm_mW(0, 0, 0) turned the laser back off along with another ValueError: 147. This is good enough for me to set up some voltage probes. The laser has four wires: red, black, blue, and yellow. Here are their voltages at various milliwatt settings, relative to yellow which is connected to ground.

Power (mW) Red Black Blue
0 (OFF) 11.20 8.67 4.89
1 11.20 7.40 3.75
10 11.20 7.27 3.61
20 11.19 7.12 3.52
30 11.19 7.01 3.44
40 11.18 6.91 3.36
50 11.18 6.80 3.28
60 11.18 6.71 3.24
70 11.17 6.63 3.20
80 11.16 6.55 3.14

These values weren't as enlightening as I had hoped they would be, but maybe these snapshots will make more sense in the context of a normal print job.