- Added alternate units for motor parameters
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Tue, 13 Feb 2018 00:05:53 +0000 (16:05 -0800)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Tue, 13 Feb 2018 00:05:53 +0000 (16:05 -0800)
 - Automatic config file upgrading
 - Fixed planner/jog sync
 - Fixed planner limits config
 - Accel units mm/min² -> m/min²
 - Search and latch velocity mm/min -> m/min
 - Fixed password update (broken in last version)
 - Start Web server eariler in case of Python coding errors

18 files changed:
CHANGELOG.md [new file with mode: 0644]
Makefile
package.json
scripts/gplan-init-build.sh
src/avr/src/config.h
src/avr/src/exec.c
src/jade/templates/motor-view.jade
src/jade/templates/templated-input.jade
src/js/app.js
src/js/motor-view.js
src/py/bbctrl/AVR.py
src/py/bbctrl/Config.py
src/py/bbctrl/Ctrl.py
src/py/bbctrl/Planner.py
src/py/bbctrl/Web.py
src/py/inevent/EventStream.py
src/resources/config-template.json
src/stylus/style.styl

diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644 (file)
index 0000000..745d8f5
--- /dev/null
@@ -0,0 +1,12 @@
+Buildbotics CNC Controller Firmware Change Log
+==============================================
+
+## v0.3.4
+ - Added alternate units for motor parameters
+ - Automatic config file upgrading
+ - Fixed planner/jog sync
+ - Fixed planner limits config
+ - Accel units mm/min² -> m/min²
+ - Search and latch velocity mm/min -> m/min
+ - Fixed password update (broken in last version)
+ - Start Web server eariler in case of Python coding errors
index 8b154350905b2b70a9ebf806ea6109c02bc95a91..b10db0a8482c0a995b0484f83e5eab5a0e945c08 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -61,8 +61,10 @@ $(GPLAN_TARGET): $(GPLAN_MOD)
 
 $(GPLAN_MOD): $(GPLAN_IMG)
        ./scripts/gplan-init-build.sh
-       git -C rpi-share/cbang pull
-       git -C rpi-share/camotics pull
+       git -C rpi-share/cbang fetch
+       git -C rpi-share/cbang reset --hard FETCH_HEAD
+       git -C rpi-share/camotics fetch
+       git -C rpi-share/camotics reset --hard FETCH_HEAD
        cp ./scripts/gplan-build.sh rpi-share/
        sudo ./scripts/rpi-chroot.sh $(GPLAN_IMG) /mnt/host/gplan-build.sh
 
index 214a07f42c11bbd4b1064515d424fcd5f02e96e3..8cbb856314727fa09168d197de5163b5c150dbbd 100644 (file)
@@ -1,6 +1,6 @@
 {
   "name": "bbctrl",
-  "version": "0.3.3",
+  "version": "0.3.4",
   "homepage": "http://buildbotics.com/",
   "repository": "https://github.com/buildbotics/bbctrl-firmware",
   "license": "GPL-3.0+",
index a4cbde3c3886b8fedecbffcf3ec08f6101c08aa1..6459f4994f9d7c249efe4b3a099d527f1891ebd5 100755 (executable)
@@ -31,11 +31,18 @@ if [ ! -e $GPLAN_IMG ]; then
 fi
 
 # Get repos
+function fetch_local_repo() {
+    mkdir -p $1
+    git -C $1 init
+    git -C $1 fetch -t "$2" $3
+    git -C $1 reset --hard FETCH_HEAD
+}
+
 mkdir -p rpi-share || true
 
 if [ ! -e rpi-share/cbang ]; then
     if [ "$CBANG_HOME" != "" ]; then
-        git clone $CBANG_HOME rpi-share/cbang
+        fetch_local_repo rpi-share/cbang "$CBANG_HOME" master
     else
         git clone https://github.com/CauldronDevelopmentLLC/cbang \
             rpi-share/cbang
@@ -44,7 +51,7 @@ fi
 
 if [ ! -e rpi-share/camotics ]; then
     if [ "$CAMOTICS_HOME" != "" ]; then
-        git clone $CAMOTICS_HOME rpi-share/camotics
+        fetch_local_repo rpi-share/camotics "$CAMOTICS_HOME" master
     else
         git clone https://github.com/CauldronDevelopmentLLC/camotics \
             rpi-share/camotics
index 0393dda467919caf3149c11a9d330510a9b5bbf6..1dde93339a8186411f75d978e40c25a0e5634d62 100644 (file)
@@ -211,7 +211,7 @@ enum {
 #define CURRENT_SENSE_REF        2.75          // volts
 #define MAX_CURRENT              10            // amps
 #define VELOCITY_MULTIPLIER      1000.0
-#define ACCEL_MULTIPLIER         1000.0
+#define ACCEL_MULTIPLIER         1000000.0
 #define JERK_MULTIPLIER          1000000.0
 #define SYNC_QUEUE_SIZE          4096
 #define EXEC_FILL_TARGET         8
index e8f75a32759c677788acec0ae2b87c4b4d8df51a..5315a242b74b20aadabbf06eed75326dd227f290 100644 (file)
@@ -58,7 +58,6 @@ void exec_init() {
   memset(&ex, 0, sizeof(ex));
   ex.feed_override = 1;
   ex.spindle_override = 1;
-  // TODO implement pause
   // TODO implement move stepping
   // TODO implement overrides
   // TODO implement optional pause
index 9827706d79124902736f180ba6b567a85c8d43a8..2a5777d282f6d35067313855253dba5d3af421c1 100644 (file)
@@ -8,3 +8,24 @@ script#motor-view-template(type="text/x-template")
 
         templated-input(v-for="templ in category", :name="$key",
           :model.sync="motor[$key]", :template="templ")
+
+          label.extra(v-if="$key == 'max-velocity'", slot="extra",
+            title="Revolutions Per Minute")
+            | ({{1000 * motor[$key] / motor['travel-per-rev'] | fixed 0}} RPM)
+
+          label.extra(v-if="$key == 'max-accel'", slot="extra",
+            title="G-force")
+            | ({{motor[$key] * 0.0283254504 | fixed 3}} g)
+
+          label.extra(v-if="$key == 'max-jerk'", slot="extra",
+            title="G-force per minute")
+            | ({{motor[$key] * 0.0283254504 | fixed 2}} g/min)
+
+          label.extra(v-if="$key == 'step-angle'", slot="extra",
+            title="Steps per revolution")
+            | ({{360 / motor[$key] | fixed 0}} steps/rev)
+
+          label.extra(v-if="$key == 'travel-per-rev'", slot="extra",
+            title="Micrometers per step")
+            | ({{motor[$key] * motor['step-angle'] / 0.36 | fixed 1}}
+            | &nbsp;µm/step)
index 855d91d131fcfa51a44dcb3f8c8e8d78855cdccf..85bdbdbf171d3f8386b33faeac1deca1a4b9f8a6 100644 (file)
@@ -1,5 +1,6 @@
 script#templated-input-template(type="text/x-template")
-  .pure-control-group(:class="name")
+  .pure-control-group(class="tmpl-input-{{name}}",
+    title="Default {{template.default}} {{template.unit}}")
     label(:for="name") {{name}}
 
     select(v-if="template.type == 'enum' || template.values", v-model="model",
@@ -29,3 +30,5 @@ script#templated-input-template(type="text/x-template")
       | {{model}}
 
     label.units {{template.unit}}
+
+    slot(name="extra")
index 228db446f05a25573e388842bc7ac73035e8b23c..58947ad01ac817e32efeed47bc7a85df976a2aef 100644 (file)
@@ -63,7 +63,7 @@ module.exports = new Vue({
     send: function (msg) {
       if (this.status == 'connected') {
         console.debug('>', msg);
-        this.sock.send(msg)
+        this.sock.send(msg);
       }
     },
 
@@ -122,7 +122,7 @@ module.exports = new Vue({
 
       }.bind(this)).fail(function () {
         alert('Invalid password');
-      }.bind(this));
+      }.bind(this))
     },
 
 
@@ -164,18 +164,18 @@ module.exports = new Vue({
             if (key == 'msg') this.$broadcast('message', msg.msg);
             else Vue.set(this.state, key, msg[key]);
           }
-      }.bind(this);
+      }.bind(this)
 
       this.sock.onopen = function (e) {
         this.status = 'connected';
         this.$emit(this.status);
         this.$broadcast(this.status);
-      }.bind(this);
+      }.bind(this)
 
       this.sock.onclose = function (e) {
         this.status = 'disconnected';
         this.$broadcast(this.status);
-      }.bind(this);
+      }.bind(this)
     },
 
 
index 71ca620820a430217dbec9eadb9a0b074bb24128..fb1623f0aeef23925aba5240bb0f5b50814f9a00 100644 (file)
@@ -15,7 +15,7 @@ module.exports = {
 
 
   watch: {
-    index: function() {this.update();}
+    index: function() {this.update()}
   },
 
 
index b9ccdfd15a68285b157f7a36a0aa8384c24f8216..478d9bf15aaafd1e39530d012e698c45645249c4 100644 (file)
@@ -22,9 +22,9 @@ log = logging.getLogger('AVR')
 #   Mark axis homed and set absolute position
 
 axis_homing_procedure = '''
-  G28.2 %(axis)s0 F[#<_%(axis)s_sv>]
+  G28.2 %(axis)s0 F[#<_%(axis)s_sv> * 1000]
   G38.6 %(axis)s[#<_%(axis)s_hd> * [#<_%(axis)s_tm> - #<_%(axis)s_tn>] * 1.5]
-  G38.8 %(axis)s[#<_%(axis)s_hd> * -#<_%(axis)s_lb>] F[#<_%(axis)s_lv>]
+  G38.8 %(axis)s[#<_%(axis)s_hd> * -#<_%(axis)s_lb>] F[#<_%(axis)s_lv> * 1000]
   G38.6 %(axis)s[#<_%(axis)s_hd> * #<_%(axis)s_lb> * 1.5]
   G91 G0 G53 %(axis)s[#<_%(axis)s_hd> * -#<_%(axis)s_zb>]
   G90 G28.3 %(axis)s[#<_%(axis)s_hp>]
index d66ecbef4cbf201087b3b55f3964f4ebb31d3851..5ac4f8f0523b4cba60040ece5feb4a8b8f2dd52b 100644 (file)
@@ -26,13 +26,17 @@ default_config = {
 class Config(object):
     def __init__(self, ctrl):
         self.ctrl = ctrl
-        self.version = pkg_resources.require('bbctrl')[0].version
-        default_config['version'] = self.version
 
-        # Load config template
-        with open(bbctrl.get_resource('http/config-template.json'), 'r',
-                  encoding = 'utf-8') as f:
-            self.template = json.load(f)
+        try:
+            self.version = pkg_resources.require('bbctrl')[0].version
+            default_config['version'] = self.version
+
+            # Load config template
+            with open(bbctrl.get_resource('http/config-template.json'), 'r',
+                      encoding = 'utf-8') as f:
+                self.template = json.load(f)
+
+        except Exception as e: log.exception(e)
 
 
     def load_path(self, path):
@@ -43,7 +47,10 @@ class Config(object):
     def load(self):
         try:
             config = self.load_path('config.json')
-            config['version'] = self.version
+
+            try:
+                self.upgrade(config)
+            except Exception as e: log.exception(e)
 
             # Add missing sections
             for key, value in default_config.items():
@@ -56,11 +63,26 @@ class Config(object):
             return default_config
 
 
-    def save(self, config):
-        self.update(config)
+    def upgrade(self, config):
+        version = tuple(map(int, config['version'].split('.')))
+
+        if version < (0, 2, 4):
+            for motor in config['motors']:
+                for key in 'max-jerk max-velocity'.split():
+                    if key in motor: motor[key] /= 1000
+
+        if version < (0, 3, 4):
+            for motor in config['motors']:
+                for key in 'max-accel latch-velocity search-velocity'.split():
+                    if key in motor: motor[key] /= 1000
 
         config['version'] = self.version
 
+
+    def save(self, config):
+        self.upgrade(config)
+        self.update(config)
+
         with open('config.json', 'w') as f:
             json.dump(config, f)
 
index 039e4da618881addf7957b87596a3d8103503c82..7a228178fcefffa334238b5c96918c44dde08874 100644 (file)
@@ -33,15 +33,19 @@ class Ctrl(object):
 
         self.msgs = bbctrl.Messages(self)
         self.state = bbctrl.State(self)
-        self.planner = bbctrl.Planner(self)
-        self.i2c = bbctrl.I2C(args.i2c_port)
         self.config = bbctrl.Config(self)
-        self.lcd = bbctrl.LCD(self)
         self.web = bbctrl.Web(self)
-        self.avr = bbctrl.AVR(self)
-        self.jog = bbctrl.Jog(self)
-        self.pwr = bbctrl.Pwr(self)
 
-        self.avr.connect()
+        try:
+            self.planner = bbctrl.Planner(self)
+            self.i2c = bbctrl.I2C(args.i2c_port)
+            self.lcd = bbctrl.LCD(self)
+            self.avr = bbctrl.AVR(self)
+            self.jog = bbctrl.Jog(self)
+            self.pwr = bbctrl.Pwr(self)
 
-        self.lcd.add_new_page(IPPage(self.lcd))
+            self.avr.connect()
+
+            self.lcd.add_new_page(IPPage(self.lcd))
+
+        except Exception as e: log.exception(e)
index ee25cb684969a218a6ca09fb0230d2940aae87cf..d7bcd4318773ecce6a67383dbf6f003854fb2185 100644 (file)
@@ -51,14 +51,18 @@ class Planner():
             value = state.get(axis + 'p', None)
             if value is not None: start[axis] = value
 
-        return {
+        config = {
             "start":     start,
             "max-vel":   get_vector('vm', 1000),
-            "max-accel": get_vector('am', 1000),
+            "max-accel": get_vector('am', 1000000),
             "max-jerk":  get_vector('jm', 1000000),
             # TODO junction deviation & accel
             }
 
+        log.info('Config:' + json.dumps(config))
+
+        return config
+
 
     def update(self, update):
         if 'id' in update: self.planner.set_active(update['id'])
@@ -116,7 +120,7 @@ class Planner():
             raise Exception('Cannot issue MDI command while GCode running')
 
         log.info('MDI:' + cmd)
-        self.planner.load_string(cmd)
+        self.planner.load_string(cmd, self.get_config())
         self.mode = 'mdi'
 
 
@@ -125,11 +129,11 @@ class Planner():
             raise Exception('Busy, cannot start new GCode program')
 
         log.info('GCode:' + path)
-        self.planner.load('upload' + path)
+        self.planner.load('upload' + path, self.get_config())
 
 
     def reset(self):
-        self.planner = gplan.Planner(self.get_config())
+        self.planner = gplan.Planner()
         self.planner.set_resolver(self.get_var)
         self.planner.set_logger(self.log, 1, 'LinePlanner:3')
 
@@ -172,11 +176,6 @@ class Planner():
 
 
     def next(self):
-        if not self.is_running():
-            config = self.get_config()
-            log.info('Planner config:' + json.dumps(config))
-            self.planner.set_config(config)
-
         while self.planner.has_more():
             cmd = self.planner.next()
             self.lastID = cmd['id']
index 201cf257d6372bf3d317c798b0b6c7c73f7a6fa9..8eb44f44a91480b6a4f9e28c6916ce05b84656dd 100644 (file)
@@ -82,7 +82,7 @@ class PasswordHandler(bbctrl.APIHandler):
             check_password(self.json['current'])
 
             # Set password
-            s = '%s:%s' % (username, self.json['password'])
+            s = '%s:%s' % (get_username(), self.json['password'])
             s = s.encode('utf-8')
 
             p = subprocess.Popen(['chpasswd', '-c', 'MD5'],
index ac68222cf4bafb586135ab82dc005769e6a1a4f1..404815e03205dcb5450e599d82ad6fa6efb6c393 100644 (file)
@@ -143,6 +143,9 @@ class EventStream(object):
     return self
 
 
+  def next(self): return self.__next__()
+
+
   def __next__(self):
     """
     Returns the next waiting event.
index a1638bb3fce3ea591d4f5e70148de6f60baea364..fa754ba5c1e512631ec0cfa9c5ae9bf215251bd5 100644 (file)
@@ -57,8 +57,8 @@
       "max-accel": {
         "type": "float",
         "min": 0,
-        "unit": "m/min²",
-        "default": 1000,
+        "unit": "km/min²",
+        "default": 10,
         "code": "am"
       },
       "max-jerk": {
       "search-velocity": {
         "type": "float",
         "min": 0,
-        "unit": "mm/min",
-        "default": 500,
+        "unit": "m/min",
+        "default": 0.5,
         "code": "sv"
       },
       "latch-velocity": {
         "type": "float",
         "min": 0,
-        "unit": "mm/min",
-        "default": 100,
+        "unit": "m/min",
+        "default": 0.1,
         "code": "lv"
       },
       "latch-backoff": {
index 289060de129944574f821f8b3c162753b138f658..388add592b2aab711784e05c4bf200ab474ef7ec 100644 (file)
@@ -129,6 +129,9 @@ body
       text-transform capitalize
 
     .pure-control-group
+      label.units
+        width 6em
+
       label.units
         text-align left
 
@@ -136,10 +139,6 @@ body
         width 24em
         height 12em
 
-    .switch
-      h3, .pure-control-group
-        display inline-block
-
 @keyframes blink
   50%
     fill #ff9d00