diff --git a/core/detectors/sts/CbmStsBaseLinkDef.h b/core/detectors/sts/CbmStsBaseLinkDef.h
index 5fd4a03d16f704305e9a629691a253bc2e515f11..22171bcc85591f745051111630619df1a5a2376a 100644
--- a/core/detectors/sts/CbmStsBaseLinkDef.h
+++ b/core/detectors/sts/CbmStsBaseLinkDef.h
@@ -21,4 +21,7 @@
 #pragma link C++ class CbmStsSetup + ;
 #pragma link C++ class CbmStsStation + ;
 
+#pragma link C++ enum CbmStsELoss;
+#pragma link C++ enum CbmStsSensorClass;
+
 #endif /* __CINT__ */
diff --git a/reco/detectors/sts/CbmRecoSts.cxx b/reco/detectors/sts/CbmRecoSts.cxx
index 349da2d807ff921f6c60953cbbc9db96d0cafffa..19e8fb05be0d38e4fcd3471b41018ae671223cf9 100644
--- a/reco/detectors/sts/CbmRecoSts.cxx
+++ b/reco/detectors/sts/CbmRecoSts.cxx
@@ -20,6 +20,7 @@
 #include "CbmStsParSetSensorCond.h"
 #include "CbmStsParSim.h"
 #include "CbmStsRecoModule.h"
+#include "CbmStsRecoModuleOrtho.h"
 #include "CbmStsSetup.h"
 #include <FairField.h>
 #include <FairRun.h>
@@ -67,20 +68,25 @@ UInt_t CbmRecoSts::CreateModules() {
     assert(setupSensor);
     Int_t sensorAddress = Int_t(setupSensor->GetAddress());
 
+    // --- Parameter sets from database or user-defined
+    CbmStsParSetModule* modulePars = (fUserParSetModule ? fUserParSetModule : fParSetModule);
+    CbmStsParSetSensor* sensorPars = (fUserParSetSensor ? fUserParSetSensor : fParSetSensor);
+    CbmStsParSetSensorCond* sensorConds = (fUserParSetCond ? fUserParSetCond : fParSetCond);
+
     // --- Module parameters
     const CbmStsParModule& modPar =
       (fUserParModule ? *fUserParModule
-                      : fParSetModule->GetParModule(moduleAddress));
+                      : modulePars->GetParModule(moduleAddress));
 
     // --- Sensor parameters
     const CbmStsParSensor& sensPar =
       (fUserParSensor ? *fUserParSensor
-                      : fParSetSensor->GetParSensor(sensorAddress));
+                      : sensorPars->GetParSensor(sensorAddress));
 
     // --- Sensor conditions
     const CbmStsParSensorCond& sensCond =
       (fUserParSensorCond ? *fUserParSensorCond
-                          : fParSetCond->GetParSensor(sensorAddress));
+                          : sensorConds->GetParSensor(sensorAddress));
 
     // --- Calculate and set average Lorentz shift
     // --- This will be used in hit finding for correcting the position.
@@ -112,8 +118,9 @@ UInt_t CbmRecoSts::CreateModules() {
     }  //? Lorentz-shift correction
 
     // --- Create reco module
-    CbmStsRecoModule* recoModule =
-      new CbmStsRecoModule(setupModule, modPar, sensPar, lorentzF, lorentzB);
+    CbmStsRecoModule* recoModule = new CbmStsRecoModule(setupModule, modPar, sensPar,
+                                                        lorentzF, lorentzB);
+    assert(recoModule);
     auto result = fModules.insert({moduleAddress, recoModule});
     assert(result.second);
     fModuleIndex.push_back(recoModule);
diff --git a/reco/detectors/sts/CbmRecoSts.h b/reco/detectors/sts/CbmRecoSts.h
index 0489d6cce40dc4a0d7a4313474aaecd15d0bfec3..318d3ac3044bf655f29e74a180225a69c825cf1c 100644
--- a/reco/detectors/sts/CbmRecoSts.h
+++ b/reco/detectors/sts/CbmRecoSts.h
@@ -167,16 +167,31 @@ public:
   void UseModulePar(CbmStsParModule* modulePar) { fUserParModule = modulePar; }
 
 
-  /** @brief User-defined sensor parameters
-      ** @param parModule Sensor parameter object
+  /** @brief User-defined module parameter set
+     ** @param parModule Module parameter set object
+     **
+     ** If defined, this parameter set will be used instead of that found in the runtimeDb.
+     */
+  void UseModuleParSet(CbmStsParSetModule* moduleParSet) { fUserParSetModule = moduleParSet; }
+
+
+  /** @brief User-defined sensor condition parameters
+      ** @param parModule Sensor condition parameter object
       **
-      ** If defined, these parameters will be used for all sensors instead
+      ** If defined, these condition parameters will be used for all sensors instead
       ** of those found in the runtimeDb.
       */
   void UseSensorCond(CbmStsParSensorCond* sensorCond) {
     fUserParSensorCond = sensorCond;
   }
 
+  /** @brief User-defined module parameter set
+     ** @param parModule Module parameter set object
+     **
+     ** If defined, this parameter set will be used instead of that found in the runtimeDb.
+     */
+  void UseSensorCondSet(CbmStsParSetSensorCond* sensorCondSet) { fUserParSetCond = sensorCondSet; }
+
 
   /** @brief User-defined sensor parameters
      ** @param parModule Sensor parameter object
@@ -187,6 +202,14 @@ public:
   void UseSensorPar(CbmStsParSensor* sensorPar) { fUserParSensor = sensorPar; }
 
 
+  /** @brief User-defined module parameter set
+     ** @param parModule Module parameter set object
+     **
+     ** If defined, this parameter set will be used instead of that found in the runtimeDb.
+     */
+  void UseSensorParSet(CbmStsParSetSensor* sensorParSet) { fUserParSetSensor = sensorParSet; }
+
+
 private:
   /** @brief Average Lorentz Shift in a sensor
      ** @param conditions  Sensor operating conditions
@@ -240,6 +263,11 @@ private:
   CbmStsParSensor* fUserParSensor         = nullptr;
   CbmStsParSensorCond* fUserParSensorCond = nullptr;
 
+  // --- User-defined parameter sets, not from database
+  CbmStsParSetModule* fUserParSetModule   = nullptr;
+  CbmStsParSetSensor* fUserParSetSensor   = nullptr;
+  CbmStsParSetSensorCond* fUserParSetCond = nullptr;
+
   // --- Settings
   ECbmRecoMode fMode           = kCbmRecoEvent;  ///< Time-slice or event
   Double_t fTimeCutDigisSig    = 3.;      ///< Time cut for cluster finding
diff --git a/reco/detectors/sts/CbmStsRecoModule.cxx b/reco/detectors/sts/CbmStsRecoModule.cxx
index aac2534c9878a60059c354917df6eefde09b347e..491e2061a39b6aed1cd56bb1148efc500de8700a 100644
--- a/reco/detectors/sts/CbmStsRecoModule.cxx
+++ b/reco/detectors/sts/CbmStsRecoModule.cxx
@@ -16,6 +16,7 @@
 #include "CbmStsAlgoAnaCluster.h"
 #include "CbmStsAlgoFindClusters.h"
 #include "CbmStsAlgoFindHits.h"
+#include "CbmStsAlgoFindHitsOrtho.h"
 #include "CbmStsDigi.h"
 #include "CbmStsModule.h"
 #include "CbmStsParSensor.h"
@@ -59,8 +60,8 @@ void CbmStsRecoModule::AddDigiToQueue(const CbmStsDigi* digi, Int_t digiIndex) {
   Int_t moduleAddress =
     CbmStsAddress::GetMotherAddress(digi->GetAddress(), kStsModule);
   assert(moduleAddress == fSetupModule->GetAddress());
-  assert(digi->GetChannel() < 2 * fNofStrips);
-  if (digi->GetChannel() < fNofStrips)
+  assert(digi->GetChannel() < fNofStripsF + fNofStripsB);
+  if (digi->GetChannel() < fNofStripsF)
     fDigisF.push_back({digi, digiIndex});
   else
     fDigisB.push_back({digi, digiIndex});
@@ -90,7 +91,7 @@ void CbmStsRecoModule::Reconstruct() {
   fClusterFinder->Exec(fDigisF,
                        fClustersF,
                        fSetupModule->GetAddress(),
-                       fNofStrips,
+                       fNofStripsF,
                        0,
                        fTimeCutDigiSig,
                        fTimeCutDigiAbs,
@@ -99,8 +100,8 @@ void CbmStsRecoModule::Reconstruct() {
   fClusterFinder->Exec(fDigisB,
                        fClustersB,
                        fSetupModule->GetAddress(),
-                       fNofStrips,
-                       fNofStrips,
+                       fNofStripsB,
+                       fNofStripsF,
                        fTimeCutDigiSig,
                        fTimeCutDigiAbs,
                        fConnectEdgeBack,
@@ -125,21 +126,28 @@ void CbmStsRecoModule::Reconstruct() {
             });
 
   // --- Perform hit finding
-  assert(fHitFinder);
-  fHitFinder->Exec(fClustersF,
-                   fClustersB,
-                   fHits,
-                   fSetupModule->GetAddress(),
-                   fTimeCutClusterSig,
-                   fTimeCutClusterAbs,
-                   fDyActive,
-                   fNofStrips,
-                   fStripPitch,
-                   fStereoFront,
-                   fStereoBack,
-                   fLorentzShiftF,
-                   fLorentzShiftB,
-                   fMatrix);
+  if (fHitFinder)  fHitFinder->Exec(fClustersF,
+                                    fClustersB,
+                                    fHits,
+                                    fSetupModule->GetAddress(),
+                                    fTimeCutClusterSig,
+                                    fTimeCutClusterAbs,
+                                    fDyActive,
+                                    fNofStripsF,
+                                    fStripPitchF,
+                                    fStereoFront,
+                                    fStereoBack,
+                                    fLorentzShiftF,
+                                    fLorentzShiftB,
+                                    fMatrix);
+  else if ( fHitFinderOrtho ) fHitFinderOrtho->Exec(fClustersF, fClustersB, fHits,
+                                                    fSetupModule->GetAddress(),
+                                                    fTimeCutClusterSig,
+                                                    fTimeCutClusterAbs,
+                                                    fNofStripsF, fNofStripsB,
+                                                    fStripPitchF, fStripPitchB,
+                                                    fLorentzShiftF, fLorentzShiftB,
+                                                    fMatrix);
 }
 // -------------------------------------------------------------------------
 
@@ -156,11 +164,11 @@ void CbmStsRecoModule::Reset() {
 void CbmStsRecoModule::Init() {
 
   // Reconstruction is currently implemented for double-sided strip
-  // sensor with the same number of strips and strip pitch on the
-  // front and on the back side.
+  // sensors (class DssdStereo or DssdOrtho)
 
   // --- Sensor class must be DssdStereo
-  assert(fParSensor->GetClass() == CbmStsSensorClass::kDssdStereo);
+  auto type = fParSensor->GetClass();
+  assert(type == CbmStsSensorClass::kDssdStereo || type == CbmStsSensorClass::kDssdOrtho);
 
   // --- Check for physical node of sensor
   assert(fSetupModule);
@@ -179,25 +187,36 @@ void CbmStsRecoModule::Init() {
   fMatrix = sensorNode->GetMatrix();
 
   // --- Number of strips must be the same on both sides
-  Int_t nStripsF = fParSensor->GetParInt(4);
-  Int_t nStripsB = fParSensor->GetParInt(5);
-  assert(nStripsF > 0 && nStripsF == nStripsB);
-  fNofStrips = nStripsF;
-
-  // --- Strip pitch must be the same on both sides
-  fStripPitch = fParSensor->GetPar(6);
-  assert(fStripPitch > 0. && fStripPitch == fParSensor->GetPar(7));
-
-  // --- Check that active size in x fits the geometrical extension
-  assert(Double_t(fNofStrips) * fStripPitch <= fParSensor->GetPar(0));
-
-  // --- Check that active size in y fits the geometrical extension
-  fDyActive = fParSensor->GetPar(3);
-  assert(fDyActive <= fParSensor->GetPar(1));
-
-  // --- Horizontal cross-connection for non-vanishing stereo angles
+  // --- Number of strips, strip pitch and stereo angle
+  fNofStripsF = fParSensor->GetParInt(4);
+  fNofStripsB = fParSensor->GetParInt(5);
+  fStripPitchF = fParSensor->GetPar(6);
+  fStripPitchB = fParSensor->GetPar(7);
   fStereoFront = fParSensor->GetPar(8);
   fStereoBack  = fParSensor->GetPar(9);
+  assert(fNofStripsF > 0);
+  assert(fNofStripsB > 0);
+  assert(fStripPitchF > 0.);
+  assert(fStripPitchB > 0.);
+
+  // --- For DssdStereo, number of strips and pitch must be the same on both sides
+  if ( type == CbmStsSensorClass::kDssdStereo ) {
+    assert ( fNofStripsB == fNofStripsF );
+    assert ( fStripPitchB == fStripPitchF );
+  }
+
+  // --- Check consistency with geometric extensions
+  if ( type == CbmStsSensorClass::kDssdStereo ) {
+    assert(Double_t(fNofStripsF) * fStripPitchF <= fParSensor->GetPar(0));
+    fDyActive = fParSensor->GetPar(3);
+    assert(fDyActive <= fParSensor->GetPar(1));
+  }
+  else if ( type == CbmStsSensorClass::kDssdOrtho ) {
+    assert(Double_t(fNofStripsF) * fStripPitchF <= fParSensor->GetPar(0));
+    assert(Double_t(fNofStripsB) * fStripPitchB <= fParSensor->GetPar(1));
+  }
+
+  // --- Horizontal cross-connection for non-vanishing stereo angles
   if (fStereoFront > 1.) fConnectEdgeFront = kTRUE;
   if (fStereoBack > 1.) fConnectEdgeBack = kTRUE;
 
@@ -207,9 +226,10 @@ void CbmStsRecoModule::Init() {
   fConnectEdgeBack  = kFALSE;
 
   // Algorithms
-  fClusterAna    = new CbmStsAlgoAnaCluster();
-  fClusterFinder = new CbmStsAlgoFindClusters();
-  fHitFinder     = new CbmStsAlgoFindHits();
+  fClusterAna     = new CbmStsAlgoAnaCluster();
+  fClusterFinder  = new CbmStsAlgoFindClusters();
+  if (type == CbmStsSensorClass::kDssdStereo) fHitFinder = new CbmStsAlgoFindHits();
+  else fHitFinderOrtho = new CbmStsAlgoFindHitsOrtho();
 
   // Name
   fName = fSetupModule->GetName();
@@ -220,7 +240,7 @@ void CbmStsRecoModule::Init() {
 // -----   Info to string  -------------------------------------------------
 std::string CbmStsRecoModule::ToString() const {
   std::stringstream ss;
-  ss << fSetupModule->ToString() << " Strips " << fNofStrips;
+  ss << fSetupModule->ToString() << " Strips " << fNofStripsF << " / " << fNofStripsB;
   return ss.str();
 }
 // -------------------------------------------------------------------------
diff --git a/reco/detectors/sts/CbmStsRecoModule.h b/reco/detectors/sts/CbmStsRecoModule.h
index 2aa06bad8b9d592b9b21204781ea1ac887965dea..62227af1e764558c15510cd6f0c453b03d41848f 100644
--- a/reco/detectors/sts/CbmStsRecoModule.h
+++ b/reco/detectors/sts/CbmStsRecoModule.h
@@ -16,6 +16,7 @@ class TGeoHMatrix;
 class CbmStsAlgoAnaCluster;
 class CbmStsAlgoFindClusters;
 class CbmStsAlgoFindHits;
+class CbmStsAlgoFindHitsOrtho;
 class CbmStsHit;
 class CbmStsDigi;
 class CbmStsModule;
@@ -121,9 +122,10 @@ private:
 
 private:
   // --- Algorithms
-  CbmStsAlgoAnaCluster* fClusterAna      = nullptr;  //! ///< Algo
-  CbmStsAlgoFindClusters* fClusterFinder = nullptr;  //! ///< Algo
-  CbmStsAlgoFindHits* fHitFinder         = nullptr;  //! ///< Algo
+  CbmStsAlgoAnaCluster* fClusterAna        = nullptr;  //! ///< Algo
+  CbmStsAlgoFindClusters* fClusterFinder   = nullptr;  //! ///< Algo
+  CbmStsAlgoFindHits* fHitFinder           = nullptr;  //! ///< Algo
+  CbmStsAlgoFindHitsOrtho* fHitFinderOrtho = nullptr;  //! ///< Algo
   std::mutex fLock {};
 
   // --- Parameters
@@ -131,8 +133,10 @@ private:
   const CbmStsParModule* fParModule = nullptr;  //!
   const CbmStsParSensor* fParSensor = nullptr;  //!
   Double_t fDyActive                = 0.;       ///< Active sensor size in y
-  UInt_t fNofStrips                 = 0;        ///< Number of sensor strips
-  Double_t fStripPitch              = 0.;       ///< Sensor strip pitch [cm]
+  UInt_t fNofStripsF                = 0;        ///< Number of sensor strips front side
+  UInt_t fNofStripsB                = 0;        ///< Number of sensor strips back side
+  Double_t fStripPitchF             = 0.;       ///< Sensor strip pitch front side [cm]
+  Double_t fStripPitchB             = 0.;       ///< Sensor strip pitch back side [cm]
   Double_t fStereoFront   = 0.;       ///< Strip stereo angle front side [deg]
   Double_t fStereoBack    = 0.;       ///< Strip stereo angle back side [deg]
   TGeoHMatrix* fMatrix    = nullptr;  ///< Sensor position in global C.S. [cm]