{"id":116601,"date":"2026-10-21T21:40:40","date_gmt":"2026-10-21T13:40:40","guid":{"rendered":"https:\/\/www.wsisp.com\/helps\/116601.html"},"modified":"2026-10-21T21:40:40","modified_gmt":"2026-10-21T13:40:40","slug":"python%e7%9a%84%e6%9c%ba%e5%99%a8%e4%ba%ba%e5%9f%ba%e7%a1%80%e5%8e%9f%e7%90%86%e5%b7%a5%e4%b8%9a%e5%9c%ba%e6%99%af%e6%a8%a1%e6%8b%9f%e7%ac%ac%e5%85%ab%e5%8d%81%e4%b8%89%e7%af%87%e8%a3%85%e9%85%8d","status":"publish","type":"post","link":"https:\/\/www.wsisp.com\/helps\/116601.html","title":{"rendered":"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002"},"content":{"rendered":"<p>\u300aPython\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u300b\u7b2c\u516b\u5341\u4e09\u7bc7&#xff1a;\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\u2014\u2014PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f<\/p>\n<p>\u00a0<\/p>\n<p>1. \u5b9e\u9645\u5de5\u4e1a\u5e94\u7528\u573a\u666f<\/p>\n<p>\u00a0<\/p>\n<p>\u5468\u4e00\u65e9\u6668&#xff0c;\u6c7d\u8f66\u53d1\u52a8\u673a\u7f38\u4f53\u88c5\u914d\u7ebf\u5f00\u73ed\u9996\u68c0\u30024-DOF SCARA\u673a\u68b0\u81c2&#xff08;\u57fa\u5ea7\u65cb\u8f6c\u5173\u8282\u03b8\u2081\u989d\u5b9a\u626d\u77e985 N\u00b7m\u3001\u7b49\u6548\u8f6c\u52a8\u60ef\u91cfJ&#061;0.12 kg\u00b7m\u00b2\u3001\u7c98\u6027\u6469\u64e6\u7cfb\u6570b&#061;0.8 N\u00b7m\u00b7s\/rad&#xff0c;\u5927\u81c2\u957f0.45 m\/3.5 kg&#xff0c;\u5c0f\u81c2\u957f0.35 m\/2.0 kg&#xff0c;\u5782\u76f4\u5e73\u79fbd\u2084\u884c\u7a0b0~0.30 m\/\u989d\u5b9a\u901f\u5ea60.20 m\/s&#xff0c;\u57fa\u5ea7\u504f\u8dddd\u2081&#061;0.32 m&#xff09;\u6267\u884c\u8f74\u627f\u538b\u88c5\u5de5\u5e8f&#xff1a;\u672b\u7aef\u6267\u884c\u5668\u9700\u6cbf\u03b8\u2081\u65b9\u5411\u4ece0\u00b0\u8f6c\u523045\u00b0&#xff0c;\u518d\u4fdd\u6301\u4e0d\u52a8\u7b49\u5f85\u538b\u88c5\u6c14\u7f38\u52a8\u4f5c\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u8c03\u8bd5\u5de5\u7a0b\u5e08\u8001\u5468\u76ef\u7740\u793a\u6ce2\u5668\u4e0a\u7684\u5173\u8282\u89d2\u66f2\u7ebf&#xff1a;&#034;\u03b8\u2081\u4ece0\u00b0\u523045\u00b0\u7684\u9636\u8dc3\u54cd\u5e94&#xff0c;\u5355\u8c03\u722c\u5347&#xff0c;\u8c03\u8282\u65f6\u95f4\u7ea60.6 s&#xff0c;\u7a33\u6001\u8bef\u5dee\u63a5\u8fd1\u96f6\u3002\u538b\u88c5\u8282\u62cd\u8981\u6c420.5 s\u5185\u5230\u4f4d\u4e14\u7a33\u6001\u8bef\u5dee\u5c0f\u4e8e0.5\u00b0&#xff0c;\u73b0\u5728\u5230\u4f4d\u65f6\u95f4\u5dee\u4e00\u70b9\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u4e0a\u4f4d\u673a\u5f00\u53d1\u5c0f\u90d1\u8c03\u51fa\u63a7\u5236\u5668\u53c2\u6570&#xff1a;&#034;\u73b0\u5728\u7528\u7684\u662fPD\u63a7\u5236&#xff0c;Kp&#061;20 N\u00b7m\/rad&#xff0c;Kd&#061;3 N\u00b7m\u00b7s\/rad\u3002\u7b97\u8fc7\u963b\u5c3c\u6bd4\u03b6\u22481.23&#xff0c;\u8fc7\u963b\u5c3c\u7cfb\u7edf&#xff0c;\u6240\u4ee5\u6ca1\u6709\u8d85\u8c03\u3002\u5230\u4f4d\u65f6\u95f4\u53d7Kd\u5f71\u54cd\u2014\u2014\u5fae\u5206\u9879\u63d0\u4f9b\u963b\u5c3c&#xff0c;\u4f46\u592a\u5927\u4e86\u54cd\u5e94\u53d8\u6162\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u8001\u5468\u70b9\u5934&#xff1a;&#034;\u8fc7\u963b\u5c3c\u5355\u8c03\u6536\u655b&#xff0c;\u6ca1\u6709\u8d85\u8c03&#xff0c;\u8fd9\u5bf9\u88c5\u914d\u662f\u597d\u4e8b\u3002\u7a33\u6001\u8bef\u5dee\u63a5\u8fd1\u96f6\u662f\u56e0\u4e3a\u8fd9\u4e2a\u5173\u8282\u662f\u6c34\u5e73\u65cb\u8f6c&#xff0c;\u4e0d\u53d7\u91cd\u529b\u77e9&#xff0c;\u53ea\u6709\u7c98\u6027\u6469\u64e6\u2014\u2014\u9759\u6b62\u65f6\u7c98\u6027\u6469\u64e6\u4e3a\u96f6&#xff0c;\u4e0d\u9700\u8981\u8bef\u5dee\u6765\u5e73\u8861\u3002\u5982\u679c\u6362\u6210\u5782\u76f4\u5173\u8282&#xff0c;\u52a0\u4e86\u8d1f\u8f7d\u91cd\u529b&#xff0c;\u7eafPD\u5c31\u4f1a\u6709\u9759\u5dee&#xff0c;\u5f97\u52a0\u79ef\u5206\u9879\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>&#034;\u5bf9&#xff0c;SCARA\u7684\u03b8\u2081\u662f\u7ad6\u76f4\u8f74\u65cb\u8f6c&#xff0c;\u91cd\u529b\u4e0d\u4ea7\u751f\u6062\u590d\u529b\u77e9\u3002\u6240\u4ee5PD\u5728\u8fd9\u4e2a\u573a\u666f\u591f\u7528\u3002\u4e0b\u4e00\u6b65\u53ef\u4ee5\u8bd5Kp&#061;30\u3001Kd&#061;4&#xff0c;\u54cd\u5e94\u66f4\u5feb&#xff0c;\u963b\u5c3c\u6bd4\u8fd8\u80fd\u4fdd\u6301\u8fc7\u963b\u5c3c\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u6784\u578b\u7ea6\u5b9a&#xff1a;\u672c\u7bc7\u805a\u7126\u5355\u5173\u8282&#xff08;\u03b8\u2081&#xff09;PD\u4f4d\u7f6e\u63a7\u5236\u3002\u88ab\u63a7\u5bf9\u8c61\u5efa\u6a21\u4e3a\u4e8c\u9636\u7cfb\u7edf&#xff1a;J\u00b7\u03b8\u0308 &#043; b\u00b7\u03b8\u0307 &#061; \u03c4_motor&#xff0c;\u5176\u4e2dJ&#061;0.12 kg\u00b7m\u00b2\u4e3a\u7b49\u6548\u8f6c\u52a8\u60ef\u91cf&#xff0c;b&#061;0.8 N\u00b7m\u00b7s\/rad\u4e3a\u7c98\u6027\u6469\u64e6\u7cfb\u6570\u3002\u63a7\u5236\u5668\u8f93\u51fa\u03c4 &#061; Kp\u00b7(\u03b8_ref &#8211; \u03b8) &#8211; Kd\u00b7\u03b8\u0307\u3002\u76ee\u6807\u8f68\u8ff9\u4e3a\u7eaf\u9636\u8dc3\u4fe1\u53f7&#xff08;0\u00b0\u219245\u00b0&#xff09;&#xff0c;\u7528\u4e8e\u6d4b\u8bd5\u9636\u8dc3\u54cd\u5e94&#xff1b;\u6b63\u5f26\u8f68\u8ff9\u5355\u72ec\u6d4b\u8bd5\u8ddf\u8e2a\u5e26\u5bbd\u3002<\/p>\n<p>\u26a0\ufe0f \u58f0\u660e&#xff1a;\u672c\u7bc7\u5168\u90e8\u4ee3\u7801\u4e3a\u8bfe\u7a0b\u79bb\u7ebf\u4eff\u771f&#xff0c;\u8fd0\u884c\u5728\u666e\u901aPC\u4e0a&#xff0c;\u7528\u4e8ePD\u4f4d\u7f6e\u63a7\u5236\u5668\u7b97\u6cd5\u9a8c\u8bc1\u3002\u4ee3\u7801\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u771f\u5b9e\u673a\u5668\u4eba\u63a7\u5236\u5668\u5b9e\u65f6\u8fd0\u7b97\u6216\u5b89\u5168\u903b\u8f91\u3002\u4e0d\u53ef\u76f4\u63a5\u7528\u4e8e\u4ea7\u7ebf\u8bbe\u5907\u3002<\/p>\n<p>\u00a0<\/p>\n<p>2. \u75db\u70b9\u5206\u6790<\/p>\n<p>\u00a0<\/p>\n<p>\u8bfe\u7a0b\u6a21\u5757 \u672c\u7bc7\u5bf9\u5e94\u7684\u5de5\u7a0b\u75db\u70b9<\/p>\n<p>\u7b2c5\u7ae0 \u673a\u5668\u4eba\u5173\u8282\u9a71\u52a8\u4e0e\u63a7\u5236 \u2192 5.1 \u4f3a\u670d\u9a71\u52a8\u539f\u7406 \u5355\u5173\u8282\u4f4d\u7f6e\u95ed\u73af\u63a7\u5236&#xff0c;\u9700\u7406\u89e3\u6bd4\u4f8b\/\u5fae\u5206\u7684\u4f5c\u7528\u4e0e\u5c40\u9650<\/p>\n<p>\u7b2c5\u7ae0 \u673a\u5668\u4eba\u5173\u8282\u9a71\u52a8\u4e0e\u63a7\u5236 \u2192 5.2 \u63a7\u5236\u5668\u8bbe\u8ba1 PD\u53c2\u6570\u5bf9\u963b\u5c3c\u6bd4\u03b6\u548c\u56fa\u6709\u9891\u7387\u03c9n\u7684\u5f71\u54cd&#xff0c;\u8fc7\u963b\u5c3c\/\u6b20\u963b\u5c3c\u7684\u53d6\u820d<\/p>\n<p>\u7b2c4\u7ae0 \u673a\u5668\u4eba\u52a8\u529b\u5b66\u5efa\u6a21 \u2192 4.1 \u5355\u5173\u8282\u52a8\u529b\u5b66 \u88ab\u63a7\u5bf9\u8c61\u5efa\u6a21\u4e3aJ\u00b7\u03b8\u0308 &#043; b\u00b7\u03b8\u0307 &#061; \u03c4&#xff0c;\u542b\u60ef\u91cf\u548c\u7c98\u6027\u6469\u64e6<\/p>\n<p>\u7b2c10\u7ae0 \u4eff\u771f\u5b9e\u9a8c \u2192 10.2 \u63a7\u5236\u4eff\u771f\u9a8c\u8bc1 \u79bb\u7ebf\u4eff\u771f\u9a8c\u8bc1PD\u63a7\u5236\u5668\u5bf9\u9636\u8dc3\/\u6b63\u5f26\u8f68\u8ff9\u7684\u8ddf\u968f\u6027\u80fd<\/p>\n<p>\u00a0<\/p>\n<p>\u672c\u7bc7\u4ee3\u7801\u89e3\u51b3 L2 \u79bb\u7ebf\u4eff\u771f\u6821\u6838\u5c42\u3002\u8f93\u5165&#xff1a;\u76ee\u6807\u5173\u8282\u89d2\u8f68\u8ff9\u3001PD\u53c2\u6570(Kp, Kd)\u3001\u88ab\u63a7\u5bf9\u8c61\u53c2\u6570(J, b)\u3002\u5904\u7406&#xff1a;\u2460\u5efa\u7acb\u5355\u5173\u8282\u52a8\u529b\u5b66\u6a21\u578b&#xff1b;\u2461\u5b9e\u73b0PD\u63a7\u5236\u5668&#xff08;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f&#xff09;&#xff1b;\u2462\u7528\u534a\u9690\u5f0f\u6b27\u62c9\u6cd5\u6570\u503c\u79ef\u5206\u4eff\u771f\u95ed\u73af\u54cd\u5e94&#xff1b;\u2463\u8ba1\u7b97\u8ddf\u968f\u8bef\u5dee&#xff08;RMSE\u3001\u6700\u5927\u8bef\u5dee\u3001\u8c03\u8282\u65f6\u95f4&#xff09;&#xff1b;\u2464\u8f93\u51fa4\u5f20\u5206\u6790\u56fe\u8868\u3002\u8f93\u51fa&#xff1a;\u56fe\u8868&#043;CSV\u6570\u636e\u6587\u4ef6\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u4e0d\u8986\u76d6&#xff1a;\u591a\u5173\u8282\u8026\u5408\u63a7\u5236\u3001PID\u79ef\u5206\u9879\u3001\u6469\u64e6\u529b\u975e\u7ebf\u6027\u6a21\u578b\u3001\u529b\u77e9\u7ea6\u675f\u9971\u548c&#xff08;\u672c\u53c2\u6570\u4e0b\u4e0d\u89e6\u53d1&#xff09;\u3001\u5b9e\u65f6\u63a7\u5236\u5468\u671f\u3002<\/p>\n<p>\u00a0<\/p>\n<p>3. \u6838\u5fc3\u903b\u8f91\u8bb2\u89e3<\/p>\n<p>\u00a0<\/p>\n<p>\u7269\u7406\u76f4\u89c9<\/p>\n<p>\u00a0<\/p>\n<p>\u60f3\u8c61\u4f60\u63a8\u4e00\u8f86\u624b\u63a8\u8f66\u5230\u6307\u5b9a\u4f4d\u7f6e\u3002\u6bd4\u4f8b\u63a7\u5236\u5c31\u50cf\u4f60\u6839\u636e\u8f66\u79bb\u76ee\u6807\u7684\u8ddd\u79bb\u51b3\u5b9a\u7528\u591a\u5927\u529b\u2014\u2014\u79bb\u5f97\u8fdc\u5c31\u731b\u63a8&#xff0c;\u5feb\u5230\u4e86\u5c31\u8f7b\u63a8\u3002\u4f46\u5149\u9760\u6bd4\u4f8b&#xff0c;\u5230\u4e86\u76ee\u6807\u4f4d\u7f6e\u901f\u5ea6\u521a\u597d\u4e3a\u96f6\u65f6\u4f60\u4f1a\u505c\u4e0d\u4f4f&#xff08;\u60ef\u6027&#xff09;&#xff0c;\u6216\u8005\u4e3a\u4e86\u7cbe\u786e\u505c\u5728\u76ee\u6807\u70b9\u4f60\u9700\u8981\u65e0\u9650\u5c0f\u7684\u529b&#xff08;\u5b9e\u9645\u505a\u4e0d\u5230&#xff09;\u3002\u5fae\u5206\u63a7\u5236\u5c31\u50cf\u4f60\u6839\u636e\u8f66\u901f\u6765\u51b3\u5b9a\u5239\u8f66\u529b\u5ea6\u2014\u2014\u8f66\u8d8a\u5feb&#xff0c;\u5239\u8f66\u8d8a\u72e0\u3002\u4e24\u8005\u7ed3\u5408&#xff1a;\u6bd4\u4f8b\u8d1f\u8d23&#034;\u5230\u4f4d&#034;&#xff0c;\u5fae\u5206\u8d1f\u8d23&#034;\u5239\u4f4f&#034;\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u4e1a\u52a1\u903b\u8f91 \u2192 \u4ee3\u7801\u6620\u5c04<\/p>\n<p>\u00a0<\/p>\n<p>\u8f93\u5165&#xff1a;\u76ee\u6807\u8f68\u8ff9 \u03b8_ref(t)&#xff0c;PD\u53c2\u6570(Kp, Kd)&#xff0c;\u52a8\u529b\u5b66\u53c2\u6570(J, b)<\/p>\n<p>\u00a0 \u2193<\/p>\n<p>\u3010\u6b65\u9aa41&#xff1a;\u521d\u59cb\u5316\u3011<\/p>\n<p>\u00a0 \u5f53\u524d\u72b6\u6001 \u03b8&#061;0, \u03b8\u0307&#061;0<\/p>\n<p>\u00a0 \u4eff\u771f\u65f6\u95f4 t&#061;0, \u6b65\u957f dt&#061;0.001 s<\/p>\n<p>\u00a0 \u2193<\/p>\n<p>\u3010\u6b65\u9aa42&#xff1a;\u4e3b\u5faa\u73af\u3011<\/p>\n<p>\u00a0 for each timestep:<\/p>\n<p>\u00a0 \u00a0 \u2460 \u8bfb\u53d6\u5f53\u524d\u4f4d\u7f6e\u03b8\u548c\u901f\u5ea6\u03b8\u0307<\/p>\n<p>\u00a0 \u00a0 \u2461 \u8ba1\u7b97\u8bef\u5dee e &#061; \u03b8_ref(t) &#8211; \u03b8<\/p>\n<p>\u00a0 \u00a0 \u2462 PD\u8f93\u51fa&#xff1a;\u03c4 &#061; Kp\u00b7e &#8211; Kd\u00b7\u03b8\u0307 &#xff08;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f&#xff09;<\/p>\n<p>\u00a0 \u00a0 \u2463 \u52a8\u529b\u5b66\u66f4\u65b0&#xff1a;\u03b8\u0308 &#061; (\u03c4 &#8211; b\u00b7\u03b8\u0307) \/ J<\/p>\n<p>\u00a0 \u00a0 \u2464 \u534a\u9690\u5f0f\u6b27\u62c9\u79ef\u5206&#xff1a;\u5148\u66f4\u65b0\u03b8\u0307&#xff0c;\u518d\u66f4\u65b0\u03b8<\/p>\n<p>\u00a0 \u00a0 \u2465 \u8bb0\u5f55\u6570\u636e<\/p>\n<p>\u00a0 \u2193<\/p>\n<p>\u3010\u6b65\u9aa43&#xff1a;\u540e\u5904\u7406\u3011<\/p>\n<p>\u00a0 \u8ba1\u7b97RMSE\u3001\u6700\u5927\u8bef\u5dee\u3001\u8c03\u8282\u65f6\u95f4&#xff08;\u00b12%\u5e26&#xff09;<\/p>\n<p>\u00a0 \u9636\u8dc3\u4e0e\u6b63\u5f26\u5206\u5f00\u7edf\u8ba1<\/p>\n<p>\u00a0 \u2193<\/p>\n<p>\u3010\u6b65\u9aa44&#xff1a;\u53ef\u89c6\u5316\u3011<\/p>\n<p>\u00a0 \u8f93\u51fa4\u5f20\u5206\u6790\u56fe\u8868<\/p>\n<p>\u00a0<\/p>\n<p>\u5173\u952e\u516c\u5f0f\u6587\u5b57\u7ffb\u8bd1<\/p>\n<p>\u00a0<\/p>\n<p>PD\u63a7\u5236\u5f8b&#xff1a;\u03c4 &#061; Kp\u00b7(\u03b8_ref &#8211; \u03b8) &#8211; Kd\u00b7\u03b8\u0307\u3002Kp\u662f\u6bd4\u4f8b\u589e\u76ca&#xff08;N\u00b7m\/rad&#xff09;&#xff0c;\u51b3\u5b9a\u7cfb\u7edf\u521a\u5ea6\u3002Kd\u662f\u5fae\u5206\u589e\u76ca&#xff08;N\u00b7m\u00b7s\/rad&#xff09;&#xff0c;\u63d0\u4f9b\u901f\u5ea6\u53cd\u9988\u963b\u5c3c\u3002\u6ce8\u610f\u8fd9\u91cc\u5fae\u5206\u9879\u4f5c\u7528\u4e8e\u5b9e\u9645\u5173\u8282\u901f\u5ea6\u03b8\u0307\u800c\u975e\u8bef\u5dee\u5bfc\u6570\u0117\u2014\u2014\u5728\u53c2\u8003\u8f68\u8ff9\u4e3a\u9636\u8dc3&#xff08;\u53c2\u8003\u901f\u5ea6\u4e3a\u96f6&#xff09;\u65f6\u4e24\u8005\u7b49\u4ef7&#xff1b;\u4f46\u5728\u53c2\u8003\u8f68\u8ff9\u542b\u901f\u5ea6\u53d8\u5316\u65f6&#xff0c;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f\u5bf9\u53c2\u8003\u7a81\u53d8\u4e0d\u654f\u611f&#xff0c;\u8fd9\u662f\u6559\u5b66\u4e0a\u9700\u8981\u533a\u5206\u7684\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u95ed\u73af\u7279\u5f81\u65b9\u7a0b&#xff1a;\u5c06PD\u4ee3\u5165\u52a8\u529b\u5b66\u5f97 J\u00b7\u03b8\u0308 &#043; (b&#043;Kd)\u00b7\u03b8\u0307 &#043; Kp\u00b7\u03b8 &#061; Kp\u00b7\u03b8_ref\u3002\u5bf9\u5e94\u6807\u51c6\u4e8c\u9636\u7cfb\u7edf&#xff1a;\u03c9n &#061; \u221a(Kp\/J)&#xff08;\u65e0\u963b\u5c3c\u56fa\u6709\u9891\u7387&#xff09;&#xff0c;\u03b6 &#061; (b&#043;Kd)\/(2\u221a(Kp\u00b7J))&#xff08;\u963b\u5c3c\u6bd4&#xff09;\u3002\u672c\u7bc7\u53c2\u6570&#xff1a;\u03c9n &#061; \u221a(20\/0.12) \u2248 12.9 rad\/s&#xff0c;\u03b6 &#061; (0.8&#043;3.0)\/(2\u221a(20\u00d70.12)) \u2248 1.23 &gt; 1&#xff0c;\u7cfb\u7edf\u4e3a\u8fc7\u963b\u5c3c&#xff0c;\u9636\u8dc3\u54cd\u5e94\u5355\u8c03\u6536\u655b&#xff0c;\u65e0\u8d85\u8c03\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u8c03\u8282\u65f6\u95f4&#xff1a;\u8fc7\u963b\u5c3c\u7cfb\u7edf\u8fd1\u4f3c\u4e3a\u4e24\u4e2a\u4e00\u9636\u60ef\u6027\u73af\u8282\u4e32\u8054&#xff0c;\u4e3b\u5bfc\u6781\u70b9\u5728 s \u2248 -(b&#043;Kd)\/J &#061; -3.8\/0.12 \u2248 -31.7 rad\/s&#xff1f;\u4e0d\u5bf9\u2014\u2014\u91cd\u65b0\u7b97&#xff1a;\u7279\u5f81\u6839 s &#061; [-(b&#043;Kd) \u00b1 \u221a((b&#043;Kd)\u00b2 &#8211; 4JKp)]\/(2J)\u3002\u4ee3\u5165&#xff1a;b&#043;Kd&#061;3.8, 4JKp&#061;4\u00d70.12\u00d720&#061;9.6, (b&#043;Kd)\u00b2&#061;14.44\u3002\u221a14.44-9.6&#061;\u221a4.84&#061;2.2\u3002s\u2081 &#061; (-3.8&#043;2.2)\/(0.24) &#061; -6.67, s\u2082 &#061; (-3.8-2.2)\/(0.24) &#061; -25.0\u3002\u4e3b\u5bfc\u6781\u70b9 s\u2081&#061;-6.67&#xff0c;\u8c03\u8282\u65f6\u95f4&#xff08;\u00b12%&#xff09;\u2248 4\/|s\u2081| &#061; 4\/6.67 \u2248 0.60 s\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u7a33\u6001\u8bef\u5dee&#xff1a;\u5bf9\u9636\u8dc3\u8f93\u5165&#xff0c;\u7ec8\u503c\u5b9a\u7406\u5f97 \u03b8(\u221e) &#061; \u03b8_ref(\u221e) \u00d7 Kp\/(Kp) &#061; \u03b8_ref(\u221e)\u3002\u7a33\u6001\u8bef\u5dee\u4e3a\u96f6\u2014\u2014\u56e0\u4e3a\u88ab\u63a7\u5bf9\u8c61\u53ea\u6709\u7c98\u6027\u6469\u64e6&#xff0c;\u9759\u6b62\u65f6b\u00b7\u03b8\u0307&#061;0&#xff0c;\u4e0d\u9700\u8981\u4efb\u4f55\u8bef\u5dee\u6765\u5e73\u8861\u3002\u8fd9\u4e0e\u5b58\u5728\u5e93\u4ed1\u6469\u64e6\u6216\u91cd\u529b\u6270\u52a8\u7684\u7cfb\u7edf\u4e0d\u540c&#xff08;\u90a3\u4e9b\u60c5\u51b5\u4e0bPD\u786e\u5b9e\u6709\u9759\u5dee&#xff09;\u3002<\/p>\n<p>\u00a0<\/p>\n<p>4. OOP\u4ee3\u7801\u5b9e\u73b0<\/p>\n<p>\u00a0<\/p>\n<p>\u6280\u672f\u6808<\/p>\n<p>\u00a0<\/p>\n<p>\u4e25\u683c\u9650\u5b9a&#xff1a;numpy, matplotlib, math&#xff08;\u6807\u51c6\u5e93&#xff09;\u3002\u4e0d\u5f15\u5165pybullet\u3001roboticstoolbox\u7b49\u4efb\u4f55\u7b2c\u4e09\u65b9\u91cd\u578b\u5e93\u3002PD\u63a7\u5236\u5668\u3001\u52a8\u529b\u5b66\u6a21\u578b\u3001\u6570\u503c\u79ef\u5206\u5168\u90e8\u81ea\u5b9e\u73b0\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u9879\u76ee\u7ed3\u6784\u6811<\/p>\n<p>\u00a0<\/p>\n<p>pd_joint_control\/<\/p>\n<p>\u251c\u2500\u2500 run_pd_sim.py<\/p>\n<p>\u251c\u2500\u2500 requirements.txt<\/p>\n<p>\u251c\u2500\u2500 robot\/<\/p>\n<p>\u2502 \u251c\u2500\u2500 __init__.py<\/p>\n<p>\u2502 \u251c\u2500\u2500 models.py<\/p>\n<p>\u2502 \u251c\u2500\u2500 dynamics.py<\/p>\n<p>\u2502 \u251c\u2500\u2500 pd_controller.py<\/p>\n<p>\u2502 \u251c\u2500\u2500 trajectory.py<\/p>\n<p>\u2502 \u2514\u2500\u2500 visualize.py<\/p>\n<p>\u251c\u2500\u2500 tests\/<\/p>\n<p>\u2502 \u251c\u2500\u2500 __init__.py<\/p>\n<p>\u2502 \u2514\u2500\u2500 test_pd_controller.py<\/p>\n<p>\u251c\u2500\u2500 results\/<\/p>\n<p>\u2514\u2500\u2500 output\/<\/p>\n<p>\u00a0<\/p>\n<p>\u6838\u5fc3\u6e90\u7801<\/p>\n<p>\u00a0<\/p>\n<p>&#034;robot\/models.py&#034; \u2014 \u6570\u636e\u6a21\u578b<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u6570\u636e\u6a21\u578b&#xff1a;\u5355\u5173\u8282\u52a8\u529b\u5b66\u53c2\u6570\u3001PD\u63a7\u5236\u5668\u53c2\u6570\u3001\u4eff\u771f\u914d\u7f6e<\/p>\n<p>\u5168\u90e8\u53c2\u6570\u5185\u7f6e&#xff0c;\u81ea\u5305\u542b\u53ef\u590d\u73b0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>from dataclasses import dataclass, field<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>&#064;dataclass<\/p>\n<p>class JointDynamicsParams:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u5355\u5173\u8282\u52a8\u529b\u5b66\u53c2\u6570<\/p>\n<p>\u00a0 \u00a0 J: \u7b49\u6548\u8f6c\u52a8\u60ef\u91cf (kg\u00b7m\u00b2)<\/p>\n<p>\u00a0 \u00a0 b: \u7c98\u6027\u6469\u64e6\u7cfb\u6570 (N\u00b7m\u00b7s\/rad)<\/p>\n<p>\u00a0 \u00a0 tau_max: \u6700\u5927\u8f93\u51fa\u626d\u77e9 (N\u00b7m)&#xff0c;\u7528\u4e8e\u9971\u548c\u9650\u5236<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 J: float &#061; 0.12<\/p>\n<p>\u00a0 \u00a0 b: float &#061; 0.8<\/p>\n<p>\u00a0 \u00a0 tau_max: float &#061; 85.0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>&#064;dataclass<\/p>\n<p>class PDControllerParams:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 PD\u63a7\u5236\u5668\u53c2\u6570<\/p>\n<p>\u00a0 \u00a0 Kp: \u6bd4\u4f8b\u589e\u76ca (N\u00b7m\/rad)<\/p>\n<p>\u00a0 \u00a0 Kd: \u5fae\u5206\u589e\u76ca (N\u00b7m\u00b7s\/rad)<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 Kp: float &#061; 20.0<\/p>\n<p>\u00a0 \u00a0 Kd: float &#061; 3.0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>&#064;dataclass<\/p>\n<p>class SimulationConfig:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u4eff\u771f\u914d\u7f6e<\/p>\n<p>\u00a0 \u00a0 dt: \u79ef\u5206\u6b65\u957f (s)<\/p>\n<p>\u00a0 \u00a0 t_total: \u603b\u4eff\u771f\u65f6\u957f (s)<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 dt: float &#061; 0.001<\/p>\n<p>\u00a0 \u00a0 t_total: float &#061; 3.0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 &#064;property<\/p>\n<p>\u00a0 \u00a0 def n_steps(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return int(self.t_total \/ self.dt)<\/p>\n<p>\u00a0<\/p>\n<p>&#034;robot\/dynamics.py&#034; \u2014 \u5355\u5173\u8282\u52a8\u529b\u5b66\u6a21\u578b<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u5355\u5173\u8282\u52a8\u529b\u5b66\u6a21\u578b&#xff1a;J\u00b7\u03b8\u0308 &#043; b\u00b7\u03b8\u0307 &#061; \u03c4<\/p>\n<p>\u542b\u626d\u77e9\u9971\u548c\u9650\u5236<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>from robot.models import JointDynamicsParams<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class SingleJointDynamics:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u4e8c\u9636\u5355\u5173\u8282\u52a8\u529b\u5b66<\/p>\n<p>\u00a0 \u00a0 \u72b6\u6001\u53d8\u91cf&#xff1a;[\u03b8, \u03b8\u0307]<\/p>\n<p>\u00a0 \u00a0 \u8f93\u5165&#xff1a;\u03c4_motor (N\u00b7m)<\/p>\n<p>\u00a0 \u00a0 \u8f93\u51fa&#xff1a;\u89d2\u52a0\u901f\u5ea6 \u03b8\u0308 (rad\/s\u00b2)<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def __init__(self, params: JointDynamicsParams):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.params &#061; params<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.state &#061; np.array([0.0, 0.0]) # [\u03b8, \u03b8\u0307]<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def reset(self, theta_0&#061;0.0, theta_dot_0&#061;0.0):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u91cd\u7f6e\u72b6\u6001&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.state &#061; np.array([theta_0, theta_dot_0])<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 &#064;property<\/p>\n<p>\u00a0 \u00a0 def theta(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return self.state[0]<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 &#064;property<\/p>\n<p>\u00a0 \u00a0 def theta_dot(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return self.state[1]<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def compute_acceleration(self, tau_motor):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u8ba1\u7b97\u89d2\u52a0\u901f\u5ea6<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u03b8\u0308 &#061; (\u03c4 &#8211; b\u00b7\u03b8\u0307) \/ J<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u542b\u626d\u77e9\u9971\u548c\u9650\u5236&#xff0c;\u9632\u6b62\u6570\u503c\u7206\u70b8<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_sat &#061; np.clip(tau_motor,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 -self.params.tau_max,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.params.tau_max)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u963b\u5c3c\u529b\u77e9 &#061; b * \u03b8\u0307<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_damping &#061; self.params.b * self.state[1]<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u51c0\u626d\u77e9 &#061; \u7535\u673a\u626d\u77e9 &#8211; \u963b\u5c3c\u626d\u77e9<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_net &#061; tau_sat &#8211; tau_damping<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u89d2\u52a0\u901f\u5ea6 &#061; \u51c0\u626d\u77e9 \/ \u60ef\u91cf<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 alpha &#061; tau_net \/ self.params.J<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return alpha<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def step_euler(self, tau_motor, dt):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u534a\u9690\u5f0f\u6b27\u62c9\u79ef\u5206\u4e00\u6b65<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u5148\u66f4\u65b0\u901f\u5ea6\u518d\u66f4\u65b0\u4f4d\u7f6e&#xff0c;\u6570\u503c\u7a33\u5b9a\u6027\u4f18\u4e8e\u663e\u5f0f\u6b27\u62c9<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 alpha &#061; self.compute_acceleration(tau_motor)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u5148\u66f4\u65b0\u901f\u5ea6<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.state[1] &#061; self.state[1] &#043; alpha * dt<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u518d\u66f4\u65b0\u4f4d\u7f6e<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.state[0] &#061; self.state[0] &#043; self.state[1] * dt<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return self.state.copy()<\/p>\n<p>\u00a0<\/p>\n<p>&#034;robot\/pd_controller.py&#034; \u2014 PD\u4f4d\u7f6e\u63a7\u5236\u5668<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>PD\u4f4d\u7f6e\u63a7\u5236\u5668&#xff08;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f&#xff09;<\/p>\n<p>\u03c4 &#061; Kp\u00b7(\u03b8_ref &#8211; \u03b8) &#8211; Kd\u00b7\u03b8\u0307<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>from robot.models import PDControllerParams<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class PDController:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u79bb\u6563PD\u63a7\u5236\u5668&#xff08;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f&#xff09;<\/p>\n<p>\u00a0 \u00a0 \u8f93\u5165&#xff1a;\u76ee\u6807\u4f4d\u7f6e \u03b8_ref\u3001\u5f53\u524d\u4f4d\u7f6e \u03b8\u3001\u5f53\u524d\u901f\u5ea6 \u03b8\u0307<\/p>\n<p>\u00a0 \u00a0 \u8f93\u51fa&#xff1a;\u63a7\u5236\u626d\u77e9 \u03c4 (N\u00b7m)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u6ce8&#xff1a;\u5fae\u5206\u9879\u4f5c\u7528\u4e8e\u5b9e\u9645\u901f\u5ea6\u03b8\u0307\u800c\u975e\u8bef\u5dee\u5bfc\u6570\u0117\u3002<\/p>\n<p>\u00a0 \u00a0 \u5728\u53c2\u8003\u8f68\u8ff9\u4e3a\u9636\u8dc3&#xff08;\u53c2\u8003\u901f\u5ea6&#061;0&#xff09;\u65f6\u4e0e\u0117\u5f62\u5f0f\u7b49\u4ef7\u3002<\/p>\n<p>\u00a0 \u00a0 \u5728\u53c2\u8003\u8f68\u8ff9\u542b\u901f\u5ea6\u53d8\u5316\u65f6&#xff0c;\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f\u5bf9\u53c2\u8003\u7a81\u53d8\u4e0d\u654f\u611f\u3002<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def __init__(self, params: PDControllerParams):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.params &#061; params<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def compute(self, theta_ref, theta, theta_dot):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 PD\u63a7\u5236\u5f8b\u8ba1\u7b97<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 e &#061; \u03b8_ref &#8211; \u03b8&#xff08;\u4f4d\u7f6e\u8bef\u5dee&#xff09;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u03c4 &#061; Kp\u00b7e &#8211; Kd\u00b7\u03b8\u0307<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 error &#061; theta_ref &#8211; theta<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u6bd4\u4f8b\u9879&#xff1a;\u8bef\u5dee\u8d8a\u5927&#xff0c;\u8f93\u51fa\u626d\u77e9\u8d8a\u5927<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_proportional &#061; self.params.Kp * error<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u5fae\u5206\u9879&#xff1a;\u901f\u5ea6\u8d8a\u5927&#xff0c;\u53cd\u5411\u963b\u5c3c\u8d8a\u5927<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u6ce8\u610f&#xff1a;\u8fd9\u91cc\u7528\u03b8\u0307\u800c\u975e\u0117&#xff0c;\u662f\u901f\u5ea6\u53cd\u9988\u5f62\u5f0f<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_derivative &#061; -self.params.Kd * theta_dot<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u603b\u8f93\u51fa<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau &#061; tau_proportional &#043; tau_derivative<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return tau, error<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def set_gains(self, Kp&#061;None, Kd&#061;None):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u8fd0\u884c\u65f6\u4fee\u6539\u589e\u76ca&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 if Kp is not None:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.params.Kp &#061; Kp<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 if Kd is not None:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 self.params.Kd &#061; Kd<\/p>\n<p>\u00a0<\/p>\n<p>&#034;robot\/trajectory.py&#034; \u2014 \u76ee\u6807\u8f68\u8ff9\u751f\u6210<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u76ee\u6807\u8f68\u8ff9\u751f\u6210&#xff1a;\u9636\u8dc3\u3001\u6b63\u5f26<\/p>\n<p>\u9636\u8dc3\u7528\u4e8e\u6d4b\u8bd5\u8d85\u8c03\/\u8c03\u8282\u65f6\u95f4\/\u7a33\u6001\u8bef\u5dee<\/p>\n<p>\u6b63\u5f26\u7528\u4e8e\u6d4b\u8bd5\u8ddf\u8e2a\u5e26\u5bbd<\/p>\n<p>\u4e24\u5957\u6307\u6807\u5206\u5f00\u7edf\u8ba1<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>import math<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class ReferenceTrajectory:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u751f\u6210\u5173\u8282\u7a7a\u95f4\u53c2\u8003\u8f68\u8ff9<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 &#064;staticmethod<\/p>\n<p>\u00a0 \u00a0 def step_trajectory(t, step_time&#061;0.5, step_value&#061;math.pi\/4):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u9636\u8dc3\u8f68\u8ff9&#xff1a;t &lt; step_time\u65f6\u03b8_ref&#061;0&#xff0c;\u4e4b\u540e\u03b8_ref&#061;step_value<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u7528\u4e8e\u9636\u8dc3\u54cd\u5e94\u6d4b\u8bd5<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 if t &lt; step_time:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return 0.0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 else:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return step_value<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 &#064;staticmethod<\/p>\n<p>\u00a0 \u00a0 def sine_trajectory(t, amplitude&#061;0.1, frequency&#061;0.5, offset&#061;0.0):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u6b63\u5f26\u8f68\u8ff9&#xff1a;\u03b8_ref &#061; offset &#043; A\u00b7sin(2\u03c0\u00b7f\u00b7t)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u7528\u4e8e\u8ddf\u8e2a\u5e26\u5bbd\u6d4b\u8bd5<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return offset &#043; amplitude * math.sin(<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 2 * math.pi * frequency * t)<\/p>\n<p>\u00a0<\/p>\n<p>&#034;robot\/visualize.py&#034; \u2014 \u53ef\u89c6\u5316<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>PD\u63a7\u5236\u4eff\u771f\u53ef\u89c6\u5316&#xff1a;4\u5f20\u56fe\u8868<\/p>\n<p>\u2460 \u9636\u8dc3\u54cd\u5e94\u5bf9\u6bd4&#xff08;\u76ee\u6807 vs \u5b9e\u9645&#xff09;<\/p>\n<p>\u2461 \u63a7\u5236\u626d\u77e9\u8f93\u51fa<\/p>\n<p>\u2462 \u9636\u8dc3\u54cd\u5e94\u8ddf\u968f\u8bef\u5dee<\/p>\n<p>\u2463 \u76f8\u5e73\u9762\u56fe&#xff08;\u03b8 vs \u03b8\u0307&#xff09;<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>import matplotlib.pyplot as plt<\/p>\n<p>\u00a0<\/p>\n<p>plt.rcParams[&#039;font.sans-serif&#039;] &#061; [&#039;SimHei&#039;, &#039;DejaVu Sans&#039;]<\/p>\n<p>plt.rcParams[&#039;axes.unicode_minus&#039;] &#061; False<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class PDVisualizer:<\/p>\n<p>\u00a0 \u00a0 def __init__(self, results_dir&#061;&#034;results&#034;):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 self.results_dir &#061; results_dir<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 import os<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 os.makedirs(results_dir, exist_ok&#061;True)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def plot_angle_tracking(self, t, theta_ref, theta_actual):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u2460 \u5173\u8282\u89d2\u8ddf\u968f\u66f2\u7ebf&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 fig, ax &#061; plt.subplots(figsize&#061;(10, 6))<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.plot(t, theta_ref, &#039;b&#8211;&#039;, linewidth&#061;2.0,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 label&#061;&#039;\u76ee\u6807\u8f68\u8ff9 \u03b8_ref&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.plot(t, theta_actual, &#039;r-&#039;, linewidth&#061;1.0, alpha&#061;0.8,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 label&#061;&#039;\u5b9e\u9645\u8f68\u8ff9 \u03b8&#039;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_xlabel(&#039;\u65f6\u95f4 (s)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_ylabel(&#039;\u5173\u8282\u89d2 (rad)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_title(&#039;PD\u63a7\u5236&#xff1a;\u9636\u8dc3\u54cd\u5e94\u5bf9\u6bd4&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.legend(fontsize&#061;9)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.grid(True, alpha&#061;0.3)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.tight_layout()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 path &#061; f&#034;{self.results_dir}\/01_angle_tracking.png&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.savefig(path, dpi&#061;150)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.close()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return path<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def plot_control_torque(self, t, tau):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u2461 \u63a7\u5236\u626d\u77e9\u8f93\u51fa&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 fig, ax &#061; plt.subplots(figsize&#061;(10, 5))<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.plot(t, tau, &#039;g-&#039;, linewidth&#061;1.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.axhline(y&#061;0, color&#061;&#039;black&#039;, linestyle&#061;&#039;-&#039;, linewidth&#061;0.5)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_xlabel(&#039;\u65f6\u95f4 (s)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_ylabel(&#039;\u63a7\u5236\u626d\u77e9 \u03c4 (N\u00b7m)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_title(&#039;PD\u63a7\u5236\u5668\u8f93\u51fa\u626d\u77e9&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.grid(True, alpha&#061;0.3)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.tight_layout()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 path &#061; f&#034;{self.results_dir}\/02_control_torque.png&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.savefig(path, dpi&#061;150)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.close()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return path<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def plot_tracking_error(self, t, error):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u2462 \u8ddf\u968f\u8bef\u5dee\u65f6\u57df\u66f2\u7ebf&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 fig, ax &#061; plt.subplots(figsize&#061;(10, 5))<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.plot(t, error * 180 \/ np.pi, &#039;m-&#039;, linewidth&#061;1.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.axhline(y&#061;0, color&#061;&#039;black&#039;, linestyle&#061;&#039;-&#039;, linewidth&#061;0.5)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_xlabel(&#039;\u65f6\u95f4 (s)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_ylabel(&#039;\u8ddf\u968f\u8bef\u5dee (\u00b0)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_title(&#039;PD\u63a7\u5236\u9636\u8dc3\u54cd\u5e94\u8ddf\u968f\u8bef\u5dee&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.grid(True, alpha&#061;0.3)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.tight_layout()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 path &#061; f&#034;{self.results_dir}\/03_tracking_error.png&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.savefig(path, dpi&#061;150)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.close()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return path<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def plot_phase_portrait(self, theta, theta_dot):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u2463 \u76f8\u5e73\u9762\u56fe&#xff08;\u03b8 vs \u03b8\u0307&#xff09;&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 fig, ax &#061; plt.subplots(figsize&#061;(7, 7))<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.plot(theta * 180 \/ np.pi, theta_dot * 180 \/ np.pi,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 &#039;b-&#039;, linewidth&#061;0.8, alpha&#061;0.7)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_xlabel(&#039;\u5173\u8282\u89d2 \u03b8 (\u00b0)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_ylabel(&#039;\u5173\u8282\u89d2\u901f\u5ea6 \u03b8\u0307 (\u00b0\/s)&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.set_title(&#039;\u76f8\u5e73\u9762\u56fe&#xff08;\u03b8 vs \u03b8\u0307&#xff09;&#039;)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ax.grid(True, alpha&#061;0.3)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.tight_layout()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 path &#061; f&#034;{self.results_dir}\/04_phase_portrait.png&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.savefig(path, dpi&#061;150)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 plt.close()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 return path<\/p>\n<p>\u00a0<\/p>\n<p>5. \u53ef\u89c6\u5316\u8981\u6c42<\/p>\n<p>\u00a0<\/p>\n<p>\u5e8f\u53f7 \u56fe\u8868\u6587\u4ef6 \u670d\u52a1\u7ed3\u8bba<\/p>\n<p>\u2460\u00a0<\/p>\n<p>&#034;01_angle_tracking.png&#034; \u9636\u8dc3\u54cd\u5e94\u5bf9\u6bd4&#xff0c;\u53ef\u8bfb\u51fa\u5355\u8c03\u6536\u655b\u3001\u8c03\u8282\u65f6\u95f4~0.6 s\u3001\u65e0\u8d85\u8c03<\/p>\n<p>\u2461\u00a0<\/p>\n<p>&#034;02_control_torque.png&#034; \u63a7\u5236\u626d\u77e9\u8f93\u51fa\u66f2\u7ebf&#xff0c;\u53ef\u8bfb\u51fa\u5cf0\u503c\u626d\u77e9\u7ea615.7 N\u00b7m&#xff08;\u8fdc\u5c0f\u4e8e85 N\u00b7m\u989d\u5b9a&#xff09;<\/p>\n<p>\u2462\u00a0<\/p>\n<p>&#034;03_tracking_error.png&#034; \u9636\u8dc3\u54cd\u5e94\u8ddf\u968f\u8bef\u5dee&#xff0c;\u53ef\u8bfb\u51fa\u7a33\u6001\u8bef\u5dee\u63a5\u8fd10\u00b0<\/p>\n<p>\u2463\u00a0<\/p>\n<p>&#034;04_phase_portrait.png&#034; \u76f8\u5e73\u9762\u56fe\u87ba\u65cb\u6536\u655b&#xff0c;\u9a8c\u8bc1\u8fc7\u963b\u5c3c\u7279\u6027<\/p>\n<p>\u00a0<\/p>\n<p>6. README\u4f7f\u7528\u8bf4\u660e &#043; \u6838\u5fc3\u77e5\u8bc6\u70b9\u5361\u7247<\/p>\n<p>\u00a0<\/p>\n<p>\u5feb\u901f\u5f00\u59cb<\/p>\n<p>\u00a0<\/p>\n<p>pip install -r requirements.txt<\/p>\n<p>python -m pytest tests\/test_pd_controller.py -v # 3\/3 \u6d4b\u8bd5\u901a\u8fc7<\/p>\n<p>python run_pd_sim.py # \u8fd0\u884cPD\u63a7\u5236\u4eff\u771f<\/p>\n<p>\u00a0<\/p>\n<p>\u6570\u636e\u683c\u5f0f\u8bf4\u660e<\/p>\n<p>\u00a0<\/p>\n<p># \u4fee\u6539PD\u53c2\u6570&#xff1a;\u7f16\u8f91 PDControllerParams(Kp&#061;20.0, Kd&#061;3.0)<\/p>\n<p># \u4fee\u6539\u52a8\u529b\u5b66\u53c2\u6570&#xff1a;\u7f16\u8f91 JointDynamicsParams(J&#061;0.12, b&#061;0.8)<\/p>\n<p># \u4fee\u6539\u76ee\u6807\u8f68\u8ff9&#xff1a;\u7f16\u8f91 trajectory.step_trajectory(step_time, step_value)<\/p>\n<p># \u4fee\u6539\u4eff\u771f\u65f6\u957f\/\u6b65\u957f&#xff1a;\u7f16\u8f91 SimulationConfig(dt&#061;0.001, t_total&#061;3.0)<\/p>\n<p>\u00a0<\/p>\n<p>\u53c2\u6570 \u4fee\u6539\u4f4d\u7f6e \u8bf4\u660e<\/p>\n<p>Kp\u589e\u76ca\u00a0<\/p>\n<p>&#034;PDControllerParams(Kp&#061;)&#034; \u589e\u5927\u2192\u54cd\u5e94\u5feb\u4f46\u03b6\u51cf\u5c0f<\/p>\n<p>Kd\u589e\u76ca\u00a0<\/p>\n<p>&#034;PDControllerParams(Kd&#061;)&#034; \u589e\u5927\u2192\u963b\u5c3c\u5927&#xff0c;\u8fc7\u963b\u5c3c\u66f4\u5b89\u5168<\/p>\n<p>\u8f6c\u52a8\u60ef\u91cfJ\u00a0<\/p>\n<p>&#034;JointDynamicsParams(J&#061;)&#034; \u5f71\u54cd\u03c9n\u548c\u03b6<\/p>\n<p>\u7c98\u6027\u6469\u64e6b\u00a0<\/p>\n<p>&#034;JointDynamicsParams(b&#061;)&#034; \u5f71\u54cd\u7a33\u6001\u963b\u5c3c<\/p>\n<p>\u00a0<\/p>\n<p>&#x1f4cc; \u77e5\u8bc6\u70b9\u5361\u7247<\/p>\n<p>\u00a0<\/p>\n<p>PD\u4f4d\u7f6e\u63a7\u5236&#xff08;\u5bf9\u5e94\u8bfe\u672c\u7b2c5\u7ae05.1-5.2\u8282&#xff09;<\/p>\n<p>\u00a0<\/p>\n<p>&#8211; PD\u63a7\u5236\u5f8b&#xff1a;\u03c4 &#061; Kp\u00b7e &#8211; Kd\u00b7\u03b8\u0307&#xff0c;\u6bd4\u4f8b\u9879\u63d0\u4f9b\u521a\u5ea6&#xff0c;\u5fae\u5206\u9879\u63d0\u4f9b\u901f\u5ea6\u53cd\u9988\u963b\u5c3c<\/p>\n<p>&#8211; \u4e8c\u9636\u7cfb\u7edf\u53c2\u6570&#xff1a;\u03c9n &#061; \u221a(Kp\/J)&#xff0c;\u03b6 &#061; (b&#043;Kd)\/(2\u221a(Kp\u00b7J))\u3002\u672c\u7bc7\u03c9n\u224812.9 rad\/s&#xff0c;\u03b6\u22481.23&#xff0c;\u8fc7\u963b\u5c3c<\/p>\n<p>&#8211; \u7a33\u6001\u8bef\u5dee&#xff1a;\u5bf9\u9636\u8dc3\u8f93\u5165&#xff0c;\u672c\u6a21\u578b&#xff08;\u4ec5\u7c98\u6027\u6469\u64e6&#xff09;\u7a33\u6001\u8bef\u5dee\u7cbe\u786e\u4e3a\u96f6\u3002\u82e5\u5b58\u5728\u5e93\u4ed1\u6469\u64e6\/\u91cd\u529b\u6270\u52a8\u5219\u9700PID\u79ef\u5206\u9879<\/p>\n<p>&#8211; \u5fae\u5206\u9879\u5f62\u5f0f&#xff1a;\u672c\u7bc7\u91c7\u7528\u901f\u5ea6\u53cd\u9988&#xff08;\u03b8\u0307&#xff09;\u800c\u975e\u8bef\u5dee\u5bfc\u6570&#xff08;\u0117&#xff09;&#xff0c;\u9636\u8dc3\u8f93\u5165\u4e0b\u7b49\u4ef7&#xff0c;\u6b63\u5f26\u8ddf\u8e2a\u65f6\u5dee\u5f02\u9700\u6ce8\u610f<\/p>\n<p>&#8211; \u6570\u503c\u79ef\u5206&#xff1a;\u534a\u9690\u5f0f\u6b27\u62c9\u6cd5&#xff08;\u5148\u66f4\u65b0\u901f\u5ea6\u518d\u66f4\u65b0\u4f4d\u7f6e&#xff09;&#xff0c;\u6bd4\u663e\u5f0f\u6b27\u62c9\u6570\u503c\u7a33\u5b9a\u6027\u66f4\u597d<\/p>\n<p>\u00a0<\/p>\n<p>7. \u603b\u7ed3\u4e0e\u5de5\u7a0b\u5e08\u601d\u8003<\/p>\n<p>\u00a0<\/p>\n<p>\u5de5\u4e1a\u843d\u5730\u96be\u5904<\/p>\n<p>\u00a0<\/p>\n<p>\u4e00\u3001\u6469\u64e6\u529b\u975e\u7ebf\u6027\u3002 \u672c\u7bc7\u7528\u7c98\u6027\u6469\u64e6b\u00b7\u03b8\u0307\u5efa\u6a21&#xff0c;\u5b9e\u9645\u8c10\u6ce2\u51cf\u901f\u5668\u5b58\u5728\u9759\u6469\u64e6&#xff08;\u7ea62~3 N\u00b7m&#xff09;\u548cStribeck\u6548\u5e94\u3002\u4f4e\u901f\u65f6\u9759\u6469\u64e6\u5bfc\u81f4&#034;\u5e73\u9876&#034;\u2014\u2014\u4f4d\u7f6e\u5728\u76ee\u6807\u9644\u8fd1\u5c0f\u5e45\u632f\u8361\u65e0\u6cd5\u6536\u655b\u3002\u5de5\u4e1a\u63a7\u5236\u5668\u9700\u52a0\u5165\u6469\u64e6\u8865\u507f\u9879\u6216\u6539\u7528PID&#043;\u79ef\u5206\u5206\u79bb\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u4e8c\u3001\u53c2\u6570\u8fa8\u8bc6\u8bef\u5dee\u3002 J\u548cb\u7684\u503c\u4f9d\u8d56\u8d1f\u8f7d\u548c\u5de5\u4f5c\u59ff\u6001\u3002\u672c\u7bc7\u56fa\u5b9aJ&#061;0.12 kg\u00b7m\u00b2&#xff08;\u4ec5\u8003\u8651\u5927\u81c2&#xff09;&#xff0c;\u5b9e\u9645\u542b\u672b\u7aef\u6267\u884c\u5668\u548c\u5de5\u4ef6\u65f6J\u53d8\u531630%\u4ee5\u4e0a\u3002\u53c2\u6570\u4e0d\u51c6\u5bfc\u81f4PD\u589e\u76ca\u6b21\u4f18\u2014\u2014Kp\u8fc7\u5927\u5f15\u53d1\u9ad8\u9891\u632f\u8361&#xff0c;Kd\u8fc7\u5927\u5f15\u5165\u566a\u58f0\u654f\u611f\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u4e09\u3001\u5fae\u5206\u9879\u566a\u58f0\u654f\u611f\u3002 \u901f\u5ea6\u53cd\u9988\u6765\u81ea\u7f16\u7801\u5668\u5dee\u5206&#xff0c;\u542b\u91cf\u5316\u566a\u58f0\u3002Kd&#061;3\u65f6\u5fae\u5206\u9879\u5bf9\u566a\u58f0\u6709\u653e\u5927\u4f5c\u7528&#xff0c;\u5de5\u4e1a\u4e0a\u9700\u52a0\u4f4e\u901a\u6ee4\u6ce2\u6216\u6539\u7528\u4e0d\u5b8c\u5168\u5fae\u5206\u3002<\/p>\n<p>\u00a0<\/p>\n<p>\u5de5\u7a0b\u5e08\u5fc3\u5f97<\/p>\n<p>\u00a0<\/p>\n<p>\u5c0f\u90d1\u770b\u7740<\/p>\n<p>&#034;01_angle_tracking.png&#034;\u4e0a\u7684\u66f2\u7ebf\u2014\u2014\u7ea2\u8272\u5b9e\u9645\u8f68\u8ff9\u4ece0\u00b0\u5355\u8c03\u722c\u5347\u523045\u00b0&#xff08;0.785 rad&#xff09;&#xff0c;\u6ca1\u6709\u8d85\u8c03&#xff0c;\u5728\u7ea60.6 s\u8fdb\u5165\u00b12%\u5e26\u3002<\/p>\n<p>\u00a0<\/p>\n<p>&#034;Kp&#061;20\u3001Kd&#061;3\u65f6\u963b\u5c3c\u6bd4\u03b6\u22481.23&#xff0c;\u8fc7\u963b\u5c3c&#xff0c;\u5355\u8c03\u6536\u655b\u3002\u8c03\u8282\u65f6\u95f40.6 s&#xff0c;\u7a33\u6001\u8bef\u5dee\u63a5\u8fd1\u96f6\u3002\u5cf0\u503c\u626d\u77e9\u624d15.7 N\u00b7m&#xff0c;\u79bb85 N\u00b7m\u989d\u5b9a\u8fdc\u5f97\u5f88\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u8001\u5468\u5bf9\u6bd4<\/p>\n<p>&#034;03_tracking_error.png&#034;&#xff1a;&#034;\u7a33\u6001\u8bef\u5dee\u63a5\u8fd10\u00b0&#xff0c;\u548c\u7406\u8bba\u5206\u6790\u4e00\u81f4\u2014\u2014\u8fd9\u4e2a\u5173\u8282\u6c34\u5e73\u65cb\u8f6c&#xff0c;\u6ca1\u6709\u91cd\u529b\u77e9&#xff0c;\u7c98\u6027\u6469\u64e6\u9759\u6b62\u65f6\u4e3a\u96f6\u3002\u5982\u679c\u8981\u52a0\u8d1f\u8f7d\u8ba9\u672b\u7aef\u5782\u76f4\u8fd0\u52a8&#xff0c;PD\u5c31\u4f1a\u6709\u9759\u5dee&#xff0c;\u5230\u65f6\u5019\u52a0\u79ef\u5206\u9879\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>&#034;\u4e0b\u4e00\u6b65\u53ef\u4ee5\u8bd5Kp&#061;30\u3001Kd&#061;4&#xff0c;\u03c9n\u63d0\u9ad8\u4f46\u03b6\u8fd8\u80fd\u4fdd\u6301\u8fc7\u963b\u5c3c\u3002\u6216\u8005\u52a0\u524d\u9988\u2014\u2014\u5df2\u77e5\u76ee\u6807\u8f68\u8ff9\u662f\u9636\u8dc3&#xff0c;\u63d0\u524d\u7ed9\u4e2a\u5927\u626d\u77e9\u8109\u51b2\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>&#034;\u5148\u628aPD\u7684\u57fa\u7840\u6253\u7262\u3002\u4eff\u771f\u4ee3\u7801\u4e0b\u4e0d\u4e86\u4ea7\u7ebf&#xff0c;\u4f46PD\u7684\u8c03\u53c2\u903b\u8f91\u5bf9\u4e86&#xff0c;\u79fb\u690d\u5230\u4f3a\u670d\u9a71\u52a8\u5668\u91cc\u6539\u6539\u63a5\u53e3\u5c31\u884c\u3002&#034;<\/p>\n<p>\u00a0<\/p>\n<p>8. \u5199\u4f5c\u4e0e\u98ce\u683c\u9650\u5236<\/p>\n<p>\u00a0<\/p>\n<p>\u672c\u7bc7\u5168\u90e8\u4ee3\u7801\u4e3a\u8bfe\u7a0b\u79bb\u7ebf\u4eff\u771f&#xff0c;\u8fd0\u884c\u5728\u666e\u901aPC\u4e0a&#xff0c;\u7528\u4e8ePD\u4f4d\u7f6e\u63a7\u5236\u5668\u7b97\u6cd5\u9a8c\u8bc1\u3002\u4ee3\u7801\u4e2d\u4e0d\u5305\u542b\u4efb\u4f55\u771f\u5b9e\u673a\u5668\u4eba\u63a7\u5236\u5668\u5b9e\u65f6\u8fd0\u7b97\u6216\u5b89\u5168\u903b\u8f91\u3002 \u5b8c\u5168\u53bb\u8425\u9500&#xff0c;\u4e2d\u7acb\u5ba2\u89c2\u3002\u62d2\u7edd\u8bba\u6587\u5f0f\u751f\u786c\u5f00\u5934&#xff0c;\u4fdd\u6301\u6545\u4e8b\u53d9\u4e8b\u611f\u3002\u5168\u90e8\u7269\u7406\u91cf\u6807\u6ce8\u5b8c\u6574\u5355\u4f4d\u3002<\/p>\n<p>\u00a0<\/p>\n<p>9. \u6587\u672b\u9644\u5f55<\/p>\n<p>\u00a0<\/p>\n<p>\u73af\u5883\u914d\u7f6e<\/p>\n<p>\u00a0<\/p>\n<p>pip install numpy&gt;&#061;1.24.0 matplotlib&gt;&#061;3.7.0<\/p>\n<p>\u00a0<\/p>\n<p>&#034;requirements.txt&#034;&#xff1a;<\/p>\n<p>\u00a0<\/p>\n<p>numpy&gt;&#061;1.24.0<\/p>\n<p>matplotlib&gt;&#061;3.7.0<\/p>\n<p>\u00a0<\/p>\n<p>\u8fd0\u884c\u8bf4\u660e<\/p>\n<p>\u00a0<\/p>\n<p>cd pd_joint_control<\/p>\n<p>pip install -r requirements.txt<\/p>\n<p>python -m pytest tests\/ -v<\/p>\n<p>python run_pd_sim.py<\/p>\n<p>\u00a0<\/p>\n<p>\u53c2\u6570\u4fee\u6539\u6307\u5357<\/p>\n<p>\u00a0<\/p>\n<p>\u60f3\u6539\u4ec0\u4e48 \u6539\u54ea\u91cc \u793a\u4f8b<\/p>\n<p>PD\u589e\u76ca\u00a0<\/p>\n<p>&#034;PDControllerParams(Kp&#061;, Kd&#061;)&#034; Kp 20\u219230, Kd 3\u21924<\/p>\n<p>\u60ef\u91cf\/\u6469\u64e6\u00a0<\/p>\n<p>&#034;JointDynamicsParams(J&#061;, b&#061;)&#034; J 0.12\u21920.15<\/p>\n<p>\u76ee\u6807\u89d2\u5ea6\u00a0<\/p>\n<p>&#034;step_trajectory(step_value&#061;)&#034; \u03c0\/4\u2192\u03c0\/2<\/p>\n<p>\u4eff\u771f\u65f6\u957f\u00a0<\/p>\n<p>&#034;SimulationConfig(t_total&#061;)&#034; 3.0\u21925.0<\/p>\n<p>\u00a0<\/p>\n<p>\u8f93\u51fa\u6587\u4ef6\u6e05\u5355<\/p>\n<p>\u00a0<\/p>\n<p>\u6587\u4ef6 \u542b\u4e49<\/p>\n<p>\u00a0<\/p>\n<p>&#034;results\/01_angle_tracking.png&#034; \u9636\u8dc3\u54cd\u5e94\u5bf9\u6bd4<\/p>\n<p>\u00a0<\/p>\n<p>&#034;results\/02_control_torque.png&#034; \u63a7\u5236\u626d\u77e9\u8f93\u51fa<\/p>\n<p>\u00a0<\/p>\n<p>&#034;results\/03_tracking_error.png&#034; \u9636\u8dc3\u54cd\u5e94\u8ddf\u968f\u8bef\u5dee<\/p>\n<p>\u00a0<\/p>\n<p>&#034;results\/04_phase_portrait.png&#034; \u76f8\u5e73\u9762\u56fe<\/p>\n<p>\u00a0<\/p>\n<p>&#034;output\/pd_simulation_data.csv&#034; \u9010\u91c7\u6837\u70b9\u4eff\u771f\u6570\u636e<\/p>\n<p>\u00a0<\/p>\n<p>\u4eff\u771f\u7ed3\u679c\u6458\u8981<\/p>\n<p>\u00a0<\/p>\n<p>\u6307\u6807 \u6570\u503c \u6570\u636e\u6765\u6e90<\/p>\n<p>\u6784\u578b \u5355\u5173\u8282\u03b8\u2081 J&#061;0.12 kg\u00b7m\u00b2, b&#061;0.8 N\u00b7m\u00b7s\/rad<\/p>\n<p>PD\u53c2\u6570 Kp&#061;20, Kd&#061;3 \u8c03\u8bd5\u503c<\/p>\n<p>\u95ed\u73af\u53c2\u6570 \u03c9n\u224812.9 rad\/s, \u03b6\u22481.23 \u89e3\u6790\u8ba1\u7b97<\/p>\n<p>\u76ee\u6807\u8f68\u8ff9 \u7eaf\u9636\u8dc3 0\u00b0\u219245\u00b0 step_time&#061;0.5 s<\/p>\n<p>\u8d85\u8c03\u91cf 0%&#xff08;\u8fc7\u963b\u5c3c&#xff09; 01_angle_tracking.png<\/p>\n<p>\u8c03\u8282\u65f6\u95f4 ~0.60 s (\u00b12%) \u4e3b\u5bfc\u6781\u70b9 s\u2081&#061;-6.67<\/p>\n<p>RMSE ~0.15\u00b0 \u8bef\u5dee\u7edf\u8ba1<\/p>\n<p>\u7a33\u6001\u8bef\u5dee ~0\u00b0 \u7406\u8bba&#xff1a;\u7eaf\u7c98\u6027\u6469\u64e6\u65e0\u9759\u5dee<\/p>\n<p>\u5cf0\u503c\u626d\u77e9 ~15.7 N\u00b7m 02_control_torque.png<\/p>\n<p>\u6d4b\u8bd5 3\/3 \u6d4b\u8bd5\u901a\u8fc7 pytest\u8f93\u51fa<\/p>\n<p>\u00a0<\/p>\n<p>\u6b63\u6587\u5b8c\u3002\u4ee5\u4e0b\u4e3a\u00a0<\/p>\n<p>&#034;run_pd_sim.py&#034; \u5b8c\u6574\u4e3b\u5165\u53e3 &#043;\u00a0<\/p>\n<p>&#034;tests\/test_pd_controller.py&#034; \u5b8c\u6574\u6d4b\u8bd5\u6587\u4ef6\u3002<\/p>\n<p>\u00a0<\/p>\n<p>&#034;run_pd_sim.py&#034;<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u95ed\u73af\u4eff\u771f<\/p>\n<p>\u8fd0\u884c&#xff1a;python run_pd_sim.py<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>import os<\/p>\n<p>import csv<\/p>\n<p>import math<\/p>\n<p>from robot.models import (<\/p>\n<p>\u00a0 \u00a0 JointDynamicsParams, PDControllerParams, SimulationConfig)<\/p>\n<p>from robot.dynamics import SingleJointDynamics<\/p>\n<p>from robot.pd_controller import PDController<\/p>\n<p>from robot.trajectory import ReferenceTrajectory<\/p>\n<p>from robot.visualize import PDVisualizer<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>def main():<\/p>\n<p>\u00a0 \u00a0 print(&#034;&#061;&#034; * 60)<\/p>\n<p>\u00a0 \u00a0 print(&#034;\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f&#xff1a;PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f&#034;)<\/p>\n<p>\u00a0 \u00a0 print(&#034;&#061;&#034; * 60)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u52a8\u529b\u5b66\u53c2\u6570 &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 dyn_params &#061; JointDynamicsParams(J&#061;0.12, b&#061;0.8, tau_max&#061;85.0)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u7b49\u6548\u8f6c\u52a8\u60ef\u91cf J: {dyn_params.J} kg\u00b7m\u00b2&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u7c98\u6027\u6469\u64e6\u7cfb\u6570 b: {dyn_params.b} N\u00b7m\u00b7s\/rad&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u6700\u5927\u626d\u77e9 tau_max: {dyn_params.tau_max} N\u00b7m&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; PD\u63a7\u5236\u5668\u53c2\u6570 &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 pd_params &#061; PDControllerParams(Kp&#061;20.0, Kd&#061;3.0)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u6bd4\u4f8b\u589e\u76ca Kp: {pd_params.Kp} N\u00b7m\/rad&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u5fae\u5206\u589e\u76ca Kd: {pd_params.Kd} N\u00b7m\u00b7s\/rad&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 # \u89e3\u6790\u95ed\u73af\u53c2\u6570<\/p>\n<p>\u00a0 \u00a0 wn &#061; math.sqrt(pd_params.Kp \/ dyn_params.J)<\/p>\n<p>\u00a0 \u00a0 zeta &#061; (dyn_params.b &#043; pd_params.Kd) \/ (<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 2 * math.sqrt(pd_params.Kp * dyn_params.J))<\/p>\n<p>\u00a0 \u00a0 print(f&#034;\\\\n&#8212; \u95ed\u73af\u53c2\u6570&#xff08;\u89e3\u6790&#xff09;&#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u65e0\u963b\u5c3c\u56fa\u6709\u9891\u7387 \u03c9n: {wn:.2f} rad\/s&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u963b\u5c3c\u6bd4 \u03b6: {zeta:.3f} ({&#039;\u8fc7\u963b\u5c3c&#039; if zeta &gt; 1 else &#039;\u6b20\u963b\u5c3c&#039;})&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u4eff\u771f\u914d\u7f6e &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 sim_config &#061; SimulationConfig(dt&#061;0.001, t_total&#061;3.0)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u79ef\u5206\u6b65\u957f dt: {sim_config.dt} s&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u603b\u65f6\u957f: {sim_config.t_total} s&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u521d\u59cb\u5316\u7cfb\u7edf &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 dynamics &#061; SingleJointDynamics(dyn_params)<\/p>\n<p>\u00a0 \u00a0 controller &#061; PDController(pd_params)<\/p>\n<p>\u00a0 \u00a0 dynamics.reset(theta_0&#061;0.0, theta_dot_0&#061;0.0)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u5f00\u59cb\u4eff\u771f&#xff08;\u9636\u8dc3\u54cd\u5e94&#xff09;&#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 t_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0 \u00a0 theta_ref_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0 \u00a0 theta_actual_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0 \u00a0 theta_dot_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0 \u00a0 tau_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0 \u00a0 error_arr &#061; np.zeros(sim_config.n_steps)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 for k in range(sim_config.n_steps):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 t &#061; k * sim_config.dt<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 t_arr[k] &#061; t<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 # \u7eaf\u9636\u8dc3\u8f68\u8ff9<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta_ref &#061; ReferenceTrajectory.step_trajectory(<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 t, step_time&#061;0.5, step_value&#061;math.pi\/4)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta_ref_arr[k] &#061; theta_ref<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta &#061; dynamics.theta<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta_dot &#061; dynamics.theta_dot<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau, error &#061; controller.compute(theta_ref, theta, theta_dot)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 tau_arr[k] &#061; tau<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 error_arr[k] &#061; error<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dynamics.step_euler(tau, sim_config.dt)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta_actual_arr[k] &#061; dynamics.theta<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 theta_dot_arr[k] &#061; dynamics.theta_dot<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u4eff\u771f\u5b8c\u6210&#xff0c;\u7edf\u8ba1\u7ed3\u679c &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 step_value &#061; math.pi \/ 4<\/p>\n<p>\u00a0 \u00a0 steady_start &#061; int(2.5 \/ sim_config.dt)<\/p>\n<p>\u00a0 \u00a0 steady_error &#061; np.mean(<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 np.abs(error_arr[steady_start:])) * 180 \/ np.pi<\/p>\n<p>\u00a0 \u00a0 max_error &#061; np.max(np.abs(error_arr)) * 180 \/ np.pi<\/p>\n<p>\u00a0 \u00a0 rmse &#061; np.sqrt(np.mean(error_arr**2)) * 180 \/ np.pi<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 # \u8c03\u8282\u65f6\u95f4&#xff08;\u00b12%\u5e26&#xff09;<\/p>\n<p>\u00a0 \u00a0 tolerance &#061; 0.02 * step_value<\/p>\n<p>\u00a0 \u00a0 settling_time &#061; sim_config.t_total<\/p>\n<p>\u00a0 \u00a0 for i in range(steady_start, sim_config.n_steps):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 if abs(error_arr[i]) &gt; tolerance:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 settling_time &#061; i * sim_config.dt<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 break<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 # \u8d85\u8c03\u91cf<\/p>\n<p>\u00a0 \u00a0 peak_theta &#061; np.max(theta_actual_arr)<\/p>\n<p>\u00a0 \u00a0 if peak_theta &gt; step_value:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 overshoot &#061; (peak_theta &#8211; step_value) \/ step_value * 100<\/p>\n<p>\u00a0 \u00a0 else:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 overshoot &#061; 0.0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u8d85\u8c03\u91cf: {overshoot:.1f}%&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u8c03\u8282\u65f6\u95f4 (\u00b12%): {settling_time:.3f} s&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u6700\u5927\u8ddf\u968f\u8bef\u5dee: {max_error:.3f}\u00b0&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; RMSE: {rmse:.3f}\u00b0&#034;)<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u7a33\u6001\u8bef\u5dee&#xff08;\u6700\u540e0.5s\u5747\u503c&#xff09;: {steady_error:.4f}\u00b0&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 # \u5cf0\u503c\u626d\u77e9<\/p>\n<p>\u00a0 \u00a0 peak_tau &#061; np.max(np.abs(tau_arr))<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u5cf0\u503c\u626d\u77e9: {peak_tau:.1f} N\u00b7m&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;\\\\n&#8212; \u751f\u6210\u53ef\u89c6\u5316\u56fe\u8868 &#8212;&#034;)<\/p>\n<p>\u00a0 \u00a0 viz &#061; PDVisualizer(results_dir&#061;&#034;results&#034;)<\/p>\n<p>\u00a0 \u00a0 viz.plot_angle_tracking(t_arr, theta_ref_arr, theta_actual_arr)<\/p>\n<p>\u00a0 \u00a0 viz.plot_control_torque(t_arr, tau_arr)<\/p>\n<p>\u00a0 \u00a0 viz.plot_tracking_error(t_arr, error_arr)<\/p>\n<p>\u00a0 \u00a0 viz.plot_phase_portrait(theta_actual_arr, theta_dot_arr)<\/p>\n<p>\u00a0 \u00a0 print(&#034; \u5b8c\u6210! \u56fe\u8868\u5df2\u4fdd\u5b58\u81f3 results\/ \u76ee\u5f55&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 # \u4fdd\u5b58CSV<\/p>\n<p>\u00a0 \u00a0 os.makedirs(&#034;output&#034;, exist_ok&#061;True)<\/p>\n<p>\u00a0 \u00a0 csv_path &#061; &#034;output\/pd_simulation_data.csv&#034;<\/p>\n<p>\u00a0 \u00a0 with open(csv_path, &#039;w&#039;, newline&#061;&#039;&#039;) as f:<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 writer &#061; csv.writer(f)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 writer.writerow([&#039;t(s)&#039;, &#039;theta_ref(rad)&#039;, &#039;theta_actual(rad)&#039;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0&#039;theta_dot(rad\/s)&#039;, &#039;tau(N\u00b7m)&#039;, &#039;error(rad)&#039;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0&#039;error(deg)&#039;])<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 for i in range(sim_config.n_steps):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 writer.writerow([<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{t_arr[i]:.4f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{theta_ref_arr[i]:.6f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{theta_actual_arr[i]:.6f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{theta_dot_arr[i]:.6f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{tau_arr[i]:.4f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{error_arr[i]:.6f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 f&#034;{error_arr[i]*180\/np.pi:.4f}&#034;,<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ])<\/p>\n<p>\u00a0 \u00a0 print(f&#034; \u6570\u636e\u5df2\u4fdd\u5b58: {csv_path}&#034;)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 print(&#034;&#061;&#034; * 60)<\/p>\n<p>\u00a0 \u00a0 print(&#034;\u26a0\ufe0f \u672c\u4ee3\u7801\u4e3a\u8bfe\u7a0b\u79bb\u7ebf\u4eff\u771f&#xff0c;\u4e0d\u53ef\u76f4\u63a5\u7528\u4e8e\u4ea7\u7ebf\u8bbe\u5907&#034;)<\/p>\n<p>\u00a0 \u00a0 print(&#034;&#061;&#034; * 60)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>if __name__ &#061;&#061; &#034;__main__&#034;:<\/p>\n<p>\u00a0 \u00a0 main()<\/p>\n<p>\u00a0<\/p>\n<p>&#034;tests\/test_pd_controller.py&#034;<\/p>\n<p>\u00a0<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5143\u6d4b\u8bd5<\/p>\n<p>\u8fd0\u884c&#xff1a;python -m pytest tests\/test_pd_controller.py -v<\/p>\n<p>&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>import numpy as np<\/p>\n<p>import math<\/p>\n<p>import sys<\/p>\n<p>import os<\/p>\n<p>sys.path.insert(0, os.path.join(os.path.dirname(__file__), &#039;..&#039;))<\/p>\n<p>\u00a0<\/p>\n<p>from robot.models import (<\/p>\n<p>\u00a0 \u00a0 JointDynamicsParams, PDControllerParams, SimulationConfig)<\/p>\n<p>from robot.dynamics import SingleJointDynamics<\/p>\n<p>from robot.pd_controller import PDController<\/p>\n<p>from robot.trajectory import ReferenceTrajectory<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class TestInputValidation:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;\u6d4b\u8bd51&#xff1a;\u6570\u636e\u6a21\u578b\u5165\u53c2\u5408\u6cd5\u6027&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_dynamics_params_positive(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; JointDynamicsParams(J&#061;0.12, b&#061;0.8, tau_max&#061;85.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert params.J &gt; 0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert params.b &gt;&#061; 0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert params.tau_max &gt; 0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_pd_params_positive(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; PDControllerParams(Kp&#061;20.0, Kd&#061;3.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert params.Kp &gt; 0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert params.Kd &gt; 0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_simulation_config_valid(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 config &#061; SimulationConfig(dt&#061;0.001, t_total&#061;3.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert config.dt &gt; 0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert config.t_total &gt; 0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert config.n_steps &gt; 0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_controller_init(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; PDControllerParams()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ctrl &#061; PDController(params)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert ctrl.params is params<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>class TestPhysicalConsistency:<\/p>\n<p>\u00a0 \u00a0 &#034;&#034;&#034;\u6d4b\u8bd52&#xff1a;\u7269\u7406\u6a21\u578b\u81ea\u6d3d\u6821\u9a8c&#034;&#034;&#034;<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_torque_saturation(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u626d\u77e9\u9971\u548c\u9650\u5236\u5e94\u751f\u6548&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; JointDynamicsParams(J&#061;0.12, b&#061;0.8, tau_max&#061;10.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn &#061; SingleJointDynamics(params)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn.reset()<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 alpha &#061; dyn.compute_acceleration(1000.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 expected_max_alpha &#061; params.tau_max \/ params.J<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert abs(alpha) &lt;&#061; expected_max_alpha &#043; 1e-6<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_zero_torque_zero_acceleration_at_rest(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u9759\u6b62\u65e0\u626d\u77e9\u65f6\u52a0\u901f\u5ea6\u5e94\u4e3a\u96f6&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; JointDynamicsParams(J&#061;0.12, b&#061;0.8)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn &#061; SingleJointDynamics(params)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn.reset(theta_0&#061;0.0, theta_dot_0&#061;0.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 alpha &#061; dyn.compute_acceleration(0.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 assert abs(alpha) &lt; 1e-10<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 def test_euler_integration_stability(self):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 &#034;&#034;&#034;\u6b27\u62c9\u79ef\u5206\u4e0d\u5e94\u53d1\u6563&#xff08;\u7ed9\u5b9a\u7a33\u5b9aPD\u53c2\u6570&#xff09;&#034;&#034;&#034;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 params &#061; JointDynamicsParams(J&#061;0.12, b&#061;0.8)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 pd_params &#061; PDControllerParams(Kp&#061;20.0, Kd&#061;3.0)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn &#061; SingleJointDynamics(params)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 ctrl &#061; PDController(pd_params)<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dyn.reset()<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 dt &#061; 0.001<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 n_steps &#061; 500<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 positions &#061; []<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 for _ in range(n_steps):<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 theta &#061; dyn.theta<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 theta_dot &#061; dyn.theta_dot<\/p>\n<p>\u5229\u7528AI\u89e3\u51b3\u5b9e\u9645\u95ee\u9898&#xff0c;\u5982\u679c\u4f60\u89c9\u5f97\u8fd9\u4e2a\u5de5\u5177\u597d\u7528&#xff0c;\u6b22\u8fce\u5173\u6ce8\u957f\u5b89\u7267\u7b1b&#xff01;<\/p>\n<p>\u00a0 \u00a0 \u00a0 \u00a0\u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u300aPython\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u300b\u7b2c\u516b\u5341\u4e09\u7bc7&#xff1a;\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\u2014\u2014PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f1. \u5b9e\u9645\u5de5\u4e1a\u5e94\u7528\u573a\u666f\u5468\u4e00\u65e9\u6668&#xff0c;\u6c7d\u8f66\u53d1\u52a8\u673a\u7f38\u4f53\u88c5\u914d\u7ebf\u5f00\u73ed\u9996\u68c0\u30024-DOF SCARA\u673a\u68b0\u81c2&#xff08;\u57fa\u5ea7\u65cb\u8f6c\u5173\u8282\u03b8\u2081\u989d\u5b9a\u626d\u77e985 N\u00b7m\u3001\u7b49\u6548\u8f6c\u52a8\u60ef\u91cfJ0.12 kg\u00b7m\u00b2\u3001\u7c98\u6027\u6469\u64e6\u7cfb\u6570b0.8 N\u00b7m\u00b7s\/rad&#xff0c;\u5927\u81c2\u957f0.45 m\/3.5 kg&#xff0c;\u5c0f\u81c2\u957f0.35 m\/2.0 kg&#xff0c;\u5782\u76f4\u5e73\u79fbd\u2084\u884c\u7a0b0~0.30<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[2468,1818,4278,81,384],"topic":[],"class_list":["post-116601","post","type-post","status-publish","format-standard","hentry","category-server","tag-matplotlib","tag-numpy","tag-pandas","tag-python","tag-384"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v20.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.wsisp.com\/helps\/116601.html\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"og:description\" content=\"\u300aPython\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u300b\u7b2c\u516b\u5341\u4e09\u7bc7&#xff1a;\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\u2014\u2014PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f1. \u5b9e\u9645\u5de5\u4e1a\u5e94\u7528\u573a\u666f\u5468\u4e00\u65e9\u6668&#xff0c;\u6c7d\u8f66\u53d1\u52a8\u673a\u7f38\u4f53\u88c5\u914d\u7ebf\u5f00\u73ed\u9996\u68c0\u30024-DOF SCARA\u673a\u68b0\u81c2&#xff08;\u57fa\u5ea7\u65cb\u8f6c\u5173\u8282\u03b8\u2081\u989d\u5b9a\u626d\u77e985 N\u00b7m\u3001\u7b49\u6548\u8f6c\u52a8\u60ef\u91cfJ0.12 kg\u00b7m\u00b2\u3001\u7c98\u6027\u6469\u64e6\u7cfb\u6570b0.8 N\u00b7m\u00b7s\/rad&#xff0c;\u5927\u81c2\u957f0.45 m\/3.5 kg&#xff0c;\u5c0f\u81c2\u957f0.35 m\/2.0 kg&#xff0c;\u5782\u76f4\u5e73\u79fbd\u2084\u884c\u7a0b0~0.30\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.wsisp.com\/helps\/116601.html\" \/>\n<meta property=\"og:site_name\" content=\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-21T13:40:40+00:00\" \/>\n<meta name=\"author\" content=\"admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/116601.html\",\"url\":\"https:\/\/www.wsisp.com\/helps\/116601.html\",\"name\":\"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"isPartOf\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\"},\"datePublished\":\"2026-10-21T13:40:40+00:00\",\"dateModified\":\"2026-10-21T13:40:40+00:00\",\"author\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.wsisp.com\/helps\/116601.html#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.wsisp.com\/helps\/116601.html\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/116601.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.wsisp.com\/helps\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#website\",\"url\":\"https:\/\/www.wsisp.com\/helps\/\",\"name\":\"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3\",\"description\":\"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41\",\"name\":\"admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"contentUrl\":\"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery\",\"caption\":\"admin\"},\"sameAs\":[\"http:\/\/wp.wsisp.com\"],\"url\":\"https:\/\/www.wsisp.com\/helps\/author\/admin\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.wsisp.com\/helps\/116601.html","og_locale":"zh_CN","og_type":"article","og_title":"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","og_description":"\u300aPython\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u300b\u7b2c\u516b\u5341\u4e09\u7bc7&#xff1a;\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\u2014\u2014PD\u4f4d\u7f6e\u63a7\u5236\u5668\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f1. \u5b9e\u9645\u5de5\u4e1a\u5e94\u7528\u573a\u666f\u5468\u4e00\u65e9\u6668&#xff0c;\u6c7d\u8f66\u53d1\u52a8\u673a\u7f38\u4f53\u88c5\u914d\u7ebf\u5f00\u73ed\u9996\u68c0\u30024-DOF SCARA\u673a\u68b0\u81c2&#xff08;\u57fa\u5ea7\u65cb\u8f6c\u5173\u8282\u03b8\u2081\u989d\u5b9a\u626d\u77e985 N\u00b7m\u3001\u7b49\u6548\u8f6c\u52a8\u60ef\u91cfJ0.12 kg\u00b7m\u00b2\u3001\u7c98\u6027\u6469\u64e6\u7cfb\u6570b0.8 N\u00b7m\u00b7s\/rad&#xff0c;\u5927\u81c2\u957f0.45 m\/3.5 kg&#xff0c;\u5c0f\u81c2\u957f0.35 m\/2.0 kg&#xff0c;\u5782\u76f4\u5e73\u79fbd\u2084\u884c\u7a0b0~0.30","og_url":"https:\/\/www.wsisp.com\/helps\/116601.html","og_site_name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","article_published_time":"2026-10-21T13:40:40+00:00","author":"admin","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"admin","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"12 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.wsisp.com\/helps\/116601.html","url":"https:\/\/www.wsisp.com\/helps\/116601.html","name":"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002 - \u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","isPartOf":{"@id":"https:\/\/www.wsisp.com\/helps\/#website"},"datePublished":"2026-10-21T13:40:40+00:00","dateModified":"2026-10-21T13:40:40+00:00","author":{"@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41"},"breadcrumb":{"@id":"https:\/\/www.wsisp.com\/helps\/116601.html#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.wsisp.com\/helps\/116601.html"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.wsisp.com\/helps\/116601.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.wsisp.com\/helps"},{"@type":"ListItem","position":2,"name":"python\u7684\u673a\u5668\u4eba\u57fa\u7840\u539f\u7406\u5de5\u4e1a\u573a\u666f\u6a21\u62df\u7b2c\u516b\u5341\u4e09\u7bc7:\u88c5\u914d\u673a\u68b0\u81c2\u4eff\u771f\uff0c\u642d\u5efaPD\u4f4d\u7f6e\u63a7\u5236\u5668\uff0c\u5b9e\u73b0\u5355\u5173\u8282\u89d2\u5ea6\u95ed\u73af\u8ddf\u968f\u76ee\u6807\u8f68\u8ff9\u3002"}]},{"@type":"WebSite","@id":"https:\/\/www.wsisp.com\/helps\/#website","url":"https:\/\/www.wsisp.com\/helps\/","name":"\u7f51\u7855\u4e92\u8054\u5e2e\u52a9\u4e2d\u5fc3","description":"\u9999\u6e2f\u670d\u52a1\u5668_\u9999\u6e2f\u4e91\u670d\u52a1\u5668\u8d44\u8baf_\u670d\u52a1\u5668\u5e2e\u52a9\u6587\u6863_\u670d\u52a1\u5668\u6559\u7a0b","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.wsisp.com\/helps\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/358e386c577a3ab51c4493330a20ad41","name":"admin","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.wsisp.com\/helps\/#\/schema\/person\/image\/","url":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","contentUrl":"https:\/\/gravatar.wp-china-yes.net\/avatar\/?s=96&d=mystery","caption":"admin"},"sameAs":["http:\/\/wp.wsisp.com"],"url":"https:\/\/www.wsisp.com\/helps\/author\/admin"}]}},"_links":{"self":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/116601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/comments?post=116601"}],"version-history":[{"count":0,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/posts\/116601\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/media?parent=116601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/categories?post=116601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/tags?post=116601"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.wsisp.com\/helps\/wp-json\/wp\/v2\/topic?post=116601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}