Advertisement
Guest User

Untitled

a guest
Nov 26th, 2014
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.91 KB | None | 0 0
  1. component moveoff "Component to support (Hal-only) offset moves when a program is paused. Three axes are supported (labeled x,y,z).\n\nThe axis offset pin values ([xyz]-offset-in) are continuously applied (respecting limits on value, velocity, and acceleration) when a program is paused if move-enable is True. The offset(s) should be returned to zero value by changing the [xyz]-offset-in pin values or by deasserting move-enable BEFORE the program is resumed. The applied offsets are automatically returned to zero (respecting limits) when the move-enable input is deactivated. The zero value tolerance is specified by the epsilon input pin value.\n\nNOTE: The auto-return move is NOT coordinated, each axis moves at its own rate. If a controlled path is wanted, each axis should be manually returned to zero before deasserting the move-enable pin\n\nNOTE: The offsets-applied output pin is provided to indicate to a GUI that a program may be resumed. If the offset(s) are non-zero when the program is resumed, the offsets are returned to zero (respecting limits) and an error message is issued.\n\nBEWARE: If a running program: 1) is paused and 2) offset(s) are applied and 3) the is-on input is deactivated (for any reason), a servo system will potentially have a large error due to the offset output position as measured by its encoder. When the machine is subsequently turned on again, the servo will likely correct the error with full force. YOU HAVE BEEN WARNED.\n\nNOTE: This Hal-only means of offsetting is typically not known to LinuxCNC nor available in GUI preview displays. No protection is provided for offset moves that exeed soft limits managed by linuxCNC. Since soft limits are not honored, an offset move may move into hard limits (or crash if there is no limit switch). Triggering a hard limit will turn off the machine deasserting is-on -- see BEWARE above.\n\nNOTE: The [xyz]-offset-in values may be set with inifile settings or controlled by a GUI. Fixed values may be appropriate in simple cases where the direction and amount of offset is well-defined but a control method is required to deactivate the move-enble input in order to resume the program properly. It is recommended that GUIs set [xyz]-offset-in values to zero when not in use (e.g., when a program is running and not paused) and provide means for users to set/increment/modify/view the offset values for each axis in use. It may be useful to provide controls to manage the offset limits on value, velocity and acceleration.\n\nNOTE: Use of the names= option for naming is recommended (e.g., loadrt moveoff names=name1,name2,...";
  2.  
  3. /*
  4. Copyright: 2014
  5. Author: Dewey Garrett <dgarrett@panix.com>
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21.  
  22. pin in bit move_enable "Enable offsets when is-paused and is-on";
  23. pin in bit is_on "Connect to halui.machine.is-on";
  24. pin in bit is_paused "Connect to halui.program.is-paused";
  25. pin in float epsilon "When is-paused is deactivated, return to unpaused position within epsilon units. WARNING: Too small value may cause overshoot";
  26. pin out bit offset_applied "True if one or more offsets are applied";
  27.  
  28. pin in float offset-in-#[9 : personality] "Joint offset value (from gui typically for dynamic use, from inifile for fixed value)";
  29. pin in float pos-#[9 : personality] "Joint position (typ: axis.0.motor-pos-cmd)";
  30. pin out float plusoffset-#[9 : personality] "computed joint position (plus offset while paused) (typically connect to pid-command)";
  31. pin in float fb-#[9 : personality] "Joint feedback (typ from encoder and input to pid controller (pid.feedback))";
  32. pin out float fb-minusoffset-#[9 : personality] "computed joint feedback (minus x offset while paused) (typically connected to axis.0.motor-pos-fb";
  33. pin in float offset-vel#[9 : personality] "Joint offset velocity limit";
  34. pin in float offset-accel-#[9 : personality] "joint offset acceleration limit";
  35. pin out float offset-current-#[9 : personality]"joint offset current value";
  36. pin in float offset-min-#[9 : personality] = -1e20 "minimum limit for applied joint offset (typ negative)";
  37. pin in float offset-max-#[9 : personality] = 1e20 "maximum limit for applied x offset (typ positive)";
  38.  
  39. option data old_values_t;
  40.  
  41. option personality;
  42. option extra_setup;
  43. function _ ;
  44.  
  45. license "GPL";
  46. ;;
  47.  
  48. #include "rtapi_math.h"
  49.  
  50. typedef enum {
  51. IDLE,
  52. MOVE_AWAY,
  53. MOVE_BACK,
  54. } the_state;
  55.  
  56. typedef struct {
  57. hal_float_t old_in[9];
  58. hal_float_t old_out[9];
  59. hal_float_t old_v[9];
  60. hal_float_t old_lin[9];
  61. bool was_paused;
  62. bool gave_msg;
  63. } old_values_t;
  64.  
  65. struct lim3_input {
  66. hal_float_t minlimit;
  67. hal_float_t maxlimit;
  68. hal_float_t maxvlimit;
  69. hal_float_t maxalimit;
  70. hal_float_t in;
  71. hal_float_t old_in;
  72. hal_float_t old_out;
  73. hal_float_t old_v;
  74. hal_float_t lin;
  75. };
  76.  
  77. static long theperiod;
  78.  
  79. void reset_old(old_values_t d){
  80. int i;
  81. for (i = 0;i < 9; i++){
  82. d.old_in[i] = 0;
  83. d.old_out[i] = 0;
  84. d.old_v[i] = 0;
  85. d.old_lin[i] = 0;
  86. }
  87. }
  88.  
  89. int offset_removed(old_values_t d, double eps){
  90. int val = TRUE;
  91. int i;
  92. for (i = 0 ; i < 9 ; i++){
  93. if (fabs(d.old_out[i]) > eps) val = FALSE;
  94. }
  95. return val;
  96. }
  97.  
  98. void lim3(struct lim3_input input,double* old_in,double* lout,double* old_v) {
  99. /* from limit3.comp */
  100. hal_float_t dt = theperiod * 0.000000001;
  101. hal_float_t in_v, min_v, max_v, avg_v;
  102. hal_float_t min_out,max_out;
  103. hal_float_t ramp_a, match_time, est_in, est_out;
  104. hal_float_t err, dv, dp;
  105. hal_float_t thelin;
  106.  
  107. /* apply first order limit */
  108. thelin = input.in;
  109. if (thelin < input.minlimit) {
  110. thelin = input.minlimit;
  111. }
  112. if (thelin > input.maxlimit) {
  113. thelin = input.maxlimit;
  114. }
  115. *old_in = thelin;
  116.  
  117. /* calculate input derivative */
  118. in_v = (thelin - input.old_in) / dt;
  119.  
  120. /* determine v and out that can be reached in one period */
  121. min_v = input.old_v - input.maxalimit * dt;
  122. if (min_v < -input.maxvlimit) {
  123. min_v = -input.maxvlimit;
  124. }
  125. max_v = input.old_v + input.maxalimit * dt;
  126. if (max_v > input.maxvlimit) {
  127. max_v = input.maxvlimit;
  128. }
  129.  
  130. min_out = input.old_out + min_v * dt;
  131. max_out = input.old_out + max_v * dt;
  132. if ( ( thelin >= min_out ) && ( thelin <= max_out )
  133. && ( in_v >= min_v ) && ( in_v <= max_v ) ) {
  134. /* we can follow the command without hitting a limit */
  135. *lout = thelin;
  136. input.old_v = ( *lout - input.old_out ) / dt;
  137. } else {
  138. /* can't follow commanded path while obeying limits */
  139. /* determine which way we need to ramp to match v */
  140. if ( in_v > input.old_v ) {
  141. ramp_a = input.maxalimit;
  142. } else {
  143. ramp_a = -input.maxalimit;
  144. }
  145. /* determine how long the match would take */
  146. match_time = ( in_v - input.old_v ) / ramp_a;
  147. /* where we will be at the end of the match */
  148.  
  149. avg_v = ( in_v + input.old_v + ramp_a * dt ) * 0.5;
  150. est_out = input.old_out + avg_v * match_time;
  151. /* calculate the expected command position at that time */
  152. est_in = input.old_in + in_v * match_time;
  153. /* calculate position error at that time */
  154. err = est_out - est_in;
  155. /* calculate change in final position if we ramp in the
  156. opposite direction for one period */
  157. dv = -2.0 * ramp_a * dt;
  158. dp = dv * match_time;
  159. /* decide what to do */
  160. if ( fabs(err + dp*2.0) < fabs(err) ) {
  161. ramp_a = -ramp_a;
  162. }
  163. if ( ramp_a < 0.0 ) {
  164. *lout = min_out;
  165. *old_v = min_v;
  166. } else {
  167. *lout = max_out;
  168. *old_v = max_v;
  169. }
  170. }
  171. return;
  172. }
  173.  
  174. static struct lim3_input input;
  175. static the_state state = IDLE;
  176.  
  177. FUNCTION(_) {
  178. double lout,old_in,old_v;
  179. bool enable = move_enable && is_on && is_paused;
  180. bool move = 0;
  181. int i;
  182.  
  183. theperiod = period;
  184.  
  185. for (i = 0; i < personality ; i++){
  186. input.in = offset_in(i);
  187. switch (state) {
  188. case IDLE:
  189. data.was_paused = 0;
  190. data.gave_msg = 0;
  191. if ( enable ) {
  192. state = MOVE_AWAY;
  193. move = 1;
  194. }
  195. break;
  196. case MOVE_AWAY:
  197. data.was_paused = 0;
  198. if (enable) {
  199. // allow offset movements
  200. move = 1;
  201. break;
  202. }
  203. // one (or more) enablers is gone
  204. state = MOVE_BACK; // to 0,0,0
  205. input.in = 0;
  206.  
  207. //if (!is_paused && is_on && move_enable) {
  208. if (!is_paused && is_on) {
  209. // is_paused removed, move back but limit rate
  210. data.was_paused = 1;
  211. move = 1;
  212. } else if (!is_on) {
  213. // is_on removed, move back, no rate limit
  214. move = 1;
  215. reset_old(data);
  216. } else if (!move_enable) {
  217. // move_enable removed, move back, no rate limit
  218. move = 1;
  219. } else {
  220. //UNEXPECTED
  221. rtapi_print_msg(RTAPI_MSG_ERR,
  222. "moveoff.comp: Unexpected: "
  223. "state=%dis_paused=%d is_on=%d move_enable=%d\n",
  224. state,is_paused,is_on,move_enable);
  225. }
  226. break;
  227. case MOVE_BACK:
  228. move = 1;
  229. input.in = 0;
  230.  
  231. if (!data.gave_msg && !is_paused && ! offset_removed(data, epsilon)) {
  232. // is_paused deactivated
  233. data.gave_msg = 1;
  234. rtapi_print_msg(RTAPI_MSG_ERR,
  235. "moveoff.comp: ERROR:\nProgram resumed before offsets removed\n"
  236. "joint %i: %f\n",
  237. i, data.old_out[i]);
  238. }
  239. data.was_paused = 0;
  240. if (offset_removed(data, epsilon)) {
  241. state = IDLE;
  242. move = 0;
  243. reset_old(data);
  244. }
  245. break;
  246. }
  247.  
  248. if (move) {
  249. input.minlimit = offset_min(i);
  250. input.maxlimit = offset_max(i);
  251. input.maxvlimit = offset_vel(i);
  252. input.maxalimit = offset_accel(i);
  253. input.old_in = data.old_in[i];
  254. input.old_out = data.old_out[i];
  255. input.old_v = data.old_v[i];
  256. input.lin = data.old_lin[i];
  257.  
  258. lim3(input,&old_in,&lout,&old_v);
  259. data.old_in[i] = old_in;
  260. data.old_v[i] = old_v;
  261. plusoffset(i) = pos(i) + lout;
  262. offset_current(i) = lout;
  263. fb_minusoffset(i) = fb(i) - lout;
  264. data.old_out[i] = lout;
  265. data.old_v[i] = old_v;
  266.  
  267. } else {
  268. plusoffset(i) = pos(i);
  269. offset_current(i) = 0;
  270.  
  271. fb_minusoffset(i) = fb(i);
  272.  
  273. }
  274. offset_applied = ! offset_removed(data, epsilon);
  275. }
  276. }
  277.  
  278. EXTRA_SETUP(){
  279. if (personality == 0) personality = 3;
  280. return 0;
  281. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement