Beispiel #1
0
 def __init__(self, plant, scene_graph, diagram):
     self.plant = plant
     self.scene_graph = scene_graph
     self.diagram = diagram
     # Assumes single DOF per Joint.
     joints = []
     for i in range(plant.num_joints()):
         joint = plant.get_joint(JointIndex(i))
         assert joint.name(), joint.name()
         if joint.num_positions() == 0:
             continue
         assert joint.num_positions() == 1, (joint, joint.name())
         assert isinstance(joint, self._acceptable_joints)
         joints.append(joint)
     self._joint_map = {}
     self._joint_names = []
     joints = sorted(joints, key=lambda x: x.position_start())
     for joint in joints:
         self._joint_names.append(joint.name())
         self._joint_map[joint.name()] = joint
     # Get frames.
     nf = plant.num_frames()
     self._frames = []
     for i in range(nf):
         frame = plant.get_frame(FrameIndex(i))
         if frame.name() and not frame.name().startswith("_"):
             self._frames.append(frame)
     assert len(self._frames) > 0
Beispiel #2
0
def MakeNamedViewPositions(mbp, view_name):
    names = [None] * mbp.num_positions()
    for ind in range(mbp.num_joints()):
        joint = mbp.get_joint(JointIndex(ind))
        for i in range(joint.num_positions()):
            names[joint.position_start() + i] = \
                f"{joint.name()}_{joint.position_suffix(i)}"
    for ind in mbp.GetFloatingBaseBodies():
        body = mbp.get_body(ind)
        start = body.floating_positions_start()
        for i in range(7):
            names[start + i] = body.name() + body.floating_position_suffix(i)
    return namedview(view_name, names)
Beispiel #3
0
def MakeNamedViewVelocities(mbp, view_name):
    names = [None] * mbp.num_velocities()
    for ind in range(mbp.num_joints()):
        joint = mbp.get_joint(JointIndex(ind))
        for i in range(joint.num_velocities()):
            names[joint.velocity_start() + i] = \
                f"{joint.name()}_{joint.velocity_suffix(i)}"
    for ind in mbp.GetFloatingBaseBodies():
        body = mbp.get_body(ind)
        start = body.floating_velocities_start()
        for i in range(6):
            names[start +
                  i] = f"{body.name()}_{body.floating_velocity_suffix(i)}"
    return namedview(view_name, names)
Beispiel #4
0
 def test_multibody_plant_api_via_parsing(self):
     # TODO(eric.cousineau): Decouple this when construction can be done
     # without parsing.
     # This a subset of `multibody_plant_sdf_parser_test.cc`.
     file_name = FindResourceOrThrow(
         "drake/multibody/benchmarks/acrobot/acrobot.sdf")
     plant = MultibodyPlant(time_step=0.01)
     model_instance = Parser(plant).AddModelFromFile(file_name)
     self.assertIsInstance(model_instance, ModelInstanceIndex)
     plant.Finalize()
     benchmark = MakeAcrobotPlant(AcrobotParameters(), True)
     self.assertEqual(plant.num_bodies(), benchmark.num_bodies())
     self.assertEqual(plant.num_joints(), benchmark.num_joints())
     self.assertEqual(plant.num_actuators(), benchmark.num_actuators())
     self.assertEqual(plant.num_model_instances(),
                      benchmark.num_model_instances() + 1)
     self.assertEqual(plant.num_positions(), benchmark.num_positions())
     self.assertEqual(plant.num_positions(model_instance=model_instance),
                      benchmark.num_positions())
     self.assertEqual(plant.num_velocities(), benchmark.num_velocities())
     self.assertEqual(plant.num_multibody_states(),
                      benchmark.num_multibody_states())
     self.assertEqual(plant.num_actuated_dofs(),
                      benchmark.num_actuated_dofs())
     self.assertTrue(plant.is_finalized())
     self.assertTrue(plant.HasBodyNamed(name="Link1"))
     self.assertTrue(
         plant.HasBodyNamed(name="Link1", model_instance=model_instance))
     self.assertTrue(plant.HasJointNamed(name="ShoulderJoint"))
     self.assertTrue(
         plant.HasJointNamed(name="ShoulderJoint",
                             model_instance=model_instance))
     shoulder = plant.GetJointByName(name="ShoulderJoint")
     self._test_joint_api(shoulder)
     np.testing.assert_array_equal(shoulder.position_lower_limits(),
                                   [-np.inf])
     np.testing.assert_array_equal(shoulder.position_upper_limits(),
                                   [np.inf])
     self.assertIs(
         shoulder,
         plant.GetJointByName(name="ShoulderJoint",
                              model_instance=model_instance))
     self._test_joint_actuator_api(
         plant.GetJointActuatorByName(name="ElbowJoint"))
     self._test_body_api(plant.GetBodyByName(name="Link1"))
     self.assertIs(
         plant.GetBodyByName(name="Link1"),
         plant.GetBodyByName(name="Link1", model_instance=model_instance))
     self.assertEqual(len(plant.GetBodyIndices(model_instance)), 2)
     self._test_frame_api(plant.GetFrameByName(name="Link1"))
     self.assertIs(
         plant.GetFrameByName(name="Link1"),
         plant.GetFrameByName(name="Link1", model_instance=model_instance))
     self.assertEqual(model_instance,
                      plant.GetModelInstanceByName(name="acrobot"))
     self.assertIsInstance(plant.get_actuation_input_port(), InputPort)
     self.assertIsInstance(plant.get_state_output_port(), OutputPort)
     # Smoke test of deprecated methods.
     with catch_drake_warnings(expected_count=2):
         plant.get_continuous_state_output_port()
         plant.get_continuous_state_output_port(model_instance)
     self.assertIsInstance(plant.get_contact_results_output_port(),
                           OutputPort)
     self.assertIsInstance(plant.num_frames(), int)
     self.assertIsInstance(plant.get_body(body_index=BodyIndex(0)), Body)
     self.assertIs(shoulder, plant.get_joint(joint_index=JointIndex(0)))
     self.assertIsInstance(
         plant.get_joint_actuator(actuator_index=JointActuatorIndex(0)),
         JointActuator)
     self.assertIsInstance(plant.get_frame(frame_index=FrameIndex(0)),
                           Frame)
     self.assertEqual(
         "acrobot",
         plant.GetModelInstanceName(model_instance=model_instance))
    def __init__(self,
                 meshcat,
                 plant,
                 root_context=None,
                 lower_limit=-10.,
                 upper_limit=10.,
                 resolution=0.01):
        """
        Creates an meshcat slider for each joint in the plant.

        Args:
            meshcat:      A Meshcat instance.
            plant:        A MultibodyPlant. publishing_system: The System whose
                          Publish method will be called.  Can be the entire
                          Diagram, but can also be a subsystem.
            root_context: A mutable root Context of the Diagram containing the
                          ``plant``; we will extract the subcontext's using
                          `GetMyContextFromRoot`.
            lower_limit:  A scalar or vector of length robot.num_positions().
                          The lower limit of the slider will be the maximum
                          value of this number and any limit specified in the
                          Joint.

            upper_limit:  A scalar or vector of length robot.num_positions().
                          The upper limit of the slider will be the minimum
                          value of this number and any limit specified in the
                          Joint.

            resolution:   A scalar or vector of length robot.num_positions()
                          that specifies the step argument of the FloatSlider.
        """
        LeafSystem.__init__(self)

        def _broadcast(x, num):
            x = np.array(x)
            assert len(x.shape) <= 1
            return np.array(x) * np.ones(num)

        lower_limit = _broadcast(lower_limit, plant.num_positions())
        upper_limit = _broadcast(upper_limit, plant.num_positions())
        resolution = _broadcast(resolution, plant.num_positions())

        self._meshcat = meshcat
        self._plant = plant
        plant_context = plant.GetMyContextFromRoot(root_context) if \
            root_context else plant.CreateDefaultContext()

        self._sliders = {}
        self._positions = plant.GetPositions(plant_context)
        slider_num = 0
        for i in range(plant.num_joints()):
            joint = plant.get_joint(JointIndex(i))
            low = joint.position_lower_limits()
            upp = joint.position_upper_limits()
            for j in range(joint.num_positions()):
                index = joint.position_start() + j
                description = joint.name()
                if joint.num_positions() > 1:
                    description += '_' + joint.position_suffix(j)
                meshcat.AddSlider(value=self._positions[index],
                                  min=max(low[j], lower_limit[slider_num]),
                                  max=min(upp[j], upper_limit[slider_num]),
                                  step=resolution[slider_num],
                                  name=description)
                self._sliders[index] = description
                slider_num += 1

        port = self.DeclareVectorOutputPort("positions", plant.num_positions(),
                                            self.DoCalcOutput)
        port.disable_caching_by_default()
    def __init__(self,
                 robot,
                 lower_limit=-10.,
                 upper_limit=10.,
                 resolution=0.01,
                 length=200,
                 update_period_sec=0.005):
        """"
        Args:
            robot:       A MultibodyPlant.
            lower_limit: A scalar or vector of length robot.num_positions().
                         The lower limit of the slider will be the maximum
                         value of this number and any limit specified in the
                         Joint.
            upper_limit: A scalar or vector of length robot.num_positions().
                         The upper limit of the slider will be the minimum
                         value of this number and any limit specified in the
                         Joint.
            resolution:  A scalar or vector of length robot.num_positions()
                         that specifies the discretization of the slider.
            length:      The length of the sliders.
            update_period_sec: Specifies how often the window update() method
                         gets called.
        """
        VectorSystem.__init__(self, 0, robot.num_positions())

        # The widgets themselves have undeclared state.  For now, we accept it,
        # and simply disable caching on the output port.
        self.get_output_port(0).disable_caching_by_default()

        def _reshape(x, num):
            x = np.array(x)
            assert len(x.shape) <= 1
            return np.array(x) * np.ones(num)

        lower_limit = _reshape(lower_limit, robot.num_positions())
        upper_limit = _reshape(upper_limit, robot.num_positions())
        resolution = _reshape(resolution, robot.num_positions())

        # Schedule window updates in either case (new or existing window):
        self.DeclarePeriodicPublish(update_period_sec, 0.0)

        self._slider = []
        self._slider_position_start = []
        context = robot.CreateDefaultContext()
        self._default_position = robot.GetPositions(context)

        k = 0
        for i in range(0, robot.num_joints()):
            joint = robot.get_joint(JointIndex(i))
            low = joint.position_lower_limits()
            upp = joint.position_upper_limits()
            for j in range(0, joint.num_positions()):
                index = joint.position_start() + j
                description = joint.name()
                if joint.num_positions() > 1:
                    description += f"[{j}]"
                self._slider_position_start.append(index)
                self._slider.append(
                    FloatSlider(value=self._default_position[index],
                                min=max(low[j], lower_limit[k]),
                                max=min(upp[j], upper_limit[k]),
                                step=resolution[k],
                                continuous_update=True,
                                description=description,
                                style={'description_width': 'initial'},
                                layout=Layout(width=f"'{length}'")))
                display(self._slider[k])
                k += 1
def MakeJointSlidersThatPublishOnCallback(plant,
                                          publishing_system,
                                          root_context,
                                          my_callback=None,
                                          lower_limit=-10.,
                                          upper_limit=10.,
                                          resolution=0.01,
                                          length=200,
                                          continuous_update=True):
    """
    Creates an ipywidget slider for each joint in the plant.  Unlike the
    JointSliders System, we do not expect this to be used in a Simulator.  It
    simply updates the context and calls Publish directly from the slider
    callback.

    Args:
        plant:        A MultibodyPlant.
        publishing_system: The System whose Publish method will be called.  Can
                           be the entire Diagram, but can also be a subsystem.
        root_context: A mutable root Context of the Diagram containing both the
                      ``plant`` and the ``publishing_system``; we will extract
                      the subcontext's using `GetMyContextFromRoot`.
        my_callback:  An optional additional callback function that will be
                      called once immediately and again whenever the sliders
                      are moved, using ``my_callback(plant_context)``.  This
                      can be useful, e.g. for outputting text that prints the
                      current end-effector Jacobian, or for showing a rendered
                      image from a camera.
        lower_limit:  A scalar or vector of length robot.num_positions().
                      The lower limit of the slider will be the maximum
                      value of this number and any limit specified in the
                      Joint.
        upper_limit:  A scalar or vector of length robot.num_positions().
                      The upper limit of the slider will be the minimum
                      value of this number and any limit specified in the
                      Joint.
        resolution:   A scalar or vector of length robot.num_positions()
                      that specifies the step argument of the FloatSlider.
        length:       The length of the sliders, which will be passed as a
                      string to the CSS width field and can be any valid CSS
                      entry (e.g. 100, 100px).
        continuous_update: The continuous_update field for the FloatSliders.
                      The default ``True`` means that this method will publish/
                      callback as the sliders are dragged.  ``False`` means
                      that the publish/callback will only happen once the user
                      finishes dragging the slider.

    Returns:
        A list of the slider widget objects that are created.

    Note: Some publishers (like MeshcatVisualizer) use an initialization event
    to "load" the geometry.  You should call that *before* calling this method
    (e.g. with `meshcat.load()`).
    """
    def _broadcast(x, num):
        x = np.array(x)
        assert len(x.shape) <= 1
        return np.array(x) * np.ones(num)

    lower_limit = _broadcast(lower_limit, plant.num_positions())
    upper_limit = _broadcast(upper_limit, plant.num_positions())
    resolution = _broadcast(resolution, plant.num_positions())

    publishing_context = publishing_system.GetMyContextFromRoot(root_context)
    plant_context = plant.GetMyContextFromRoot(root_context)
    positions = plant.GetPositions(plant_context)

    # Publish once immediately.
    publishing_system.Publish(publishing_context)
    if my_callback:
        my_callback(plant_context)

    def _slider_callback(change, index):
        positions[index] = change.new
        plant.SetPositions(plant_context, positions)
        publishing_system.Publish(publishing_context)
        if my_callback:
            my_callback(plant_context)

    slider_widgets = []
    slider_num = 0
    for i in range(plant.num_joints()):
        joint = plant.get_joint(JointIndex(i))
        low = joint.position_lower_limits()
        upp = joint.position_upper_limits()
        for j in range(joint.num_positions()):
            index = joint.position_start() + j
            description = joint.name()
            if joint.num_positions() > 1:
                description += f"[{j}]"
            slider = FloatSlider(value=positions[index],
                                 min=max(low[j], lower_limit[slider_num]),
                                 max=min(upp[j], upper_limit[slider_num]),
                                 step=resolution[slider_num],
                                 continuous_update=continuous_update,
                                 description=description,
                                 style={'description_width': 'initial'},
                                 layout=Layout(width=f"'{length}'"))
            slider.observe(partial(_slider_callback, index=index),
                           names='value')
            display(slider)
            slider_widgets.append(slider)
            slider_num += 1

    return slider_widgets
Beispiel #8
0
    def __init__(self, robot, lower_limit=-10., upper_limit=10.,
                 resolution=-1, length=200, update_period_sec=0.005,
                 window=None, title=None):
        """"
        Args:
            robot:       A MultibodyPlant.
            lower_limit: A scalar or vector of length robot.num_positions().
                         The lower limit of the slider will be the maximum
                         value of this number and any limit specified in the
                         Joint.
            upper_limit: A scalar or vector of length robot.num_positions().
                         The upper limit of the slider will be the minimum
                         value of this number and any limit specified in the
                         Joint.
            resolution:  A scalar or vector of length robot.num_positions()
                         that specifies the discretization of the slider.  Use
                         -1 (the default) to disable any rounding.
            length:      The length of the sliders (passed as an argument to
                         tk.Scale).
            update_period_sec: Specifies how often the window update() method
                         gets called.
            window:      Optionally pass in a tkinter.Tk() object to add these
                         widgets to.  Default behavior is to create a new
                         window.
            title:       The string that appears as the title of the gui
                         window.  Use None to generate a default title.  This
                         parameter is only used if a window==None.
        """
        VectorSystem.__init__(self, 0, robot.num_positions())

        def _reshape(x, num):
            x = np.array(x)
            assert len(x.shape) <= 1
            return np.array(x) * np.ones(num)

        lower_limit = _reshape(lower_limit, robot.num_positions())
        upper_limit = _reshape(upper_limit, robot.num_positions())
        resolution = _reshape(resolution, robot.num_positions())

        if title is None:
            if robot.num_model_instances() == 1:
                title = robot.GetModelInstanceName(0) + " Joints"
            else:
                title = "Multibody Joints"

        if window is None:
            self.window = tk.Tk()
            self.window.title(title)
        else:
            self.window = window

        # Schedule window updates in either case (new or existing window):
        self.DeclarePeriodicEvent(update_period_sec, 0.0,
                                  PublishEvent(self._update))

        self._slider = []
        self._slider_position_start = []
        context = robot.CreateDefaultContext()
        state = robot.GetPositionsAndVelocities(context)
        self._default_position = state[:robot.num_positions()]

        k = 0
        for i in range(0, robot.num_joints()):
            joint = robot.get_joint(JointIndex(i))
            low = joint.position_lower_limits()
            upp = joint.position_upper_limits()
            for j in range(0, joint.num_positions()):
                self._slider_position_start.append(joint.position_start() + j)
                self._slider.append(tk.Scale(self.window,
                                             from_=max(low[j],
                                                       lower_limit[k]),
                                             to=min(upp[j], upper_limit[k]),
                                             resolution=resolution[k],
                                             label=joint.name(),
                                             length=length,
                                             orient=tk.HORIZONTAL))
                self._slider[k].pack()
                k += 1
Beispiel #9
0
    def __init__(self,
                 robot,
                 lower_limit=-10.,
                 upper_limit=10.,
                 resolution=-1,
                 length=200,
                 update_period_sec=0.005,
                 window=None,
                 title=None):
        """"
        Args:
            robot:       A MultibodyPlant.
            lower_limit: A scalar or vector of length robot.num_positions().
                         The lower limit of the slider will be the maximum
                         value of this number and any limit specified in the
                         Joint.
            upper_limit: A scalar or vector of length robot.num_positions().
                         The upper limit of the slider will be the minimum
                         value of this number and any limit specified in the
                         Joint.
            resolution:  A scalar or vector of length robot.num_positions()
                         that specifies the discretization of the slider.  Use
                         -1 (the default) to disable any rounding.
            update_period_sec: Specifies how often the window update() method
                         gets called.
            window:      Optionally pass in a tkinter.Tk() object to add these
                         widgets to.  Default behavior is to create a new
                         window.
            title:       The string that appears as the title of the gui
                         window.  Use None to generate a default title.  This
                         parameter is only used if a window==None.
        """
        VectorSystem.__init__(self, 0, robot.num_positions())

        def _reshape(x, num):
            x = np.array(x)
            assert len(x.shape) <= 1
            return np.array(x) * np.ones(num)

        def _frame_config(event):
            """
            Execute once to configure the canvas size,
            canvas contains scrollbar and slider_frame.
            """
            self.canvas.configure(scrollregion=self.canvas.bbox("all"),
                                  width=200,
                                  height=min(robot.num_joints() * 60, 400))

        lower_limit = _reshape(lower_limit, robot.num_positions())
        upper_limit = _reshape(upper_limit, robot.num_positions())
        resolution = _reshape(resolution, robot.num_positions())

        if title is None:
            if robot.num_model_instances() == 1:
                title = robot.GetModelInstanceName(0) + " Joints"
            else:
                title = "Multibody Joints"

        if window is None:
            self.window = tk.Tk()
            self.window.title(title)
        else:
            self.window = window

        # Schedule window updates in either case (new or existing window):
        self.DeclarePeriodicPublish(update_period_sec, 0.0)

        self.window.geometry("220x410")
        # Allow only y dimension resizable.
        self.window.resizable(0, 1)

        # Once window is created, create window_frame
        # and canvas that host slider_frame and scrollbar.
        self.window_frame = tk.Frame(self.window, relief=tk.GROOVE, bd=1)
        self.window_frame.place(x=0, y=0)
        self.canvas = tk.Canvas(self.window_frame)

        # Init slider_frame that actually contain the sliders
        # and scrollbar.
        self.slider_frame = tk.Frame(self.canvas)
        self.scrollbar = tk.Scrollbar(self.window_frame,
                                      orient="vertical",
                                      command=self.canvas.yview)
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        # Put scrollbar and slider_frame into canvas.
        self.scrollbar.pack(side="right", fill="y")
        self.canvas.pack(side="left")
        self.canvas.create_window((0, 0),
                                  window=self.slider_frame,
                                  anchor='nw')
        # Call _frame_config to configure canvas size.
        self.slider_frame.bind("<Configure>", _frame_config)

        self._slider = []
        self._slider_position_start = []
        context = robot.CreateDefaultContext()
        state = robot.GetPositionsAndVelocities(context)
        self._default_position = state[:robot.num_positions()]

        k = 0
        for i in range(0, robot.num_joints()):
            joint = robot.get_joint(JointIndex(i))
            low = joint.position_lower_limits()
            upp = joint.position_upper_limits()
            for j in range(0, joint.num_positions()):
                self._slider_position_start.append(joint.position_start() + j)
                self._slider.append(
                    tk.Scale(self.slider_frame,
                             from_=max(low[j], lower_limit[k]),
                             to=min(upp[j], upper_limit[k]),
                             resolution=resolution[k],
                             label=joint.name(),
                             length=length,
                             orient=tk.HORIZONTAL))
                self._slider[k].pack()
                k += 1
Beispiel #10
0
    model = parser.AddModelFromFile(sdf_file_path, model_name)

    # Weld to world so it doesn't fall through floor :D
    base_frame = plant.GetFrameByName("base", model)
    X_WB = RigidTransform([0, 0, 0])
    plant.WeldFrames(plant.world_frame(), base_frame, X_WB)

    plant.Finalize()

    # Must happen after Finalize
    # RuntimeError: Pre-finalize calls to 'num_actuated_dofs()' are not allowed; you must call Finalize() first.
    no_control(plant, builder, model)

    joints = []
    for i in range(plant.num_joints()):
        joints.append(plant.get_joint(JointIndex(i)))

    rclpy.init()
    node = rclpy.create_node('drake_demo')

    # Publish SDF content on robot_description topic
    latching_qos = QoSProfile(depth=1,
                              durability=DurabilityPolicy.TRANSIENT_LOCAL)
    description_publisher = node.create_publisher(StringMsg,
                                                  'robot_description',
                                                  qos_profile=latching_qos)
    msg = StringMsg()
    with open(sdf_file_path, 'r') as sdf_file:
        msg.data = sdf_file.read()
    description_publisher.publish(msg)
def MakeJointSlidersThatPublishOnCallback(plant,
                                          publishing_system,
                                          root_context,
                                          my_callback=None,
                                          lower_limit=-10.,
                                          upper_limit=10.,
                                          resolution=0.01,
                                          length=200,
                                          continuous_update=True,
                                          floating_base=True):
    """
    Creates an ipywidget slider for each joint in the plant.  Unlike the
    JointSliders System, we do not expect this to be used in a Simulator.  It
    simply updates the context and calls Publish directly from the slider
    callback.

    Args:
        plant:        A MultibodyPlant.
        publishing_system: The System whos Publish method will be called.  Can
                           be the entire Diagram, but can also be a subsystem.
        root_context: A mutable root Context of the Diagram containing both the
                      ``plant`` and the ``publishing_system``; we will extract
                      the subcontext's using `GetMyContextFromRoot`.
        my_callback:  An optional additional callback function that will be
                      called once immediately and again whenever the sliders
                      are moved, using ``my_callback(plant_context)``.  This
                      can be useful, e.g. for outputting text that prints the
                      current end-effector Jacobian, or for showing a rendered
                      image from a camera.
        lower_limit:  A scalar or vector of length robot.num_velocities().
                      The lower limit of the slider will be the maximum
                      value of this number and any limit specified in the
                      Joint.
        upper_limit:  A scalar or vector of length robot.num_velocities().
                      The upper limit of the slider will be the minimum
                      value of this number and any limit specified in the
                      Joint.
        resolution:   A scalar or vector of length robot.num_velocities()
                      that specifies the step argument of the FloatSlider.
        length:       The length of the sliders, which will be passed as a
                      string to the CSS width field and can be any valid CSS
                      entry (e.g. 100, 100px).
        continuous_update: The continuous_update field for the FloatSliders.
                      The default ``True`` means that this method will publish/
                      callback as the sliders are dragged.  ``False`` means
                      that the publish/callback will only happen once the user
                      finishes dragging the slider.
        floating_base: If True, then include XYZ/RPY sliders corresponding to
                      the pose of any floating joints.

    Returns:
        A list of the slider widget objects that are created.

    Note: Some publishers (like MeshcatVisualizer) use an initialization event
    to "load" the geometry.  You should call that *before* calling this method
    (e.g. with `meshcat.load()`).
    """
    def _broadcast(x, num):
        x = np.asarray(x)
        assert len(x.shape) <= 1
        return np.array(x) * np.ones(num)

    # Use num_velocities instead of num_positions because we want 6 per
    # floating base, not 7.
    lower_limit = _broadcast(lower_limit, plant.num_velocities())
    upper_limit = _broadcast(upper_limit, plant.num_velocities())
    resolution = _broadcast(resolution, plant.num_velocities())

    publishing_context = publishing_system.GetMyContextFromRoot(root_context)
    plant_context = plant.GetMyContextFromRoot(root_context)
    positions = plant.GetPositions(plant_context)

    # Publish once immediately.
    publishing_system.Publish(publishing_context)
    if my_callback:
        my_callback(plant_context)

    def _slider_callback(change, index, body=None):
        if body:  # Then it's a floating base
            pose = plant.GetFreeBodyPose(plant_context, body)
            vector_pose = np.concatenate(
                (RollPitchYaw(pose.rotation()).vector(), pose.translation()))
            vector_pose[index] = change.new
            plant.SetFreeBodyPose(
                plant_context, body,
                RigidTransform(RollPitchYaw(vector_pose[:3]), vector_pose[3:]))
        else:
            positions[index] = change.new
            plant.SetPositions(plant_context, positions)
        publishing_system.Publish(publishing_context)
        if my_callback:
            my_callback(plant_context)

    slider_widgets = []
    for i in range(plant.num_joints()):
        joint = plant.get_joint(JointIndex(i))
        low = joint.position_lower_limits()
        upp = joint.position_upper_limits()
        for j in range(joint.num_positions()):
            index = joint.position_start() + j
            description = joint.name()
            if joint.num_positions() > 1:
                description += f"[{j}]"
            slider = FloatSlider(value=positions[index],
                                 min=max(low[j], lower_limit[index]),
                                 max=min(upp[j], upper_limit[index]),
                                 step=resolution[index],
                                 continuous_update=continuous_update,
                                 description=description,
                                 style={'description_width': 'initial'},
                                 layout=Layout(width=f"'{length}'"))
            slider.observe(partial(_slider_callback, index=index),
                           names='value')
            display(slider)
            slider_widgets.append(slider)

    if floating_base:
        for bi in plant.GetFloatingBaseBodies():
            body = plant.get_body(bi)
            index = body.floating_velocities_start() - plant.num_positions()
            pose = plant.GetFreeBodyPose(plant_context, body)
            vector_pose = np.concatenate(
                (RollPitchYaw(pose.rotation()).vector(), pose.translation()))
            relative_index = 0
            for dof in ["roll", "pitch", "yaw", "x", "y", "z"]:
                slider = FloatSlider(min=lower_limit[index],
                                     max=upper_limit[index],
                                     value=vector_pose[relative_index],
                                     step=resolution[index],
                                     continuous_update=continuous_update,
                                     description=f"{body.name()}_{dof}",
                                     layout=Layout(width='90%'))
                slider.observe(partial(_slider_callback,
                                       index=relative_index,
                                       body=body),
                               names='value')
                display(slider)
                slider_widgets.append(slider)
                index += 1
                relative_index += 1

    return slider_widgets