diff --git a/VirtualRobot/Nodes/RobotNode.cpp b/VirtualRobot/Nodes/RobotNode.cpp
index 8298691bfc22221a3daf83ba7a676d53841392a0..077b2d7ab09ebf176ca677d959e82ffc2a9abc17 100644
--- a/VirtualRobot/Nodes/RobotNode.cpp
+++ b/VirtualRobot/Nodes/RobotNode.cpp
@@ -538,11 +538,11 @@ namespace VirtualRobot
     RobotNodePtr RobotNode::clone(RobotPtr newRobot, bool cloneChildren,
                                   RobotNodePtr initializeWithParent,
                                   CollisionCheckerPtr colChecker,
-                                  float scaling,
+                                  std::optional<float> scaling,
                                   bool preventCloningMeshesIfScalingIs1)
     {
-        // If scaling is <= 0 this->scaling is used instead. This enables different scalings while still able to clone the robot
-        auto actualScaling = scaling > 0 ? scaling : this->scaling;
+        const float actualScaling = scaling.value_or(this->scaling);
+        const float scalingFactor = scaling.has_value() ? scaling.value() / this->scaling : 1.0f;
 
         ReadLockPtr lock = getRobot()->getReadLock();
 
@@ -556,20 +556,20 @@ namespace VirtualRobot
 
         VisualizationNodePtr clonedVisualizationNode;
 
-        const bool deepMeshClone = !preventCloningMeshesIfScalingIs1 || std::abs(scaling - 1) <= 0;
+        const bool deepMeshClone = !preventCloningMeshesIfScalingIs1 || std::abs(scalingFactor - 1) <= 1e-12;
         if (visualizationModel)
         {
-            clonedVisualizationNode = visualizationModel->clone(deepMeshClone, actualScaling);
+            clonedVisualizationNode = visualizationModel->clone(deepMeshClone, scalingFactor);
         }
 
         CollisionModelPtr clonedCollisionModel;
 
         if (collisionModel)
         {
-            clonedCollisionModel = collisionModel->clone(colChecker, actualScaling, deepMeshClone);
+            clonedCollisionModel = collisionModel->clone(colChecker, scalingFactor, deepMeshClone);
         }
 
-        RobotNodePtr result = _clone(newRobot, clonedVisualizationNode, clonedCollisionModel, colChecker, scaling > 0 ? scaling : 1.0f);
+        RobotNodePtr result = _clone(newRobot, clonedVisualizationNode, clonedCollisionModel, colChecker, scalingFactor);
 
         if (!result)
         {
diff --git a/VirtualRobot/Nodes/RobotNode.h b/VirtualRobot/Nodes/RobotNode.h
index 454973471658e6eecc0698d000484b2e83b69dc8..1e2c571211c3c0b099b9970f686ae0ffa414be21 100644
--- a/VirtualRobot/Nodes/RobotNode.h
+++ b/VirtualRobot/Nodes/RobotNode.h
@@ -32,6 +32,7 @@
 
 #include <Eigen/Core>
 
+#include <optional>
 #include <string>
 #include <vector>
 #include <map>
@@ -271,7 +272,7 @@ namespace VirtualRobot
                                    bool cloneChildren = true,
                                    RobotNodePtr initializeWithParent = RobotNodePtr(),
                                    CollisionCheckerPtr colChecker = CollisionCheckerPtr(),
-                                   float scaling = 1.0f,
+                                   std::optional<float> scaling = std::nullopt,
                                    bool preventCloningMeshesIfScalingIs1 = false);
 
         inline float getJointValueOffset() const
diff --git a/VirtualRobot/Primitive.h b/VirtualRobot/Primitive.h
index 9d03fef485396abd4c647cdfce38adde4fa8a806..0977163be8d85009654d7c94df33440cf04017a2 100644
--- a/VirtualRobot/Primitive.h
+++ b/VirtualRobot/Primitive.h
@@ -22,6 +22,8 @@ namespace VirtualRobot
 
             virtual std::unique_ptr<Primitive> clone() const = 0;
 
+            virtual void scaleLinear(float scalingFactor) = 0;
+
         protected:
             Primitive(int type) : type(type), transform(Eigen::Matrix4f::Identity()) {}
             std::string getTransformString(int tabs = 0);
@@ -47,6 +49,14 @@ namespace VirtualRobot
                 clone->transform = transform;
                 return clone;
             }
+
+            void scaleLinear(float scalingFactor) final
+            {
+                transform.block(0, 3, 3, 1) *= scalingFactor;
+                width *= scalingFactor;
+                height *= scalingFactor;
+                depth *= scalingFactor;
+            }
         };
 
         class VIRTUAL_ROBOT_IMPORT_EXPORT Sphere : public Primitive
@@ -64,6 +74,12 @@ namespace VirtualRobot
                 clone->transform = transform;
                 return clone;
             }
+
+            void scaleLinear(float scalingFactor) final
+            {
+                transform.block(0, 3, 3, 1) *= scalingFactor;
+                radius *= scalingFactor;
+            }
         };
 
         class VIRTUAL_ROBOT_IMPORT_EXPORT Cylinder : public Primitive
@@ -82,6 +98,13 @@ namespace VirtualRobot
                 clone->transform = transform;
                 return clone;
             }
+
+            void scaleLinear(float scalingFactor) final
+            {
+                transform.block(0, 3, 3, 1) *= scalingFactor;
+                height *= scalingFactor;
+                radius *= scalingFactor;
+            }
         };
 
         /**
@@ -103,6 +126,13 @@ namespace VirtualRobot
                 clone->transform = transform;
                 return clone;
             }
+
+            void scaleLinear(float scalingFactor) final
+            {
+                transform.block(0, 3, 3, 1) *= scalingFactor;
+                height *= scalingFactor;
+                radius *= scalingFactor;
+            }
         };
 
         typedef std::shared_ptr<Primitive> PrimitivePtr;
diff --git a/VirtualRobot/Robot.cpp b/VirtualRobot/Robot.cpp
index ea1b6d6e698d919d9b0d8c1de7941b063238a20c..86643243dbec2439c1c739517da975ce66d0dd23 100644
--- a/VirtualRobot/Robot.cpp
+++ b/VirtualRobot/Robot.cpp
@@ -766,7 +766,7 @@ namespace VirtualRobot
             bool cloneRNS,
             bool cloneEEFs,
             CollisionCheckerPtr collisionChecker,
-            float scaling,
+            std::optional<float> scaling,
             bool preventCloningMeshesIfScalingIs1)
     {
         THROW_VR_EXCEPTION_IF(!startJoint, " StartJoint is nullptr");
@@ -787,7 +787,7 @@ namespace VirtualRobot
         RobotNodePtr rootNew = startJoint->clone(result, true, RobotNodePtr(), colChecker, scaling, preventCloningMeshesIfScalingIs1);
         THROW_VR_EXCEPTION_IF(!rootNew, "Clone failed...");
         result->setRootNode(rootNew);
-        result->setScaling(scaling > 0 ? scaling : this->scaling);
+        result->setScaling(scaling.value_or(this->scaling));
 
         std::vector<RobotNodePtr> rn = result->getRobotNodes();
 
@@ -849,7 +849,7 @@ namespace VirtualRobot
     }
 
     RobotPtr Robot::cloneScaling() {
-        return clone(getName(), CollisionCheckerPtr(), -1.0f);
+        return clone();
     }
 
     Eigen::Matrix4f Robot::getGlobalPoseForRobotNode(
@@ -905,7 +905,7 @@ namespace VirtualRobot
 
     VirtualRobot::RobotPtr Robot::clone(const std::string& name,
                                         CollisionCheckerPtr collisionChecker,
-                                        float scaling,
+                                        std::optional<float> scaling,
                                         bool preventCloningMeshesIfScalingIs1)
     {
         VirtualRobot::RobotPtr result = extractSubPart(this->getRootNode(),
@@ -929,7 +929,7 @@ namespace VirtualRobot
     }
 
     RobotPtr Robot::clone(CollisionCheckerPtr collisionChecker,
-                          float scaling,
+                          std::optional<float> scaling,
                           bool preventCloningMeshesIfScalingIs1)
     {
         return clone(getName(), collisionChecker, scaling, preventCloningMeshesIfScalingIs1);
diff --git a/VirtualRobot/Robot.h b/VirtualRobot/Robot.h
index 1ab3255d1128438ff71ff27369eefe55df24a82d..868c00deb126dcac31e13277eb3f37cfef1e549c 100644
--- a/VirtualRobot/Robot.h
+++ b/VirtualRobot/Robot.h
@@ -303,7 +303,7 @@ namespace VirtualRobot
                                         bool cloneRNS = true,
                                         bool cloneEEFs = true,
                                         CollisionCheckerPtr collisionChecker = CollisionCheckerPtr(),
-                                        float scaling = 1.0f,
+                                        std::optional<float> scaling = std::nullopt,
                                         bool preventCloningMeshesIfScalingIs1 = false);
 
         /*!
@@ -315,13 +315,14 @@ namespace VirtualRobot
         */
         virtual RobotPtr clone(const std::string& name,
                                CollisionCheckerPtr collisionChecker = CollisionCheckerPtr(),
-                               float scaling = 1.0f,
+                               std::optional<float> scaling = std::nullopt,
                                bool preventCloningMeshesIfScalingIs1 = false);
         virtual RobotPtr clone(CollisionCheckerPtr collisionChecker = CollisionCheckerPtr(),
-                               float scaling = 1.0f,
+                               std::optional<float> scaling = std::nullopt,
                                bool preventCloningMeshesIfScalingIs1 = false);
 
-        /*! @brief Clones this robot and keeps the current scaling for the robot and each robot node */
+        /*! @brief Clones this robot and keeps the current scaling for the robot and each robot node. */
+        [[deprecated("Use clone() instead. Which now contains scaling as an optional.")]]
         virtual RobotPtr cloneScaling();
 
         //! Just storing the filename.
diff --git a/VirtualRobot/RobotFactory.cpp b/VirtualRobot/RobotFactory.cpp
index e49afc9cb4e22e1fccceaf54eb3987e565d74434..22869b7ff279acdfc121fbadba0cc1f3f050a514 100644
--- a/VirtualRobot/RobotFactory.cpp
+++ b/VirtualRobot/RobotFactory.cpp
@@ -344,6 +344,80 @@ namespace VirtualRobot
         return true;
     }
 
+    void RobotFactory::scaleLinear(RobotNode &node, float sizeScaling, float weightScaling)
+    {
+        Eigen::Matrix4f localTransformation = node.getLocalTransformation();
+        localTransformation.block(0, 3, 3, 1) *= sizeScaling;
+        node.setLocalTransformation(localTransformation);
+
+        if (node.optionalDHParameter.isSet)
+        {
+            node.optionalDHParameter.setAInMM(node.optionalDHParameter.aMM() * sizeScaling);
+            node.optionalDHParameter.setDInMM(node.optionalDHParameter.dMM() * sizeScaling);
+        }
+
+        node.setMass(node.getMass() * weightScaling);
+        node.setCoMLocal(node.getCoMLocal() * sizeScaling);
+        node.setInertiaMatrix(node.getInertiaMatrix() * pow(sizeScaling, 2) * weightScaling);
+        node.setScaling(node.getScaling() * sizeScaling);
+    }
+
+    void RobotFactory::scaleLinear(Robot &robot, float sizeScaling, float weightScaling,
+                                   const std::map<std::string, float> &customSegmentLengths,
+                                   const std::map<std::string, float>& customSizeScaling)
+    {
+        for (auto node : robot.getRobotNodes())
+        {
+            float model_height_scaling = sizeScaling;
+
+            const auto segLengthIt = customSegmentLengths.find(node->getName());
+            const auto sizeScaleIt = customSizeScaling.find(node->getName());
+
+            if (sizeScaleIt != customSizeScaling.end())
+            {
+                model_height_scaling = sizeScaleIt->second;
+            }
+
+            if (segLengthIt != customSegmentLengths.end())
+            {
+                if (sizeScaleIt != customSizeScaling.end())
+                {
+                    VR_WARNING << "Custom segment length ignored for node " << node->getName()
+                               << " because custom height scaling was already specified ";
+                }
+                else
+                {
+                    const float l = node->getLocalTransformation().block(0, 3, 3, 1).norm();
+                    if (l != 0.0f)
+                        model_height_scaling = 1.0f / l * segLengthIt->second;
+                }
+            }
+
+            for (auto sensor : node->getSensors())
+            {
+                Eigen::Matrix4f lt = sensor->getParentNodeToSensorTransformation();
+                lt.block(0, 3, 3, 1) *= model_height_scaling;
+                sensor->setRobotNodeToSensorTransformation(lt);
+            }
+
+            scaleLinear(*node.get(), model_height_scaling, weightScaling);
+
+            if (auto vis = node->visualizationModel)
+            {
+                node->setVisualization(node->visualizationModel->clone(true, model_height_scaling));
+            }
+
+            if (auto col = node->getCollisionModel())
+            {
+                node->setCollisionModel(col->clone(node->getCollisionChecker(), model_height_scaling, true));
+            }
+
+            node->getPrimitiveApproximation().scaleLinear(model_height_scaling);
+        }
+        robot.setScaling(robot.getScaling() * sizeScaling);
+        robot.setMass(robot.getMass() * weightScaling);
+    }
+
     RobotPtr RobotFactory::cloneChangeStructure(RobotPtr robot, robotStructureDef& newStructure)
     {
         VR_ASSERT(robot);
diff --git a/VirtualRobot/RobotFactory.h b/VirtualRobot/RobotFactory.h
index 0b5303446453bcd3bf55baee5bffc92b7308374a..e73cbe19fe49bbe0680d8ff24d5f820fb391fd69 100644
--- a/VirtualRobot/RobotFactory.h
+++ b/VirtualRobot/RobotFactory.h
@@ -147,6 +147,21 @@ namespace VirtualRobot
 
         static bool detach(RobotPtr robot, RobotNodePtr rn);
 
+        static void scaleLinear(RobotNode& node, float sizeScaling, float weightScaling = 1.);
+
+        /**
+         * Method to linearly scale the size (in all axes) and the weight of the robot, e.g. for the MMM reference model.
+         * This includes scaling all kinematic and dynamic properties as well as the visualization, collision and primitive approximation models.
+         * @param robot
+         * @param sizeScaling linear scaling factor in x,y,z-direction
+         * @param weightScaling linear weight factor
+         * @param customSegmentLengths (Optional) RobotNode name -> custom translation length. Takes priority over sizeScaling
+         * @param customSizeScaling (Optional) RobotNode name -> custom size scaling. Takes priority over customSegmentLengths.
+         */
+        static void scaleLinear(Robot& robot, float sizeScaling, float weightScaling = 1.,
+                                const std::map<std::string, float>& customSegmentLengths = std::map<std::string, float>(),
+                                const std::map<std::string, float>& customSegmentSizeScaling = std::map<std::string, float>());
+
     protected:
 
         // some internal stuff
diff --git a/VirtualRobot/SceneObject.cpp b/VirtualRobot/SceneObject.cpp
index 734ec473976bfd677d1607a1853d0a6e8c878e24..96925f44c617a5d5f33ec9123d6e803e5d8d6892 100644
--- a/VirtualRobot/SceneObject.cpp
+++ b/VirtualRobot/SceneObject.cpp
@@ -1662,4 +1662,20 @@ namespace VirtualRobot
         return defaultPrimitives.empty() && primitives.empty();
     }
 
+    void SceneObject::PrimitiveApproximation::scaleLinear(float scalingFactor)
+    {
+        for (auto& primitive : this->defaultPrimitives)
+        {
+            primitive->scaleLinear(scalingFactor);
+        }
+
+        for (auto& [id, primitives] : this->primitives)
+        {
+            for (auto& primitive : primitives)
+            {
+                primitive->scaleLinear(scalingFactor);
+            }
+        }
+    }
+
 } // namespace
diff --git a/VirtualRobot/SceneObject.h b/VirtualRobot/SceneObject.h
index aefd37fc17badf91da02a82b8691284a7be07e23..3fb7348e3d1443b39797732a2d15fbda53b9acd7 100644
--- a/VirtualRobot/SceneObject.h
+++ b/VirtualRobot/SceneObject.h
@@ -105,6 +105,8 @@ namespace VirtualRobot
 
             bool empty() const;
 
+            void scaleLinear(float scalingFactor);
+
         private:
             std::vector<Primitive::PrimitivePtr> defaultPrimitives;
             std::map<std::string, std::vector<Primitive::PrimitivePtr>> primitives;