diff --git a/scripts/ahrs_calibration.py b/scripts/ahrs_calibration.py
index d5db82c16da907c693fec202e1369f8a0b99058d..8fe5bc7e71375aa569cc7733538a834ad1ab12f7 100755
--- a/scripts/ahrs_calibration.py
+++ b/scripts/ahrs_calibration.py
@@ -44,7 +44,7 @@ class CalibrateAHRS(kp.Module):
         self.plots_path = self.require('plots_path')
         det_id = self.require('det_id')
         self.detector = kp.hardware.Detector(det_id=det_id)
-        self.du = self.get('du', default=1)
+        self.dus = self.detector.dus
 
         self.clbmap = kp.db.CLBMap(det_oid=det_id)
 
@@ -52,10 +52,13 @@ class CalibrateAHRS(kp.Module):
         self.cuckoo_log = kp.time.Cuckoo(10, print)
         self.data = {}
         queue_size = 50000
-        for ahrs_param in ('yaw', 'pitch', 'roll'):
-            self.data[ahrs_param] = defaultdict(
+        for du in self.dus:
+            self.data[du] = {}
+            for ahrs_param in ('yaw', 'pitch', 'roll'):
+                self.data[du][ahrs_param] = defaultdict(
+                    partial(deque, maxlen=queue_size))
+            self.data[du]['times'] = defaultdict(
                 partial(deque, maxlen=queue_size))
-        self.times = defaultdict(partial(deque, maxlen=queue_size))
         self.lock = threading.Lock()
         self.index = 0
 
@@ -71,23 +74,22 @@ class CalibrateAHRS(kp.Module):
             self.log.info("Skipping base CLB")
             return blob
 
-        if clb.du != self.du:
-            return blob
-
         yaw = tmch_data.yaw
         calib = get_latest_ahrs_calibration(clb.upi, max_version=4)
 
         if calib is None:
+            self.log.warning("No calibration found for CLB UPI '%s'", clb.upi)
             return blob
 
+        du = clb.du
         cyaw, cpitch, croll = fit_ahrs(tmch_data.A, tmch_data.H, *calib)
         self.cuckoo_log("DU{}-DOM{} (random pick): calibrated yaw={}".format(
             clb.du, clb.floor, cyaw))
         with self.lock:
-            self.data['yaw'][clb.floor].append(cyaw)
-            self.data['pitch'][clb.floor].append(cpitch)
-            self.data['roll'][clb.floor].append(croll)
-            self.times[clb.floor].append(now)
+            self.data[du]['yaw'][clb.floor].append(cyaw)
+            self.data[du]['pitch'][clb.floor].append(cpitch)
+            self.data[du]['roll'][clb.floor].append(croll)
+            self.data[du]['times'][clb.floor].append(now)
 
         self.cuckoo.msg()
         return blob
@@ -96,30 +98,33 @@ class CalibrateAHRS(kp.Module):
         print(self.__class__.__name__ + ": updating plot.")
         # xfmt = md.DateFormatter('%Y-%m-%d %H:%M')
         xfmt = md.DateFormatter('%H:%M')
-        for ahrs_param in self.data.keys():
-            fig, ax = plt.subplots(figsize=(16, 6))
-            sns.set_palette("husl", 18)
-            ax.set_title("AHRS {} Calibration on DU{}\n{}".format(
-                ahrs_param, self.du, datetime.utcnow()))
-            ax.set_xlabel("UTC time")
-            ax.xaxis.set_major_formatter(xfmt)
-            ax.set_ylabel(ahrs_param)
-            with self.lock:
-                for floor in sorted(self.data[ahrs_param].keys()):
-                    ax.plot(
-                        self.times[floor],
-                        self.data[ahrs_param][floor],
-                        marker='.',
-                        linestyle='none',
-                        label="Floor {}".format(floor))
-            lgd = plt.legend(
-                bbox_to_anchor=(1.005, 1), loc=2, borderaxespad=0.)
-            fig.tight_layout()
-            plt.savefig(
-                os.path.join(self.plots_path, ahrs_param + '_calib.png'),
-                bbox_extra_artists=(lgd, ),
-                bbox_inches='tight')
-            plt.close('all')
+        for du in self.dus:
+            data = self.data[du]
+            for ahrs_param in data.keys():
+                fig, ax = plt.subplots(figsize=(16, 6))
+                sns.set_palette("husl", 18)
+                ax.set_title("AHRS {} Calibration on DU{}\n{}".format(
+                    ahrs_param, du, datetime.utcnow()))
+                ax.set_xlabel("UTC time")
+                ax.xaxis.set_major_formatter(xfmt)
+                ax.set_ylabel(ahrs_param)
+                with self.lock:
+                    for floor in sorted(data[ahrs_param].keys()):
+                        ax.plot(data['times'][floor],
+                                data[ahrs_param][floor],
+                                marker='.',
+                                linestyle='none',
+                                label="Floor {}".format(floor))
+                lgd = plt.legend(bbox_to_anchor=(1.005, 1),
+                                 loc=2,
+                                 borderaxespad=0.)
+                fig.tight_layout()
+                plt.savefig(os.path.join(
+                    self.plots_path,
+                    ahrs_param + '_calib_du{}.png'.format(du)),
+                            bbox_extra_artists=(lgd, ),
+                            bbox_inches='tight')
+                plt.close('all')
 
 
 def main():
@@ -132,13 +137,12 @@ def main():
     ligier_port = int(args['-p'])
 
     pipe = kp.Pipeline()
-    pipe.attach(
-        kp.io.ch.CHPump,
-        host=ligier_ip,
-        port=ligier_port,
-        tags='IO_MONIT',
-        timeout=60 * 60 * 24 * 7,
-        max_queue=2000)
+    pipe.attach(kp.io.ch.CHPump,
+                host=ligier_ip,
+                port=ligier_port,
+                tags='IO_MONIT',
+                timeout=60 * 60 * 24 * 7,
+                max_queue=2000)
     pipe.attach(kp.io.daq.DAQProcessor)
     pipe.attach(CalibrateAHRS, det_id=det_id, plots_path=plots_path)
     pipe.drain()