{"id":42,"date":"2014-10-21T08:39:10","date_gmt":"2014-10-21T12:39:10","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=42"},"modified":"2014-10-21T08:39:10","modified_gmt":"2014-10-21T12:39:10","slug":"double_pendulum","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/21\/double_pendulum\/","title":{"rendered":"Using MATLAB Graphics from Simulink"},"content":{"rendered":"<div class=\"content\"><!--introduction--><p>Today we're going to take a break from the math behind parametric curves and take a look at using MATLAB Graphics from Simulink.<\/p><p>Combining MATLAB Graphics with Simulink is a very powerful technique for visualizing simulations, but it can be hard to figure out how to get started. Today we&#8217;re going to work through a simple example. We&#8217;ll start with double pendulum example that <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/authors\/31651\">Guy Rouleau<\/a> built as a benchmark for <a href=\"https:\/\/blogs.mathworks.com\/seth\/2009\/02\/26\/modeling-mechanical-systems-the-double-pendulum\/\">his blog post about SimMechanics<\/a>. You can get it from the <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/23126-double-pendulum\">File Exchange<\/a>.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/double_pendulum_model.PNG\" alt=\"\"> <\/p><p>We're going to modify it so that it creates a figure window which shows the pendulum animating while the simulation runs.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/pendulum.png\" alt=\"\"> <\/p><p>We'll do this in two steps. First we'll create a MATLAB class which implements all of the graphics. Next we'll use that class from Simulink. The reason for doing it in two steps is that it makes it easier to debug the graphics before we start integrating it with Simulink.<\/p><!--\/introduction--><h3>Contents<\/h3><div><ul><li><a href=\"#a1c95045-4e0a-4fa7-9f18-4be71ee212db\">Creating the parts of the visualization<\/a><\/li><li><a href=\"#43b35ec9-3557-40d5-9e96-877bd9b907c6\">Creating a DoublePendulum class<\/a><\/li><li><a href=\"#76be1503-f09e-46b4-a8e3-78b23335916b\">Connecting to Simulink<\/a><\/li><li><a href=\"#6ff3a291-9bac-46e2-a67e-58f5ae76c151\">Results<\/a><\/li><\/ul><\/div><h4>Creating the parts of the visualization<a name=\"a1c95045-4e0a-4fa7-9f18-4be71ee212db\"><\/a><\/h4><p>If you look at the picture above, you can see that we need three parts to represent the pendulum, and two objects to represent the traces.<\/p><p>The traces are easy. That&#8217;s exactly what the new <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/animatedline.html\">animatedline object<\/a> is for.<\/p><pre class=\"codeinput\">trace1 = animatedline(<span class=\"string\">'Color'<\/span>, <span class=\"string\">'red'<\/span>);\r\ntrace2 = animatedline(<span class=\"string\">'Color'<\/span>, <span class=\"string\">'green'<\/span>);\r\n<\/pre><p>The blue anchor point is also pretty easy. It&#8217;s just the punchline of a very old MATLAB graphics joke:<\/p><pre>How do you draw a circle in MATLAB?<\/pre><p>The answer is the rectangle command, of course! If we call the rectangle function with a Curvature property, it will round the corners off. If the value of the Curvature is [1 1], then the corners will be completely rounded off, and we'll get a circle!<\/p><pre class=\"codeinput\">circle = rectangle(<span class=\"string\">'Curvature'<\/span>,[1 1]);\r\nr = .5;\r\ncircle.Position = [-r\/2, -r\/2, r, r];\r\ncircle.EdgeColor = <span class=\"string\">'none'<\/span>;\r\ncircle.FaceColor = <span class=\"string\">'blue'<\/span>;\r\naxis <span class=\"string\">equal<\/span>\r\nxlim([-2.5 2.5])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/double_pendulum_02.png\" alt=\"\"> <p>The arms are a little trickier. When they&#8217;re hanging down, we can draw them using two rectangles (one of which is really a circle), but we're going to want them to swing. The <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/hgtransform.html\">hgtransform object<\/a> is the solution to that. The hgtransform object has a Matrix property which we can use to move its children around.<\/p><p>Here's a simple function which shows how to create an arm from an hgtransform and two rectangles.<\/p><pre class=\"language-matlab\"><span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% File: createArm.m<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"keyword\">function<\/span> p = createArm(w, r, len, col)\r\n<span class=\"comment\">% Creates the geometry for one pendulum.<\/span>\r\n  p = hgtransform;\r\n  l = rectangle(<span class=\"string\">'Parent'<\/span>,p);\r\n  l.Position = [-w\/2, -len, w, len];\r\n  l.FaceColor = col;\r\n  l.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n  c = rectangle(<span class=\"string\">'Parent'<\/span>,p,<span class=\"string\">'Curvature'<\/span>,[1 1]);\r\n  c.Position = [-r\/2, -(len+r\/2), r, r];\r\n  c.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n  c.FaceColor = col;\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><pre class=\"codeinput\">cla\r\narm = createArm(.125,r,2.5,<span class=\"string\">'red'<\/span>);\r\naxis <span class=\"string\">equal<\/span>\r\naxis <span class=\"string\">manual<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/double_pendulum_03.png\" alt=\"\"> <p>Now we can change the hgtransform object's Matrix property to make the arm rotate. That's easy to do by using the <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/makehgtform.html\">makehgtform<\/a> function.<\/p><pre class=\"codeinput\">arm.Matrix = makehgtform(<span class=\"string\">'zrotate'<\/span>,pi\/7);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/double_pendulum_04.png\" alt=\"\"> <h4>Creating a DoublePendulum class<a name=\"43b35ec9-3557-40d5-9e96-877bd9b907c6\"><\/a><\/h4><p>If we put these parts together, we get a class which looks something like the following:<\/p><pre class=\"language-matlab\"><span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% File: DoublePendulum.m<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"keyword\">classdef<\/span> DoublePendulum &lt; handle\r\n  <span class=\"comment\">% A class for implementing a MATLAB Graphics visualization of the<\/span>\r\n  <span class=\"comment\">% Simulink model of the double pendulum which Guy Rouleau shared in<\/span>\r\n  <span class=\"comment\">% File Exchange posting 23126.<\/span>\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"keyword\">properties<\/span> (SetAccess=private)\r\n    Arms    = gobjects(1,2);\r\n    Traces  = gobjects(1,2);\r\n    Lengths = [2 2];\r\n    Angles  = [0 0];\r\n    BallWidth = .5;\r\n    ArmWidth = .25;\r\n  <span class=\"keyword\">end<\/span>\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Public methods<\/span>\r\n  <span class=\"keyword\">methods<\/span>\r\n    <span class=\"keyword\">function<\/span> obj = DoublePendulum()\r\n      obj.createGeometry();\r\n      obj.updateTransforms();\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> setAngles(obj, a1, a2)\r\n    <span class=\"comment\">% Call this to change the angles.<\/span>\r\n      obj.Angles(1) = a1;\r\n      obj.Angles(2) = a2;\r\n      obj.addTracePoints();\r\n      obj.updateTransforms();\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> clearPoints(obj)\r\n    <span class=\"comment\">% Call this to reset the traces.<\/span>\r\n      obj.Traces(1).clearpoints();\r\n      obj.Traces(2).clearpoints();\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> r = isAlive(obj)\r\n    <span class=\"comment\">% Call this to check whether the figure window is still alive.<\/span>\r\n      r = isvalid(obj) &amp;&amp; <span class=\"keyword\">...<\/span>\r\n          isvalid(obj.Arms(1)) &amp;&amp; isvalid(obj.Arms(2)) &amp;&amp; <span class=\"keyword\">...<\/span>\r\n          isvalid(obj.Traces(1)) &amp;&amp; isvalid(obj.Traces(2));\r\n    <span class=\"keyword\">end<\/span>\r\n  <span class=\"keyword\">end<\/span>\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Private methods<\/span>\r\n  <span class=\"keyword\">methods<\/span> (Access=private)\r\n    <span class=\"keyword\">function<\/span> createArm(obj, p, len, col)\r\n    <span class=\"comment\">% Creates the geometry for one pendulum. This is basically a copy<\/span>\r\n    <span class=\"comment\">% of the function we created earlier.<\/span>\r\n      w = obj.ArmWidth;\r\n      l = rectangle(<span class=\"string\">'Parent'<\/span>,p);\r\n      l.Position = [-w\/2, -len, w, len];\r\n      l.FaceColor = col;\r\n      l.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n      c = rectangle(<span class=\"string\">'Parent'<\/span>,p);\r\n      r = obj.BallWidth;\r\n      c.Position = [-r\/2, -(len+r\/2), r, r];\r\n      c.Curvature = [1 1];\r\n      c.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n      c.FaceColor = col;\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> addTracePoints(obj)\r\n    <span class=\"comment\">% Adds the current end points of the two pendulums to the traces.<\/span>\r\n      a1 = obj.Angles(1);\r\n      a2 = obj.Angles(2);\r\n      l1 = obj.Lengths(1);\r\n      l2 = obj.Lengths(2);\r\n      x1 =  l1*sin(a1);\r\n      y1 = -l1*cos(a1);\r\n      x2 = x1 + l2*sin(a1+a2);\r\n      y2 = y1 - l2*cos(a1+a2);\r\n      obj.Traces(1).addpoints(x1,y1);\r\n      obj.Traces(2).addpoints(x2,y2);\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> createGeometry(obj)\r\n    <span class=\"comment\">% Creates all of the graphics objects for the visualization.<\/span>\r\n      col1 = <span class=\"string\">'red'<\/span>;\r\n      col2 = <span class=\"string\">'green'<\/span>;\r\n      col3 = <span class=\"string\">'blue'<\/span>;\r\n      fig = figure;\r\n      ax = axes(<span class=\"string\">'Parent'<\/span>,fig);\r\n      <span class=\"comment\">% Create the traces<\/span>\r\n      obj.Traces(1) = animatedline(<span class=\"string\">'Parent'<\/span>, ax, <span class=\"string\">'Color'<\/span>, col1);\r\n      obj.Traces(2) = animatedline(<span class=\"string\">'Parent'<\/span>, ax, <span class=\"string\">'Color'<\/span>, col2);\r\n      <span class=\"comment\">% Create the transforms<\/span>\r\n      obj.Arms(1) = hgtransform(<span class=\"string\">'Parent'<\/span>, ax);\r\n      obj.Arms(2) = hgtransform(<span class=\"string\">'Parent'<\/span>, obj.Arms(1));\r\n      <span class=\"comment\">% Create the arms<\/span>\r\n      createArm(obj, obj.Arms(1), obj.Lengths(1), col1);\r\n      createArm(obj, obj.Arms(2), obj.Lengths(2), col2);\r\n      <span class=\"comment\">% Create a blue circle at the origin.<\/span>\r\n      c = rectangle(<span class=\"string\">'Parent'<\/span>,ax);\r\n      r = obj.BallWidth;\r\n      c.Position = [-r\/2, -r\/2, r, r];\r\n      c.Curvature = [1 1];\r\n      c.EdgeColor = <span class=\"string\">'none'<\/span>;\r\n      c.FaceColor = col3;\r\n      <span class=\"comment\">% Initialize the axes.<\/span>\r\n      maxr = sum(obj.Lengths);\r\n      ax.DataAspectRatio = [1 1 1];\r\n      ax.XLim = [-maxr maxr];\r\n      ax.YLim = [-maxr 1];\r\n      grid(ax,<span class=\"string\">'on'<\/span>);\r\n      ax.SortMethod = <span class=\"string\">'childorder'<\/span>;\r\n    <span class=\"keyword\">end<\/span>\r\n    <span class=\"keyword\">function<\/span> updateTransforms(obj)\r\n    <span class=\"comment\">% Updates the transform matrices.<\/span>\r\n      a1 = obj.Angles(1);\r\n      a2 = obj.Angles(2);\r\n      offset = [0 -obj.Lengths(1) 0];\r\n      obj.Arms(1).Matrix = makehgtform(<span class=\"string\">'zrotate'<\/span>, a1);\r\n      obj.Arms(2).Matrix = makehgtform(<span class=\"string\">'translate'<\/span>, offset, <span class=\"keyword\">...<\/span>\r\n                                       <span class=\"string\">'zrotate'<\/span>, a2);\r\n    <span class=\"keyword\">end<\/span>\r\n  <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p>Notice the createGeometry method which creates each of the parts we talked about earlier. It creates two traces (one red and one green), followed by two arms (again, one red and one green), and then adds a blue circle at the origin.<\/p><p>Also notice the setAngles method. That adds a new angle to each of the traces, and calls makehgtform to rotate each of the two arms.<\/p><p>Now we can create an instance of this class at the MATLAB command line, and use the setAngles method to make it move.<\/p><pre class=\"codeinput\">cla\r\nh = DoublePendulum();\r\n<span class=\"keyword\">for<\/span> a=pi\/5:.1:2*pi\/5\r\n  h.setAngles(a,-a\/2);\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/double_pendulum_06.png\" alt=\"\"> <p>Once we have it working, we're ready to move on to the next step.<\/p><h4>Connecting to Simulink<a name=\"76be1503-f09e-46b4-a8e3-78b23335916b\"><\/a><\/h4><p>The final step is to connect it to Simulink. There are a couple of different ways to do this. We&#8217;re going to do it with an <a href=\"https:\/\/www.mathworks.com\/help\/simulink\/sfg\/what-is-an-s-function.html\">S-function<\/a>. We drag a Level-2 MATLAB S-Function block out of the library, connect it to the same signal as the scope labeled \"Angle Position\", and set its S-function to the following:<\/p><pre class=\"language-matlab\"><span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% File: doublePendulumSFunction.m<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"keyword\">function<\/span> doublePendulumSFunction(block)\r\n<span class=\"comment\">% Level-2 MATLAB file S-function for visualizing a double pendulum.<\/span>\r\n  setup(block)\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% Called when the block is added to a model.<\/span>\r\n<span class=\"keyword\">function<\/span> setup(block)\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% 1 input port, no output ports<\/span>\r\n  block.NumInputPorts  = 1;\r\n  block.NumOutputPorts = 0;\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Setup functional port properties<\/span>\r\n  block.SetPreCompInpPortInfoToDynamic;\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% The input is a vector of 2 angles<\/span>\r\n  block.InputPort(1).Dimensions = 2;\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Register block methods<\/span>\r\n  block.RegBlockMethod(<span class=\"string\">'Start'<\/span>,   @Start);\r\n  block.RegBlockMethod(<span class=\"string\">'Outputs'<\/span>, @Output);\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% To work in external mode<\/span>\r\n  block.SetSimViewingDevice(true);\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% Called when the simulation starts.<\/span>\r\n<span class=\"keyword\">function<\/span> Start(block)\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Check to see if we already have an instance of DoublePendulum<\/span>\r\n  ud = get_param(block.BlockHandle,<span class=\"string\">'UserData'<\/span>);\r\n  <span class=\"keyword\">if<\/span> isempty(ud)\r\n    vis = [];\r\n  <span class=\"keyword\">else<\/span>\r\n    vis = ud.vis;\r\n  <span class=\"keyword\">end<\/span>\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% If not, create one<\/span>\r\n  <span class=\"keyword\">if<\/span> isempty(vis) || ~isa(vis,<span class=\"string\">'DoublePendulum'<\/span>) || ~vis.isAlive\r\n    vis = DoublePendulum();\r\n  <span class=\"keyword\">else<\/span>\r\n    vis.clearPoints();\r\n  <span class=\"keyword\">end<\/span>\r\n  ud.vis = vis;\r\n  <span class=\"comment\">%<\/span>\r\n  <span class=\"comment\">% Save it in UserData<\/span>\r\n  set_param(block.BlockHandle,<span class=\"string\">'UserData'<\/span>,ud);\r\n<span class=\"keyword\">end<\/span>\r\n<span class=\"comment\">%<\/span>\r\n<span class=\"comment\">% Called when the simulation time changes.<\/span>\r\n<span class=\"keyword\">function<\/span> Output(block)\r\n  <span class=\"keyword\">if<\/span> block.IsMajorTimeStep\r\n    <span class=\"comment\">% Every time step, call setAngles<\/span>\r\n    ud = get_param(block.BlockHandle,<span class=\"string\">'UserData'<\/span>);\r\n    vis = ud.vis;\r\n    <span class=\"keyword\">if<\/span> isempty(vis) || ~isa(vis,<span class=\"string\">'DoublePendulum'<\/span>) || ~vis.isAlive\r\n      <span class=\"keyword\">return<\/span>;\r\n    <span class=\"keyword\">end<\/span>\r\n    vis.setAngles(block.InputPort(1).Data(1), <span class=\"keyword\">...<\/span>\r\n                  block.InputPort(1).Data(2));\r\n  <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><p>There are three pieces to this S-Function.<\/p><div><ol><li>The setup function gets called when the block gets loaded. This tells Simulink how to connect the block up to the rest of the model, and it registers the two functions which do the real work.<\/li><li>The function Start gets called when the simulation starts. All it does is create an instance of the DoublePendulum class we defined above, and saves it away in the block's UserData.<\/li><li>The function Output gets called whenever the simulation updates the block's inputs. All we need to do here is call the setAngles method on our DoublePendulum class. It will do all the work of updating our visualization.<\/li><\/ol><\/div><h4>Results<a name=\"6ff3a291-9bac-46e2-a67e-58f5ae76c151\"><\/a><\/h4><p>And that's it! Just press the Run button, and away we go with our pendulum swinging around wildly.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/doublependulumanimation.gif\" alt=\"\"> <\/p><p>Have you got Simulink models which could benefit from custom MATLAB graphics like this?<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_b1b85da322d74fd3bd60ebc799aef941() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='b1b85da322d74fd3bd60ebc799aef941 ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' b1b85da322d74fd3bd60ebc799aef941';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2014 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_b1b85da322d74fd3bd60ebc799aef941()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2014b<br><\/p><\/div><!--\r\nb1b85da322d74fd3bd60ebc799aef941 ##### SOURCE BEGIN #####\r\n%% Using MATLAB Graphics from Simulink\r\n% Today we're going to take a break from the math behind parametric curves and \r\n% take a look at using MATLAB Graphics from Simulink.\r\n%\r\n% Combining MATLAB Graphics with Simulink is a very powerful technique for \r\n% visualizing simulations, but it can be hard to figure out how to get started. \r\n% Today we\u00e2\u20ac\u2122re going to work through \r\n% a simple example. We\u00e2\u20ac\u2122ll start with double pendulum example that Guy Rouleau \r\n% built as a benchmark for <https:\/\/blogs.mathworks.com\/seth\/2009\/02\/26\/modeling-mechanical-systems-the-double-pendulum\/ his blog post about SimMechanics>. \r\n% You can get it from the <https:\/\/www.mathworks.com\/matlabcentral\/fileexchange\/23126-double-pendulum File Exchange>.\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/graphics\/model.png>>\r\n%\r\n% We're going to modify it so that it creates a figure window which shows \r\n% the pendulum animating while the simulation runs.\r\n%\r\n% <<https:\/\/blogs.mathworks.com\/images\/graphics\/pendulum.png>>\r\n%\r\n% We'll do this in two steps. First we'll create a MATLAB class which \r\n% implements all of the graphics. Next we'll use that class from Simulink. \r\n% The reason for doing it in two steps is that it makes it easier to debug \r\n% the graphics before we start integrating it with Simulink.\r\n\r\n%% Creating the parts of the visualization\r\n% If you look at the picture above, you can see that we need three parts to \r\n% represent the pendulum, and two objects to represent the traces.\r\n%\r\n% The traces are easy. That\u00e2\u20ac\u2122s exactly what the new animatedline object is \r\n% for.\r\n\r\ntrace1 = animatedline('Color', 'red');\r\ntrace2 = animatedline('Color', 'green');\r\n\r\n%%\r\n% The blue anchor point is also pretty easy. It\u00e2\u20ac\u2122s just the punchline of a \r\n% very old MATLAB graphics joke:\r\n%\r\n%  How do you draw a circle in MATLAB?\r\n%\r\n% The answer is the rectangle command, of course! If we call the rectangle \r\n% function with a Curvature property, it will round the corners off. If the\r\n% value of the Curvature is [1 1], then the corners will be completely \r\n% rounded off, and we'll get a circle!\r\n%\r\ncircle = rectangle('Curvature',[1 1]);\r\nr = .5;\r\ncircle.Position = [-r\/2, -r\/2, r, r];\r\ncircle.EdgeColor = 'none';\r\ncircle.FaceColor = 'blue';\r\naxis equal\r\nxlim([-2.5 2.5])\r\n\r\n%%\r\n% The arms are a little trickier. When they\u00e2\u20ac\u2122re hanging down, we can \r\n% draw them using two rectangles (one of which is really a circle), but \r\n% we're going to want them to swing. The hgtransform object is the solution \r\n% to that. The hgtransform object has a Matrix property which we can use to\r\n% move its children around.\r\n%\r\n% % Here's a simple function which shows how to create an arm from \r\n% an hgtransform and two rectangles.\r\n%\r\n%   %\r\n%   % File: createArm.m\r\n%   %\r\n%   function p = createArm(w, r, len, col)\r\n%   % Creates the geometry for one pendulum.\r\n%     p = hgtransform;\r\n%     l = rectangle('Parent',p);\r\n%     l.Position = [-w\/2, -len, w, len];\r\n%     l.FaceColor = col;\r\n%     l.EdgeColor = 'none';\r\n%     c = rectangle('Parent',p,'Curvature',[1 1]);\r\n%     c.Position = [-r\/2, -(len+r\/2), r, r];\r\n%     c.EdgeColor = 'none';\r\n%     c.FaceColor = col;\r\n%   end\r\n%\r\ncla\r\narm = createArm(.125,r,2.5,'red');\r\naxis equal\r\naxis manual\r\n%%\r\n% Now we can change the hgtransform object's Matrix property to make the \r\n% arm rotate. That's easy to do by using the <https:\/\/www.mathworks.com\/help\/matlab\/ref\/makehgtform.html makehgtform> function.\r\narm.Matrix = makehgtform('zrotate',pi\/7);\r\n\r\n%% Creating a DoublePendulum class\r\n% If we put these parts together, we get a class which looks something like \r\n% the following:\r\n%\r\n%   %\r\n%   % File: DoublePendulum.m\r\n%   %\r\n%   classdef DoublePendulum < handle\r\n%     % A class for implementing a MATLAB Graphics visualization of the \r\n%     % Simulink model of the double pendulum which Guy Rouleau shared in \r\n%     % File Exchange posting 23126.\r\n%     %\r\n%     properties (SetAccess=private)\r\n%       Arms    = gobjects(1,2);\r\n%       Traces  = gobjects(1,2);\r\n%       Lengths = [2 2];\r\n%       Angles  = [0 0];\r\n%       BallWidth = .5;\r\n%       ArmWidth = .25;\r\n%     end\r\n%     %\r\n%     % Public methods\r\n%     methods\r\n%       function obj = DoublePendulum()\r\n%         obj.createGeometry();\r\n%         obj.updateTransforms();\r\n%       end        \r\n%       function setAngles(obj, a1, a2)\r\n%       % Call this to change the angles.\r\n%         obj.Angles(1) = a1;\r\n%         obj.Angles(2) = a2;\r\n%         obj.addTracePoints();\r\n%         obj.updateTransforms();\r\n%       end\r\n%       function clearPoints(obj)\r\n%       % Call this to reset the traces.\r\n%         obj.Traces(1).clearpoints();\r\n%         obj.Traces(2).clearpoints();\r\n%       end\r\n%       function r = isAlive(obj)\r\n%       % Call this to check whether the figure window is still alive.\r\n%         r = isvalid(obj) && ...\r\n%             isvalid(obj.Arms(1)) && isvalid(obj.Arms(2)) && ...\r\n%             isvalid(obj.Traces(1)) && isvalid(obj.Traces(2));\r\n%       end\r\n%     end\r\n%     %\r\n%     % Private methods\r\n%     methods (Access=private)\r\n%       function createArm(obj, p, len, col)\r\n%       % Creates the geometry for one pendulum. This is basically a copy\r\n%       % of the function we created earlier.\r\n%         w = obj.ArmWidth;\r\n%         l = rectangle('Parent',p);\r\n%         l.Position = [-w\/2, -len, w, len];\r\n%         l.FaceColor = col;\r\n%         l.EdgeColor = 'none';\r\n%         c = rectangle('Parent',p);\r\n%         r = obj.BallWidth;\r\n%         c.Position = [-r\/2, -(len+r\/2), r, r];\r\n%         c.Curvature = [1 1];\r\n%         c.EdgeColor = 'none';\r\n%         c.FaceColor = col;\r\n%       end\r\n%       function addTracePoints(obj)\r\n%       % Adds the current end points of the two pendulums to the traces.\r\n%         a1 = obj.Angles(1);\r\n%         a2 = obj.Angles(2);\r\n%         l1 = obj.Lengths(1);\r\n%         l2 = obj.Lengths(2);\r\n%         x1 =  l1*sin(a1);\r\n%         y1 = -l1*cos(a1);\r\n%         x2 = x1 + l2*sin(a1+a2);\r\n%         y2 = y1 - l2*cos(a1+a2);\r\n%         obj.Traces(1).addpoints(x1,y1);            \r\n%         obj.Traces(2).addpoints(x2,y2);\r\n%       end\r\n%       function createGeometry(obj)\r\n%       % Creates all of the graphics objects for the visualization.\r\n%         col1 = 'red';\r\n%         col2 = 'green';\r\n%         col3 = 'blue';\r\n%         fig = figure;\r\n%         ax = axes('Parent',fig);\r\n%         % Create the traces\r\n%         obj.Traces(1) = animatedline('Parent', ax, 'Color', col1);\r\n%         obj.Traces(2) = animatedline('Parent', ax, 'Color', col2);\r\n%         % Create the transforms\r\n%         obj.Arms(1) = hgtransform('Parent', ax);\r\n%         obj.Arms(2) = hgtransform('Parent', obj.Arms(1));\r\n%         % Create the arms\r\n%         createArm(obj, obj.Arms(1), obj.Lengths(1), col1);\r\n%         createArm(obj, obj.Arms(2), obj.Lengths(2), col2);\r\n%         % Create a blue circle at the origin.\r\n%         c = rectangle('Parent',ax);\r\n%         r = obj.BallWidth;\r\n%         c.Position = [-r\/2, -r\/2, r, r];\r\n%         c.Curvature = [1 1];\r\n%         c.EdgeColor = 'none';\r\n%         c.FaceColor = col3;\r\n%         % Initialize the axes.\r\n%         maxr = sum(obj.Lengths);\r\n%         ax.DataAspectRatio = [1 1 1];\r\n%         ax.XLim = [-maxr maxr];\r\n%         ax.YLim = [-maxr 1];\r\n%         grid(ax,'on');\r\n%         ax.SortMethod = 'childorder';            \r\n%       end\r\n%       function updateTransforms(obj)\r\n%       % Updates the transform matrices.\r\n%         a1 = obj.Angles(1);\r\n%         a2 = obj.Angles(2);\r\n%         offset = [0 -obj.Lengths(1) 0];\r\n%         obj.Arms(1).Matrix = makehgtform('zrotate', a1);\r\n%         obj.Arms(2).Matrix = makehgtform('translate', offset, ...\r\n%                                          'zrotate', a2);\r\n%       end\r\n%     end\r\n%   end\r\n%\r\n% Notice the createGeometry method which creates each of the parts we\r\n% talked about earlier. It creates two traces (one red and one green),\r\n% followed by two arms (again, one red and one green), and then adds a blue\r\n% circle at the origin.\r\n%\r\n% Also notice the setAngles method. That adds a new angle to each of the\r\n% traces, and calls makehgtform to rotate each of the two arms.\r\n%\r\n\r\n%%\r\n% Now we can create an instance of this class at the MATLAB command line, \r\n% and use the setAngles method to make it move.\r\ncla\r\nh = DoublePendulum();\r\nfor a=pi\/5:.1:2*pi\/5\r\n  h.setAngles(a,-a\/2);\r\nend\r\n\r\n%%\r\n% Once we have it working, we're ready to move on to the next step.\r\n%\r\n\r\n%% Connecting to Simulink\r\n% The final step is to connect it to Simulink. There are a couple of \r\n% different ways to do this. We\u00e2\u20ac\u2122re going to do it with an <https:\/\/www.mathworks.com\/help\/simulink\/sfg\/what-is-an-s-function.html S-function>. We \r\n% drag a Level-2 MATLAB S-Function block out of the library, connect it to \r\n% the same signal as the scope labeled \"Angle Position\", and set its \r\n% S-function to the following:\r\n%\r\n%   %\r\n%   % File: doublePendulumSFunction.m\r\n%   %\r\n%   function doublePendulumSFunction(block)\r\n%   % Level-2 MATLAB file S-function for visualizing a double pendulum.\r\n%     setup(block)\r\n%   end\r\n%   %\r\n%   % Called when the block is added to a model.\r\n%   function setup(block)\r\n%     %\r\n%     % 1 input port, no output ports\r\n%     block.NumInputPorts  = 1;\r\n%     block.NumOutputPorts = 0;\r\n%     %\r\n%     % Setup functional port properties\r\n%     block.SetPreCompInpPortInfoToDynamic;\r\n%     %\r\n%     % The input is a vector of 2 angles\r\n%     block.InputPort(1).Dimensions = 2;\r\n%     %\r\n%     % Register block methods\r\n%     block.RegBlockMethod('Start',   @Start);\r\n%     block.RegBlockMethod('Outputs', @Output);\r\n%     %\r\n%     % To work in external mode\r\n%     block.SetSimViewingDevice(true);\r\n%   end\r\n%   %\r\n%   % Called when the simulation starts.\r\n%   function Start(block)\r\n%     %\r\n%     % Check to see if we already have an instance of DoublePendulum\r\n%     ud = get_param(block.BlockHandle,'UserData');\r\n%     if isempty(ud)\r\n%       vis = [];\r\n%     else\r\n%       vis = ud.vis;\r\n%     end\r\n%     %\r\n%     % If not, create one\r\n%     if isempty(vis) || ~isa(vis,'DoublePendulum') || ~vis.isAlive\r\n%       vis = DoublePendulum();\r\n%     else\r\n%       vis.clearPoints();\r\n%     end\r\n%     ud.vis = vis;\r\n%     %\r\n%     % Save it in UserData\r\n%     set_param(block.BlockHandle,'UserData',ud);\r\n%   end\r\n%   %\r\n%   % Called when the simulation time changes.\r\n%   function Output(block)\r\n%     if block.IsMajorTimeStep\r\n%       % Every time step, call setAngles\r\n%       ud = get_param(block.BlockHandle,'UserData');\r\n%       vis = ud.vis;\r\n%       if isempty(vis) || ~isa(vis,'DoublePendulum') || ~vis.isAlive\r\n%         return;\r\n%       end\r\n%       vis.setAngles(block.InputPort(1).Data(1), ...\r\n%                     block.InputPort(1).Data(2));\r\n%     end\r\n%   end\r\n%\r\n% There are three pieces to this S-Function. \r\n% \r\n% # The setup function gets called when the block gets loaded. This tells\r\n% Simulink how to connect the block up to the rest of the model, and it \r\n% registers the two functions which do the real work.\r\n% # The function Start gets called when the simulation starts. All it does is\r\n% create an instance of the DoublePendulum class we defined above, and\r\n% saves it away in the block's UserData.\r\n% # The function Output gets called whenever the simulation updates the\r\n% block's inputs. All we need to do here is call the setAngles method on\r\n% our DoublePendulum class. It will do all the work of updating our\r\n% visualization.\r\n%\r\n\r\n%% Results\r\n% And that's it! Just press the Run button, and away we go with our \r\n% pendulum swinging around wildly.\r\n%\r\n% <<..\/doublependulumanimation.gif>>\r\n%\r\n% Have you got Simulink models which could benefit from custom MATLAB\r\n% graphics like this?\r\n##### SOURCE END ##### b1b85da322d74fd3bd60ebc799aef941\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/doublependulumanimation.gif\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><!--introduction--><p>Today we're going to take a break from the math behind parametric curves and take a look at using MATLAB Graphics from Simulink.... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2014\/10\/21\/double_pendulum\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":49,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[4],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/42"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/comments?post=42"}],"version-history":[{"count":20,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/42\/revisions"}],"predecessor-version":[{"id":63,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/42\/revisions\/63"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/49"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=42"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=42"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=42"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}