Upload
evan-leonard
View
317
Download
7
Embed Size (px)
Citation preview
Halcompile
Developingrealtime components
for LinuxCNC
Halcompile
Simplifies task of writing realtime component Declaration section followed by a section of
"mostly C" Complex components better coded in "C" "comp" in LinuxCNC 2.6, "halcompile" in
master/2.7 ~70% of components in LinuxCNC are written
with comp
Building and installing a component
Ensure filename (foo.comp) is the same as component declaration (component foo)
LinuxCNC installed as package make sure linuxcnc-dev is installed sudo halcompile --install foo.comp
LinuxCNC built from source . scripts/rip-environment halcompile --install foo.comp
Simplest component
component constant;pin out float out;function _;license "GPL";;;FUNCTION(_) { out = 1.0; }
Generated code (do not read) /* Autogenerated by /home/jepler/local/src/linuxcnc/bin/comp on Mon Oct 13 13:16:11 2014 -- do not edit */#include "rtapi.h"#ifdef RTAPI#include "rtapi_app.h"#endif#include "rtapi_string.h"#include "rtapi_errno.h"#include "hal.h"
static int comp_id;
#ifdef MODULE_INFOMODULE_INFO(linuxcnc, "component:ddt:Compute the derivative of the input function");MODULE_INFO(linuxcnc, "pin:in:float:0:in::None:None");MODULE_INFO(linuxcnc, "pin:out:float:0:out::None:None");MODULE_INFO(linuxcnc, "funct:_:1:");MODULE_INFO(linuxcnc, "license:GPL");MODULE_LICENSE("GPL");#endif // MODULE_INFO
struct __comp_state { struct __comp_state *_next; hal_float_t *in; hal_float_t *out; double old;
};struct __comp_state *__comp_first_inst=0, *__comp_last_inst=0;
static void _(struct __comp_state *__comp_inst, long period);static int __comp_get_data_size(void);#undef TRUE#define TRUE (1)#undef FALSE…
static int export(char *prefix, long extra_arg) { char buf[HAL_NAME_LEN + 1]; int r = 0; int sz = sizeof(struct __comp_state) + __comp_get_data_size(); struct __comp_state *inst = hal_malloc(sz); memset(inst, 0, sz); r = hal_pin_float_newf(HAL_IN, &(inst->in), comp_id, "%s.in", prefix); if(r != 0) return r; r = hal_pin_float_newf(HAL_OUT, &(inst->out), comp_id, "%s.out", prefix); if(r != 0) return r; rtapi_snprintf(buf, sizeof(buf), "%s", prefix); r = hal_export_funct(buf, (void(*)(void *inst, long))_, inst, 1, 0, comp_id); if(r != 0) return r; if(__comp_last_inst) __comp_last_inst->_next = inst; __comp_last_inst = inst; if(!__comp_first_inst) __comp_first_inst = inst; return 0;}static int default_count=1, count=0;char *names[16] = {0,};RTAPI_MP_INT(count, "number of ddt");RTAPI_MP_ARRAY_STRING(names, 16, "names of ddt");int rtapi_app_main(void) { int r = 0; int i; comp_id = hal_init("ddt"); if(comp_id < 0) return comp_id; if(count && names[0]) { rtapi_print_msg(RTAPI_MSG_ERR,"count= and names= are mutually exclusive\n"); return -EINVAL; } if(!count && !names[0]) count = default_count; if(count) { for(i=0; i<count; i++) {…
Pins
pin direction type name; direction: in, out, (rare) io type: signed, unsigned, float, bit (old: s32, u32) name: internal _ becomes -; trailing _ is
removed Examples:
pin in float position-fb; pin out bit position-ok;
Parameters
param direction type name; direction: r, rw type, name: as for pins Examples:
param r float position-scale; param rw float max-error-seen;
Components can have state
component push2toggle"Convert a (debounced) pushbutton to a toggle";
pin in bit in;pin out bit out;variable bool last_in;license "GPL";function _;;;bool new_in = in;if(new_in && !last_in) out = !out;last_in = new_in;
Variables
variable ctype name; ctype: int, double, rtapi_s32, etc
common pitfall: using 'variable float'. value assigned to variable is remembered
from period to period
Self-documentation
Can attach documentation to most items component ddt "Compute discrete derivative of input"; pin out float temperature-cmd "Target temperature (centigrade)"; function _ "Check for fires and update outputs"; Additional documentation sections: description, notes, see_also
View documentation: halcompile --view-doc Install documentation: halcompile --install-doc
then you can view it with 'man 9 ddt' When you try writing documentation, you'll discover that it's
hard.
Other requirements
Code has to be "quick" typical servo period, 1ms typical base period, 25µs
Only certain APIs can be used If you must loop, have a strict limit Look at .time, .tmax hal parameters
these are in CPU cycles on x86, nanoseconds on ARM
Hardware access
It can be done with comp But often hardware drivers are complicated and
better written in pure "C" ISA, PCI UDP Ethernet (for 2.7/master with uspace) A realtime hardware driver might not be needed
Bed temperature: OK if delayed by 1s Stepper motor position: critical to know within 1ms≪
Documentation
Introduction to HAL http://linuxcnc.org/docs/html/hal/intro.html
Syntax of comp itself, with examples: http://linuxcnc.org/docs/html/hal/comp.html I omitted a lot of comp features in this short talk
HAL and RTAPI APIs: http://linuxcnc.org/docs/html/#man3hal
Source code for other components https://github.com/jepler/linuxcnc-mirror/tree/master/src/hal/
components
Let's live code something
cubic bezier interpolation A smooth curve with two end points and two
points giving direction u=1-t
f(t) = u³P₀ + tu²P₁ + t²uP₂ + t³P₃
http://en.wikipedia.org/wiki/Bezier_curve
Code
component cubic; license "GPL";pin in float in;pin out float out;param rw float p#[4];function _;;;double t = in, u=1-t;out = u*u*u*p(0) + u*u*t*p(1) + u*t*t*p(2) + t*t*t*p(3);
Hal harness
loadrt threadsloadrt siggenloadrt cubic
setp cubic.0.p0 0setp cubic.0.p1 .2setp cubic.0.p2 .8setp cubic.0.p3 1setp siggen.0.offset .5setp siggen.0.amplitude .5
net t siggen.0.sawtooth => cubic.0.innet c <= cubic.0.out
addf siggen.0.update thread1addf cubic.0 thread1
start
Scope it$ halrun -I harness.halhalcmd: loadusr halscope