equation 
  assert(cardinality(frame_a) > 0,
    "Connector frame_a of revolute joint is not connected");
  assert(cardinality(frame_b) > 0,
    "Connector frame_b of revolute joint is not connected");
  
  if not planarCutJoint then
    defineBranch(frame_a.R, frame_b.R);
    
    angle = Cv.from_deg(phi_offset) + phi;
    w = der(phi);
    a = der(w);
    
    // relationships between quantities of frame_a and of frame_b
    R_rel = Frames.planarRotation(e, angle, der(angle));
    frame_b.r_0 = frame_a.r_0;
    
    if rooted(frame_a.R) then
      R_rel_inv = Frames.nullRotation();
      frame_b.R = Frames.absoluteRotation(frame_a.R, R_rel);
      frame_a.f = -Frames.resolve1(R_rel, frame_b.f);
      frame_a.t = -Frames.resolve1(R_rel, frame_b.t);
    else
      R_rel_inv = Frames.Orientation(T=transpose(R_rel.T),w= -e*der(angle));
      frame_a.R = Frames.absoluteRotation(frame_b.R, R_rel_inv);
      frame_b.f = -Frames.resolve2(R_rel, frame_a.f);
      frame_b.t = -Frames.resolve2(R_rel, frame_a.t);
    end if;
    
    // d'Alemberts principle
    tau = -frame_b.t*e;
    
    // Set not used variables to arbitrary value
    r_rel_a = zeros(3);
    f_c = zeros(2);
    ex_b = zeros(3);
    ey_b = zeros(3);
  else
    // Determine relative position vector resolved in frame_a
    R_rel = Frames.relativeRotation(frame_a.R, frame_b.R);
    // r_rel_a = Frames.resolve2(frame_a.R, frame_b.r_0 - frame_a.r_0);
    r_rel_a = T.resolve1(R_rel.T, T.resolve2(frame_b.R.T, frame_b.r_0 - frame_a.r_0));
    
    // Constraint equations
    0 = ex_a*r_rel_a;
    0 = ey_a*r_rel_a;
    
    /* Transform forces and torques
       (Note that e has the same coordinates in frame_a and in frame_b
        and therefore a simplified transformation of the torque in
        direction of the rotation axis can be performed. The torques
        perpendicular to this axis are assumed to be zero by the
        assumption of a planar joint)
    */
    frame_b.t = -e*tau;
    frame_a.t = -frame_b.t;
    
    frame_a.f = [ex_a, ey_a]*f_c;
    frame_b.f = -Frames.resolve2(R_rel, frame_a.f);
    
    //angle = planarRotationAngle(e, npx, npx_b);
    angle = 0;
    phi = 0;
    w = 0;
    a = 0;
    
    // dummy
    R_rel_inv = Frames.nullRotation();
    
    // check that revolute joint is used in planar loop
    ex_b = Frames.resolve2(R_rel, ex_a);
    ey_b = Frames.resolve2(R_rel, ey_a);
    assert(noEvent(abs(e*r_rel_a) <= 1.e-10 and abs(e*ex_b) <= 1.e-10 and 
      abs(e*ey_b) <= 1.e-10), "
The revolute joint is used with parameter 
planarCutJoint=true. However, the revolute joint
is not part of a planar loop where the axis of the
revolute joint (parameter n) is orthogonal to the
possible movements. Either set planarCutJoint=false
or correct the definition of the axes vectors n
in the revolute joints of the planar loop.
");
  end if;
end Revolute;