diff --git a/ale/base/type_sensor.py b/ale/base/type_sensor.py
index 6c70eec580b1bcb452a609440c52b98300d78946..87b4394d932f556b3164b72d23a993a2e45834bc 100644
--- a/ale/base/type_sensor.py
+++ b/ale/base/type_sensor.py
@@ -386,6 +386,22 @@ class Cahvor():
         """
         raise NotImplementedError
 
+    @property
+    def final_inst_frame(self):
+      """
+      Defines the final frame before cahvor frame in the frame chain
+      """
+      raise NotImplementedError
+
+    @property
+    def sensor_position(self):
+      positions, velocities, times = super().sensor_position
+      positions += self.cahvor_camera_dict["C"]
+      if self._props.get("landed", False):
+        positions = np.array([[0, 0, 0]] * len(times))
+        velocities = np.array([[0, 0, 0]] * len(times))
+      return positions, velocities, times
+
     def compute_h_c(self):
         """
         Computes the h_c element of a cahvor model for the conversion
@@ -451,7 +467,10 @@ class Cahvor():
             v_s = self.compute_v_s()
             H_prime = (self.cahvor_camera_dict['H'] - h_c * self.cahvor_camera_dict['A'])/h_s
             V_prime = (self.cahvor_camera_dict['V'] - v_c * self.cahvor_camera_dict['A'])/v_s
-            self._cahvor_rotation_matrix = np.array([H_prime, -V_prime, -self.cahvor_camera_dict['A']])
+            if self._props.get("landed", False):
+              self._cahvor_rotation_matrix = np.array([H_prime, -V_prime, -self.cahvor_camera_dict['A']])
+            else:
+              self._cahvor_rotation_matrix = np.array([H_prime, V_prime, self.cahvor_camera_dict['A']])
         return self._cahvor_rotation_matrix
 
     @property
@@ -466,13 +485,17 @@ class Cahvor():
           A networkx frame chain object
         """
         if not hasattr(self, '_frame_chain'):
-            self._frame_chain = FrameChain.from_spice(sensor_frame=self.spacecraft_id * 1000,
+            self._frame_chain = FrameChain.from_spice(sensor_frame=self.final_inst_frame,
                                                       target_frame=self.target_frame_id,
                                                       center_ephemeris_time=self.center_ephemeris_time,
                                                       ephemeris_times=self.ephemeris_time,
                                                       nadir=False, exact_ck_times=False)
             cahvor_quats = Rotation.from_matrix(self.cahvor_rotation_matrix).as_quat()
-            cahvor_rotation = ConstantRotation(cahvor_quats, self.spacecraft_id * 1000, self.sensor_frame_id)
+            # If we are landed we only care about the final cahvor frame relative to the target
+            if self._props.get("landed", False):
+              cahvor_rotation = ConstantRotation(cahvor_quats, self.target_frame_id, self.sensor_frame_id)
+            else:
+              cahvor_rotation = ConstantRotation(cahvor_quats, self.final_inst_frame, self.sensor_frame_id)
             self._frame_chain.add_edge(rotation = cahvor_rotation)
         return self._frame_chain
 
@@ -487,7 +510,9 @@ class Cahvor():
         : float
           The detector center line/boresight center line
         """
-        return self.compute_v_c()
+        # Add here 0.5 for consistency with the CSM convention that the
+        # upper-left image pixel is at (0.5, 0.5).
+        return self.compute_v_c() + 0.5
 
     @property
     def detector_center_sample(self):
@@ -500,7 +525,9 @@ class Cahvor():
         : float
           The detector center sample/boresight center sample
         """
-        return self.compute_h_c()
+        # Add here 0.5 for consistency with the CSM convention that the
+        # upper-left image pixel is at (0.5, 0.5).
+        return self.compute_h_c() + 0.5
 
     @property
     def pixel_size(self):
diff --git a/ale/drivers/msl_drivers.py b/ale/drivers/msl_drivers.py
index 7af3d1ef3546a90c8c28ab4b25e2bd0a726784e0..b06677b8a800ad7e7738ea12d50751119f80e0fb 100644
--- a/ale/drivers/msl_drivers.py
+++ b/ale/drivers/msl_drivers.py
@@ -69,6 +69,18 @@ class MslMastcamPds3NaifSpiceDriver(Cahvor, Framer, Pds3Label, NaifSpice, Cahvor
                 self._cahvor_camera_params['R'] = np.array(camera_model_group["MODEL_COMPONENT_6"])
         return self._cahvor_camera_params
 
+    @property
+    def final_inst_frame(self):
+        """
+        Defines MSLs last naif frame before the cahvor model frame
+
+        Returns
+        -------
+        : int
+          Naif frame code for MSL_RSM_HEAD
+        """
+        return spice.bods2c("MSL_RSM_HEAD")
+
     @property
     def sensor_frame_id(self):
         """
@@ -96,7 +108,7 @@ class MslMastcamPds3NaifSpiceDriver(Cahvor, Framer, Pds3Label, NaifSpice, Cahvor
         : list<double>
           focal plane to detector lines
         """
-        return [0, 1/self.pixel_size, 0]
+        return [0, 0, 1/self.pixel_size]
     
     @property
     def focal2pixel_samples(self):
@@ -108,23 +120,7 @@ class MslMastcamPds3NaifSpiceDriver(Cahvor, Framer, Pds3Label, NaifSpice, Cahvor
         : list<double>
           focal plane to detector samples
         """
-        return [0, 0, 1/self.pixel_size]
-
-    @property
-    def detector_center_line(self):
-        return self.label["INSTRUMENT_STATE_PARMS"]["DETECTOR_LINES"]/2
-
-    @property
-    def detector_center_sample(self):
-        return self.label["INSTRUMENT_STATE_PARMS"]["MSL:DETECTOR_SAMPLES"]/2
-
-    @property
-    def detector_start_line(self):
-        return self.label["IMAGE_REQUEST_PARMS"]["FIRST_LINE"]
-
-    @property
-    def detector_start_sample(self):
-        return self.label["IMAGE_REQUEST_PARMS"]["FIRST_LINE_SAMPLE"]
+        return [0, -1/self.pixel_size, 0]
 
     @property
     def sensor_model_version(self):
diff --git a/ale/formatters/formatter.py b/ale/formatters/formatter.py
index 6de1913700912c9f400346627e455c495b05abed..73a9d644435eb621eca0c11f83cc97ec61df8aac 100644
--- a/ale/formatters/formatter.py
+++ b/ale/formatters/formatter.py
@@ -118,7 +118,7 @@ def to_isd(driver):
     sensor_frame = driver.sensor_frame_id
 
     instrument_pointing = {}
-    source_frame, destination_frame, time_dependent_sensor_frame = frame_chain.last_time_dependent_frame_between(1, sensor_frame)
+    source_frame, destination_frame, _ = frame_chain.last_time_dependent_frame_between(1, sensor_frame)
 
     # Reverse the frame order because ISIS orders frames as
     # (destination, intermediate, ..., intermediate, source)
diff --git a/ale/isd_generate.py b/ale/isd_generate.py
index a5a43812a8b10192e16165585eba737ee5d40341..103d18f7f9882668400207a20aebc29fdf2119a3 100755
--- a/ale/isd_generate.py
+++ b/ale/isd_generate.py
@@ -67,6 +67,12 @@ def main():
         action="store_true",
         help="Only use drivers that generate fresh spice data"
     )
+    parser.add_argument(
+        "-l", "--local",
+        action="store_true",
+        help="Generate local spice data, or image that is unaware of itself relative to "
+             "target body. This is largely used for landed/rover data."
+    )
     parser.add_argument(
         '--version',
         action='version',
@@ -97,7 +103,7 @@ def main():
 
     if len(args.input) == 1:
         try:
-            file_to_isd(args.input[0], args.out, kernels=k, log_level=log_level, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice)
+            file_to_isd(args.input[0], args.out, kernels=k, log_level=log_level, only_isis_spice=args.only_isis_spice, only_naif_spice=args.only_naif_spice, local=args.local)
         except Exception as err:
             # Seriously, this just throws a generic Exception?
             sys.exit(f"File {args.input[0]}: {err}")
@@ -107,7 +113,11 @@ def main():
         ) as executor:
             futures = {
                 executor.submit(
-                    file_to_isd, f, **{"kernels": k, "log_level": log_level, "only_isis_spice": args.only_isis_spice, "only_naif_spice": args.only_naif_spice}
+                    file_to_isd, f, **{"kernels": k, 
+                                       "log_level": log_level, 
+                                       "only_isis_spice": args.only_isis_spice, 
+                                       "only_naif_spice": args.only_naif_spice,
+                                       "local": args.local}
                 ): f for f in args.input
             }
             for f in concurrent.futures.as_completed(futures):
@@ -127,7 +137,8 @@ def file_to_isd(
     kernels: list = None,
     log_level=logging.WARNING,
     only_isis_spice=False,
-    only_naif_spice=False
+    only_naif_spice=False,
+    local=False
 ):
     """
     Returns nothing, but acts as a thin wrapper to take the *file* and generate
@@ -152,6 +163,10 @@ def file_to_isd(
 
     logger.info(f"Reading: {file}")
     props = {}
+
+    if local:
+        props['landed'] = local
+
     if kernels is not None:
         kernels = [str(PurePath(p)) for p in kernels]
         props["kernels"] = kernels
diff --git a/tests/pytests/test_cahvor_mixin.py b/tests/pytests/test_cahvor_mixin.py
index 26eee41f9aad1ec1838e47686f1e9f7133cb077e..b3ad22f4b41c2181c3328af7fcb791008cb8fa69 100644
--- a/tests/pytests/test_cahvor_mixin.py
+++ b/tests/pytests/test_cahvor_mixin.py
@@ -27,6 +27,7 @@ class test_cahvor_sensor(unittest.TestCase):
         self.driver.target_frame_id = 10014
         self.driver.center_ephemeris_time = 0
         self.driver.ephemeris_time = [0]
+        self.driver._props = {}
 
     @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict())
     def test_compute_functions(self, cahvor_camera_dict):
@@ -39,26 +40,28 @@ class test_cahvor_sensor(unittest.TestCase):
     def test_cahvor_model_elements(self, cahvor_camera_dict):
         cahvor_matrix = self.driver.cahvor_rotation_matrix
         np.testing.assert_allclose(cahvor_matrix, [[-0.82067034, -0.57129702, 0.01095033],
-                                                   [-0.43920248, 0.6184257, -0.65165238],
-                                                   [ 0.3655151, -0.5396012, -0.7584387 ]])
+                                                   [0.43920248, -0.6184257, 0.65165238],
+                                                   [ -0.3655151, 0.5396012, 0.7584387 ]])
 
     @patch('ale.transformation.FrameChain.from_spice', return_value=ale.transformation.FrameChain())
     @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict())
-    def test_cahvor_frame_chain(self, cahvor_camera_dict, from_spice):
+    @patch("ale.base.type_sensor.Cahvor.final_inst_frame", new_callable=PropertyMock, return_value=-76000)
+    def test_cahvor_frame_chain(self, final_inst_frame, cahvor_camera_dict, from_spice):
       frame_chain = self.driver.frame_chain
       assert len(frame_chain.nodes()) == 2
       assert -76000 in frame_chain.nodes()
       assert -76562 in frame_chain.nodes()
       from_spice.assert_called_with(center_ephemeris_time=0, ephemeris_times=[0], sensor_frame=-76000, target_frame=10014, nadir=False, exact_ck_times=False)
-      np.testing.assert_allclose(frame_chain[-76562][-76000]['rotation'].quat, [-0.28255205, 0.8940826, -0.33309383, 0.09914206])
+      print(frame_chain[-76562][-76000]['rotation'].quat[3])
+      np.testing.assert_allclose(frame_chain[-76562][-76000]['rotation'].quat, [-0.09914206260782343, 0.3330938313054434, 0.8940825953723198, -0.28255205470925904])
 
     @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict())
     def test_cahvor_detector_center_line(self, cahvor_camera_dict):
-        np.testing.assert_almost_equal(self.driver.detector_center_line, 590.1933422831007)
+        np.testing.assert_almost_equal(self.driver.detector_center_line, 590.6933422831007)
     
     @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict())
     def test_cahvor_detector_center_sample(self, cahvor_camera_dict):
-        np.testing.assert_almost_equal(self.driver.detector_center_sample, 673.4306859859296)
+        np.testing.assert_almost_equal(self.driver.detector_center_sample, 673.9306859859296)
 
     @patch("ale.base.type_sensor.Cahvor.cahvor_camera_dict", new_callable=PropertyMock, return_value=cahvor_camera_dict())
     def test_cahvor_pixel_size(self, cahvor_camera_dict):
diff --git a/tests/pytests/test_msl_drivers.py b/tests/pytests/test_msl_drivers.py
index 986dbd2094b72e0f348d2a6c987b9069d319585b..84fb73be88a97c7054234b7609cc0390cec52150 100644
--- a/tests/pytests/test_msl_drivers.py
+++ b/tests/pytests/test_msl_drivers.py
@@ -20,6 +20,11 @@ class test_mastcam_pds_naif(unittest.TestCase):
     def test_exposure_duration(self):
         np.testing.assert_almost_equal(self.driver.exposure_duration, 0.0102)
 
+    def test_final_inst_frame(self):
+        with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76562) as bods2c:
+            assert self.driver.final_inst_frame == -76562
+            bods2c.assert_called_with("MSL_RSM_HEAD")
+
     def test_cahvor_camera_dict(self):
         cahvor_camera_dict = self.driver.cahvor_camera_dict
         assert len(cahvor_camera_dict) == 4
@@ -36,13 +41,13 @@ class test_mastcam_pds_naif(unittest.TestCase):
     def test_focal2pixel_lines(self):
         with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76220) as bods2c, \
              patch('ale.drivers.msl_drivers.spice.gdpool', new_callable=PropertyMock, return_value=[100]) as gdpool:
-            np.testing.assert_allclose(self.driver.focal2pixel_lines, [0, 137.96844341513602, 0])
+            np.testing.assert_allclose(self.driver.focal2pixel_lines, [0, 0, 137.96844341513602])
             bods2c.assert_called_with('MSL_MASTCAM_RIGHT')
             gdpool.assert_called_with('INS-76220_FOCAL_LENGTH', 0, 1)
 
     def test_focal2pixel_samples(self):
         with patch('ale.drivers.msl_drivers.spice.bods2c', new_callable=PropertyMock, return_value=-76220) as bods2c, \
              patch('ale.drivers.msl_drivers.spice.gdpool', new_callable=PropertyMock, return_value=[100]) as gdpool:
-            np.testing.assert_allclose(self.driver.focal2pixel_samples, [0, 0, 137.96844341513602])
+            np.testing.assert_allclose(self.driver.focal2pixel_samples, [0, -137.96844341513602, 0])
             bods2c.assert_called_with('MSL_MASTCAM_RIGHT')
             gdpool.assert_called_with('INS-76220_FOCAL_LENGTH', 0, 1)