From 6945bbee6735801218cf78dbe50b19c4c0fe112d Mon Sep 17 00:00:00 2001
From: Andy Pugh <andy@bodgesoc.org>
Date: Fri, 28 Jan 2011 23:43:59 +0000
Subject: [PATCH 1/3] modified gearchange.comp

Signed-off-by: Andy Pugh <andy@bodgesoc.org>
---
 src/hal/components/gearchange.comp |  113 ++++++++++++++++++++++--------------
 1 files changed, 70 insertions(+), 43 deletions(-)

diff --git a/src/hal/components/gearchange.comp b/src/hal/components/gearchange.comp
index 2ca7250..8cbe8c8 100644
--- a/src/hal/components/gearchange.comp
+++ b/src/hal/components/gearchange.comp
@@ -1,88 +1,115 @@
-component gearchange """Calculate the correct motor speed setpoint for a 
-machine with multiple gear ratios.""";
+component gearchange """Adjust motor speed command for geared spindles.
+Scales the input value to the output depending on selected gear.""";
 
 pin in float speed-in "Speed command input.";
 pin out float speed-out "Speed command to DAC/PWM";
-pin in bit gear-#-sel [32 : personality+1] """Gear selection by bit. Higher
+pin in bit sel-# [32 : personality] """Gear selection by bit. Higher
 numbers take priority if more than one is set""";
-pin in bit sel "Alias for sel2 for compatibility with the previous version ";
-pin in bit dir_in "Direction input for absolute speed + dir modes";
-pin out bit dir-out "Direction output (will be reversed for negative scales)";
+pin in bit dir-in "Direction input for absolute speed + dir modes";
+pin out bit dir-out "Direction output (will be reversed for negative ratios)";
 pin out bit min-lim "Indicates that the minimum limitation is active";
 pin out bit max-lim "Indicates that the maximum limitation is active";
-pin in unsigned gear-number "Gear selection as a numeric";
+pin in signed gear-number =-1 "Numeric (rather than bit) Gear selection";
 pin out float speed-filtered "Speed command to display, limited and absolute";
 pin out float accel-limit "Acceleration limit for the selected gear";
-param rw float min#[32: personality+1] = 0 
-    "Minimum allowed speed in gear range N";
-param rw float max#[32 : personality+1] = 100000 
-    "Maximum allowed speed in gear range N";
-param rw float acc#[32 : personality+1] = 0 
-    "Maximum Acceleration in rpm/s. 0 = no limit";
-param rw float scale#[32 : personality+1] = 1.0 "Ratio in gear range 1";
-param rw bit reverse "negates the value of scale2, for compatibility";
-
-option extra_setup;
-variable float old_speed = 0;
+pin out unsigned gear "The actual detected gear";
+param rw float min-#[32: personality] = 0 
+"Minimum allowed speed in gear range N";
+param rw float max-#[32 : personality] = 100000 
+"Maximum allowed speed in gear range N";
+param rw float acc-#[32 : personality] = 0 
+"Maximum Acceleration in output units/s. 0 = no limit";
+param rw float scale-#[32 : personality] = 1.0 """Ratio between speed input and 
+the required output value""";
+modparam dummy num_gears """The number of gear ratios to create in each instance. 
+To create mutiple instances use multiple, comma separated values.""";
 
 description """The output will be a  value scaled for the selected gear, and 
 clamped to the min/max values for that gear.
 
-This should work for up to 32 gears.
+This version should work for up to 32 gears.
 To load two instances, one with 5 gears and one with 6 use:
-loadrt gearchange count=2 personality=5,6
-For a single instance you can omit the count, eg with 11 gears you can use:
-loadrt gearchange personality=11
 
-It accepts negative speeds, negative outputs and negative scales to allow for 
-gear ranges that reverse the motion.
+loadrt gearchange num_gears=5,6
+
+Gears are numbered from zero, ie the count includes neutral, so typically the 
+modparam should be one more than the actual gear ratio count.
+
+The Component accepts negative speeds, negative outputs and negative scales to 
+allow for gear ranges that reverse the motion.
+
+The scale pin is the ratio between output value and input speed, so the same VFD 
+scale parameter (typically set by the PWM scale parameter) will work for any 
+gear. It might be sensible to set the PWM scale to 1, in which case the 
+individual gear scales will be in rpm/volt. 
+The output value is that motor speed which would be required to give the 
+requested output speed with a gear ratio of 1 at the set PWM scale. For example 
+if gear 1 has a max speed of 1000rpm and requires 10V to the VFD to achieve 
+that, and gear 2 has a max speed of 4000rpm then gearchange.N.ratio2 should be 
+set to 4. Then a spindle speed of 1000rpm would give 10V output in gear 1 and 
+2.5V in gear 2. 
 
-The scale is the ratio between input speed and output speed, so the same VFD 
-scale parameter will work for any gear. The output value is that motor speed 
-which would be required to give the requested output speed with a gear ratio of
-1. If gear 1 is the slowest gear then other ratios will probably need to be 
-fractional. If the highest numbered gear is the slowest then the scales will 
-probably need to be greater than one. 
 
 The gear can be input either as a numeric value (possibly assembled from 
 \\fBweighted_sum\\fR components to convert the positions of several levers into 
-a gear) or as an individual select bit for each gear. """;
+a gear) or as an individual select bit for each gear.""";
+
+option count_function yes;
+option extra_setup yes;
+
+variable float old_speed = 0;
 
 function _;
 license "GPL";
 ;;
 #include <rtapi_math.h>
+#define MAX_INSTS 8
+static int num_gears[MAX_INSTS];
+
+RTAPI_MP_ARRAY_INT(num_gears, MAX_INSTS, "Gear count for each gearbox");
+
 FUNCTION(_) {
-    int gear;
     double speed_target;
     double delta;
     
-    if (sel) gear = 2; // Backwards compatibility
-    else if (gear_number) gear = gear_number;
-    else for (gear = personality ; gear > 0 && !gear_sel(gear) ; gear--) {}
+    if (gear_number != -1) gear = gear_number;
+    else for (gear = personality-1 ; gear > 0 && !sel(gear) ; gear--) {}
     
     speed_filtered = fabs(speed_in);
     if (speed_filtered > max(gear)) {
         max_lim = 1; min_lim = 0;
         speed_filtered = max(gear);}
-    else if (speed_filtered < min(gear)) {
+    else if (speed_filtered != 0 && speed_filtered < min(gear)) { // zero is 0
         min_lim = 1; max_lim = 0;
         speed_filtered = min(gear);}
     else { min_lim = 0; max_lim = 0; }
     
-    speed_target =  speed_filtered * ((scale(gear) != 0)? scale(gear) : 1)
-    *((speed_in < 0)? -1 : 1) ;
+    if (scale(gear) == 0) {
+        speed_target = 0;}
+    else {
+        speed_target = speed_filtered / scale(gear) * ((speed_in < 0)? -1 : 1);}
+    
     delta = acc(gear) * fperiod * ((speed_target > old_speed)? 1 : -1);
-    speed_out = 
-        ((acc(gear) != 0 && fabs(speed_target - old_speed) > fabs(delta))?
-        (old_speed += delta) : (old_speed = speed_target));
+    
+    if (acc(gear) != 0 && fabs(speed_target - old_speed) > fabs(delta)){
+        speed_out = (old_speed += delta);}
+    else{
+        speed_out = (old_speed = speed_target);}
     
     dir_out = ((scale(gear) < 0)? !dir_in : dir_in);
-    dir_out = ((reverse && gear == 2)? !dir_out : dir_out); // Backwards compat
+    
     accel_limit = acc(gear);
 }
 
 EXTRA_SETUP( ) {
-    if (personality == 0) personality = 2;
+    if (num_gears[extra_arg] < 2) personality = 2;
+    else personality = num_gears[extra_arg];
     return 0;
 }
+
+int get_count(void){
+    int i;
+    for (i = 0; num_gears[i] != 0 && i < MAX_INSTS; i++){}
+    if (i == 0) return 1;
+    return i;
+}
-- 
1.7.0.4

