commit ec6085f7267360b2c9fdc398dadde1c618ca6f65 Author: Mario Voigt Date: Mon Jul 20 22:21:36 2020 +0200 Initial commit diff --git a/abc_measurements.xlsx b/abc_measurements.xlsx new file mode 100644 index 0000000..d6bb93a Binary files /dev/null and b/abc_measurements.xlsx differ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/.cproject b/firmware_smartstepper_trikarus/stepper_nano_zero/.cproject new file mode 100644 index 0000000..114531f --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/.cproject @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/.project b/firmware_smartstepper_trikarus/stepper_nano_zero/.project new file mode 100644 index 0000000..41a61b6 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/.project @@ -0,0 +1,34 @@ + + + NZS + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + + + arduino + 2 + C:/Users/tramp_000/AppData/Local/Arduino15/packages/arduino/hardware/samd/1.6.8/cores/arduino + + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.cpp new file mode 100644 index 0000000..168493d --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.cpp @@ -0,0 +1,152 @@ +/********************************************************************** + Copyright (C) 2019 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include +#include "syslog.h" +#include "A1333.h" +#include "SPI.h" +#include +#include "board.h" + + +#define A1333_CMD_NOP (0x0000) +#define A1333_ANG15 (0x3200) + +SPISettings settingsA(500000, MSBFIRST, SPI_MODE3); ///400000, MSBFIRST, SPI_MODE1); + +boolean A1333::begin(int csPin) +{ + + digitalWrite(PIN_AS5047D_CS,LOW); //pull CS LOW by default (chip powered off) + digitalWrite(PIN_MOSI,LOW); + digitalWrite(PIN_SCK,LOW); + digitalWrite(PIN_MISO,LOW); + pinMode(PIN_MISO,OUTPUT); + delay(1000); + + + digitalWrite(PIN_AS5047D_CS,HIGH); //pull CS high + + pinMode(PIN_MISO,INPUT); + + + chipSelectPin=csPin; + + LOG("csPin is %d",csPin); + pinMode(chipSelectPin,OUTPUT); + digitalWrite(chipSelectPin,HIGH); //pull CS high by default + delay(1); + + SPI.begin(); //AS5047D SPI uses mode=1 (CPOL=0, CPHA=1) + + LOG("Begin A1333..."); + + LOG("Address is 0x%04X",readAddress(A1333_ANG15)); +} + + +//read the encoders +int16_t A1333::readAddress(uint16_t addr) +{ + uint16_t data; + //make sure it is a write by setting bit 14 + //addr=addr | 0x4000; + + SPI.beginTransaction(settingsA); + digitalWrite(chipSelectPin, LOW); + delayMicroseconds(1); + //clock out the address to read + //LOG("address 0x%04X",addr); + SPI.transfer16(addr); + digitalWrite(chipSelectPin, HIGH); + delayMicroseconds(1); + digitalWrite(chipSelectPin, LOW); + //clock out zeros to read in the data from address + data=SPI.transfer16(0x00); + + digitalWrite(chipSelectPin, HIGH); + SPI.endTransaction(); + + return data; +} + +//read the encoders +int16_t A1333::readEncoderAngle(void) +{ + + return readAddress(A1333_ANG15)>>1; +} + +int16_t A1333::readEncoderAnglePipeLineRead(void) +{ + static bool first=true; + uint16_t addr = A1333_ANG15; + uint16_t addr2; + uint16_t data; + + if (first) + { + //make sure it is a write by setting bit 14 + //addr2=addr | 0x4000; + SPI.beginTransaction(settingsA); + digitalWrite(chipSelectPin, LOW); + delayMicroseconds(1); + //clock out the address to read + SPI.transfer16(addr); + digitalWrite(chipSelectPin, HIGH); + delayMicroseconds(1); + digitalWrite(chipSelectPin, LOW); + delayMicroseconds(1); + //clock out zeros to read in the data from address + data=SPI.transfer16(addr); + + digitalWrite(chipSelectPin, HIGH); + SPI.endTransaction(); + first=false; + return data>>1; + } + + SPI.beginTransaction(settingsA); + digitalWrite(chipSelectPin, LOW); + delayMicroseconds(1); + //clock out zeros to read in the data from address + data=SPI.transfer16(addr); + + digitalWrite(chipSelectPin, HIGH); + SPI.endTransaction(); + return data>>1; +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.h b/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.h new file mode 100644 index 0000000..ee9ee68 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A1333.h @@ -0,0 +1,59 @@ +/********************************************************************** + Copyright (C) 2019 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef A1333_H_ +#define A1333_H_ + +#include + +#define A1333_DEGREES_PER_BIT (360.0/(float)(0x7FFF)) + +class A1333 { + private: + int chipSelectPin; + public: + boolean begin(int csPin); + int16_t readEncoderAngle(void); + int16_t readAddress(uint16_t addr); + int16_t readEncoderAnglePipeLineRead(void); + void diagnostics(char *ptrStr) {return;}; + bool getError(void) {return false;}; +}; + + + +#endif /* A1333_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.cpp new file mode 100644 index 0000000..61388a4 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.cpp @@ -0,0 +1,412 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "A4954.h" +#include "wiring_private.h" +#include "syslog.h" +#include "angle.h" +#include "Arduino.h" +#include "sine.h" + +static uint8_t pinState=0; + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + + + + +#define DAC_MAX (0x01FFL) +// Wait for synchronization of registers between the clock domains +static __inline__ void syncTCC(Tcc* TCCx) __attribute__((always_inline, unused)); +static void syncTCC(Tcc* TCCx) { + //int32_t t0=1000; + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + { + // t0--; + // if (t0==0) + // { + // break; + // } + // delay(1); + } +} + + +static inline void bridge1(int state) +{ + if (state==0) + { + PORT->Group[g_APinDescription[PIN_A4954_IN1].ulPort].PINCFG[g_APinDescription[PIN_A4954_IN1].ulPin].bit.PMUXEN = 0; + GPIO_OUTPUT(PIN_A4954_IN1);//pinMode(PIN_A4954_IN1,OUTPUT); + GPIO_OUTPUT(PIN_A4954_IN2);//pinMode(PIN_A4954_IN2,OUTPUT); + GPIO_HIGH(PIN_A4954_IN1);// digitalWrite(PIN_A4954_IN1, HIGH); + GPIO_LOW(PIN_A4954_IN2);//digitalWrite(PIN_A4954_IN2, LOW); + //pinPeripheral(PIN_A4954_IN2, PIO_TIMER_ALT); + pinState=(pinState & 0x0C) | 0x1; + } + if (state==1) + { + PORT->Group[g_APinDescription[PIN_A4954_IN2].ulPort].PINCFG[g_APinDescription[PIN_A4954_IN2].ulPin].bit.PMUXEN = 0; + GPIO_OUTPUT(PIN_A4954_IN2);//pinMode(PIN_A4954_IN2,OUTPUT); + GPIO_OUTPUT(PIN_A4954_IN1);pinMode(PIN_A4954_IN1,OUTPUT); + GPIO_LOW(PIN_A4954_IN1);//digitalWrite(PIN_A4954_IN1, LOW); + GPIO_HIGH(PIN_A4954_IN2);//digitalWrite(PIN_A4954_IN2, HIGH); + //pinPeripheral(PIN_A4954_IN1, PIO_TIMER); + pinState=(pinState & 0x0C) | 0x2; + } + if (state==3) + { + GPIO_LOW(PIN_A4954_IN1); + GPIO_LOW(PIN_A4954_IN2); + //digitalWrite(PIN_A4954_IN1, LOW); + //digitalWrite(PIN_A4954_IN2, LOW); + } +} + +static inline void bridge2(int state) +{ + if (state==0) + { + PORT->Group[g_APinDescription[PIN_A4954_IN3].ulPort].PINCFG[g_APinDescription[PIN_A4954_IN3].ulPin].bit.PMUXEN = 0; + GPIO_OUTPUT(PIN_A4954_IN3); //pinMode(PIN_A4954_IN3,OUTPUT); + GPIO_OUTPUT(PIN_A4954_IN4);//pinMode(PIN_A4954_IN4,OUTPUT); + GPIO_HIGH(PIN_A4954_IN3);//digitalWrite(PIN_A4954_IN3, HIGH); + GPIO_LOW(PIN_A4954_IN4);//digitalWrite(PIN_A4954_IN4, LOW); + //pinPeripheral(PIN_A4954_IN4, PIO_TIMER_ALT); + pinState=(pinState & 0x03) | 0x4; + } + if (state==1) + { + PORT->Group[g_APinDescription[PIN_A4954_IN4].ulPort].PINCFG[g_APinDescription[PIN_A4954_IN4].ulPin].bit.PMUXEN = 0; + GPIO_OUTPUT(PIN_A4954_IN4);//pinMode(PIN_A4954_IN4,OUTPUT); + GPIO_OUTPUT(PIN_A4954_IN3);//pinMode(PIN_A4954_IN3,OUTPUT); + GPIO_LOW(PIN_A4954_IN3);//digitalWrite(PIN_A4954_IN3, LOW); + GPIO_HIGH(PIN_A4954_IN4);//digitalWrite(PIN_A4954_IN4, HIGH); + //pinPeripheral(PIN_A4954_IN3, PIO_TIMER_ALT); + pinState=(pinState & 0x03) | 0x8; + } + if (state==3) + { + GPIO_LOW(PIN_A4954_IN3); + GPIO_LOW(PIN_A4954_IN4); + //digitalWrite(PIN_A4954_IN3, LOW); + //digitalWrite(PIN_A4954_IN4, LOW); + } +} + +static void enableTCC0(uint8_t percent) +{ +#ifdef MECHADUINO_HARDWARE + return; +#else + Tcc* TCCx = TCC0 ; + + + uint32_t ulValue=((uint32_t)(100-percent)*480)/100; + //ERROR("Enable TCC0"); + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; + + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + //ERROR("Setting TCC %d %d",ulValue,ulPin); + TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + syncTCC(TCCx); + + // Set TCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + syncTCC(TCCx); + + // Set TCx in waveform mode Normal PWM + TCCx->CC[1].reg = (uint32_t)ulValue; //ch5 //IN3 + syncTCC(TCCx); + + TCCx->CC[2].reg = (uint32_t)ulValue; //ch6 //IN4 + syncTCC(TCCx); + + TCCx->CC[3].reg = (uint32_t)ulValue; //ch7 //IN2 + syncTCC(TCCx); + + TCCx->CC[1].reg = (uint32_t)ulValue; //ch1 == ch5 //IN1 + + syncTCC(TCCx); + + // Set PER to maximum counter value (resolution : 0xFF) + TCCx->PER.reg = DAC_MAX; + syncTCC(TCCx); + + // Enable TCCx + TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; + syncTCC(TCCx); + //ERROR("Enable TCC0 DONE"); +#endif +} + +static void setDAC(uint32_t DAC1, uint32_t DAC2) +{ + TCC1->CC[1].reg = (uint32_t)DAC1; //D9 PA07 - VREF12 + syncTCC(TCC1); + TCC1->CC[0].reg = (uint32_t)DAC2; //D4 - VREF34 + syncTCC(TCC1); + + +} + +static void setupDAC(void) +{ + Tcc* TCCx = TCC1 ; + + + pinPeripheral(PIN_A4954_VREF34, PIO_TIMER_ALT); + pinPeripheral(PIN_A4954_VREF12, PIO_TIMER); + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; + + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + //ERROR("Setting TCC %d %d",ulValue,ulPin); + TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + syncTCC(TCCx); + + // Set TCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + syncTCC(TCCx); + + // Set TCx in waveform mode Normal PWM + TCCx->CC[1].reg = (uint32_t)0; + syncTCC(TCCx); + + TCCx->CC[0].reg = (uint32_t)0; + syncTCC(TCCx); + + // Set PER to maximum counter value (resolution : 0xFFF = 12 bits) + // =48e6/2^12=11kHz frequency + TCCx->PER.reg = DAC_MAX; + syncTCC(TCCx); + + // Enable TCCx + TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; + syncTCC(TCCx); + +} + + +void A4954::begin() +{ + //setup the A4954 pins + digitalWrite(PIN_A4954_IN3,LOW); + pinMode(PIN_A4954_IN3,OUTPUT); + digitalWrite(PIN_A4954_IN4,LOW); + pinMode(PIN_A4954_IN4,OUTPUT); + digitalWrite(PIN_A4954_IN2,LOW); + pinMode(PIN_A4954_IN2,OUTPUT); + digitalWrite(PIN_A4954_IN1,LOW); + pinMode(PIN_A4954_IN1,OUTPUT); + + //setup the PWM for current on the A4954, set for low current + digitalWrite(PIN_A4954_VREF12,LOW); + digitalWrite(PIN_A4954_VREF34,LOW); + pinMode(PIN_A4954_VREF34, OUTPUT); + pinMode(PIN_A4954_VREF12, OUTPUT); + + enabled=true; + lastStepMicros=0; + forwardRotation=true; + + enableTCC0(90); + setupDAC(); +// +// int i=0; +// bridge1(0); +// bridge2(0); +//while (1) +// { +// int32_t x; +// WARNING("MA %d",i); +// x=(int32_t)((int64_t)i*(DAC_MAX))/3300; +// setDAC(x,x); +// delay(1000); +// i=i+10; +// if (i>1000) +// { +// i=0; +// } +// +// } + +// +// WARNING("Setting DAC for 500mA output"); +// setDAC((int32_t)((int64_t)1000*(DAC_MAX))/3300,(int32_t)((int64_t)1000*(DAC_MAX))/3300); +// bridge1(0); +// bridge2(0); +// while(1) +// { +// +// } + return; +} + +void A4954::limitCurrent(uint8_t percent) +{ +#ifdef MECHADUINO_HARDWARE + return; +#else + //WARNING("current limit %d",percent); + enableTCC0(percent); + if (pinState & 0x01) + { + pinPeripheral(PIN_A4954_IN2, PIO_TIMER_ALT); //TCC0 WO[7] + } + if (pinState & 0x02) + { + pinPeripheral(PIN_A4954_IN1, PIO_TIMER); //TCC0 WO[1] + } + if (pinState & 0x04) + { + pinPeripheral(PIN_A4954_IN4, PIO_TIMER_ALT); + } + if (pinState & 0x08) + { + pinPeripheral(PIN_A4954_IN3, PIO_TIMER_ALT); + } +#endif +} + + +void A4954::enable(bool enable) +{ + enabled=enable; + if (enabled == false) + { + WARNING("A4954 disabled"); + setDAC(0,0); //turn current off + bridge1(3); //tri state bridge outputs + bridge2(3); //tri state bridge outputs + } +} + + + +//this is precise move and modulo of A4954_NUM_MICROSTEPS is a full step. +// stepAngle is in A4954_NUM_MICROSTEPS units.. +// The A4954 has no idea where the motor is, so the calling function has to +// to tell the A4954 what phase to drive motor coils. +// A4954_NUM_MICROSTEPS is 256 by default so stepAngle of 1024 is 360 degrees +// Note you can only move up to +/-A4954_NUM_MICROSTEPS from where you +// currently are. +int32_t A4954::move(int32_t stepAngle, uint32_t mA) +{ + uint16_t angle; + int32_t cos,sin; + int32_t dacSin,dacCos; + //static int i=0; + + if (enabled == false) + { + //WARNING("A4954 disabled"); + setDAC(0,0); //turn current off + bridge1(3); //tri state bridge outputs + bridge2(3); //tri state bridge outputs + return stepAngle; + } + + //WARNING("move %d %d",stepAngle,mA); + //handle roll overs, could do with modulo operator + stepAngle=stepAngle%SINE_STEPS; + + //figure out our sine Angle + // note our SINE_STEPS is 4x of microsteps for a reason + //angle=(stepAngle+(SINE_STEPS/8)) % SINE_STEPS; + angle=(stepAngle); + + //calculate the sine and cosine of our angle + sin=sine(angle); + cos=cosine(angle); + + //if we are reverse swap the sign of one of the angels + if (false == forwardRotation) + { + cos=-cos; + } + + //scale sine result by current(mA) + dacSin=((int32_t)mA*(int64_t)abs(sin))/SINE_MAX; + + //scale cosine result by current(mA) + dacCos=((int32_t)mA*(int64_t)abs(cos))/SINE_MAX; + +// if (i==0) +// { +// WARNING("dacs are %d %d",dacSin,dacCos); +// } + + //convert value into DAC scaled to 3300mA max + dacCos=(int32_t)((int64_t)dacCos*(DAC_MAX))/3300; + //convert value into DAC scaled to 3300mA max + dacSin=(int32_t)((int64_t)dacSin*(DAC_MAX))/3300; + + //WARNING("dacs are %d %d ",dacSin,dacCos); + + setDAC(dacSin,dacCos); + + if (sin>0) + { + bridge1(1); + }else + { + bridge1(0); + } + if (cos>0) + { + bridge2(1); + }else + { + bridge2(0); + } + +// if (i++>3000) +// { +// i=0; +// } + // YELLOW_LED(led); + // led=(led+1) & 0x01; + lastStepMicros=micros(); + return stepAngle; +} +#pragma GCC pop_options + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.h b/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.h new file mode 100644 index 0000000..c66decb --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A4954.h @@ -0,0 +1,90 @@ +/********************************************************************** + Copyright (C) 2019 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __A4954__H__ +#define __A4954__H__ +#include +#include "board.h" +#include "angle.h" +#include "sine.h" + +#define A4954_NUM_MICROSTEPS (256) +#define A4954_MIN_TIME_BETWEEN_STEPS_MICROS (1000) + +//prevent someone for making a mistake with the code +#if ((A4954_NUM_MICROSTEPS*4) != SINE_STEPS) +#error "SINE_STEPS must be 4x of Micro steps for the move function" +#endif + + + +/* + * When it comes to the stepper driver if we use angles + * we will always have a rounding error. For example + * a 0-65536(360) angle for 1.8 degree step is 327.68 so + * if you increment 200 of these as 327 you have a 13.6 error + * after one rotation. + * If you use floating point the effect is the same but takes longer. + * + * The only error-less accumulation system is to use native units, ie full + * steps and microsteps. + * + */ + +class A4954 +{ +private: + uint32_t lastStepMicros; // time in microseconds that last step happened + bool forwardRotation=true; + volatile bool enabled=true; + +public: + void begin(void); + + //moves motor where the modulo of A4954_NUM_MICROSTEPS is a full step. + int32_t move(int32_t stepAngle, uint32_t mA); + + uint32_t microsSinceStep(void) {return micros()-lastStepMicros;}; + void setRotationDirection(bool forward) {forwardRotation=forward;}; + + void enable(bool enable); + void limitCurrent(uint8_t percent); //higher more current +}; + + + +#endif //__A4954__H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.cpp new file mode 100644 index 0000000..f2b8a9f --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.cpp @@ -0,0 +1,337 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + + +#include "A5995.h" +#include "wiring_private.h" +#include "syslog.h" +#include "angle.h" +#include "Arduino.h" +#include "sine.h" + +static uint8_t pinState=0; + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + + + + +#define DAC_MAX (0x01FFL) +// Wait for synchronization of registers between the clock domains +static __inline__ void syncTCC(Tcc* TCCx) __attribute__((always_inline, unused)); +static void syncTCC(Tcc* TCCx) { + //int32_t t0=1000; + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + { + // t0--; + // if (t0==0) + // { + // break; + // } + // delay(1); + } +} + + + +static void setDAC(uint32_t DAC1, uint32_t DAC2) +{ + TCC1->CC[1].reg = (uint32_t)DAC1; //D9 PA07 - VREF2 + syncTCC(TCC1); + TCC1->CC[0].reg = (uint32_t)DAC2; //D4 - VREF1 + syncTCC(TCC1); + +} + +static void setupDAC(void) +{ + Tcc* TCCx = TCC1 ; + + + pinPeripheral(PIN_A5995_VREF1, PIO_TIMER_ALT); + pinPeripheral(PIN_A5995_VREF2, PIO_TIMER); + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; + + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + //ERROR("Setting TCC %d %d",ulValue,ulPin); + TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + syncTCC(TCCx); + + // Set TCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + syncTCC(TCCx); + + // Set TCx in waveform mode Normal PWM + TCCx->CC[1].reg = (uint32_t)0; + syncTCC(TCCx); + + TCCx->CC[0].reg = (uint32_t)0; + syncTCC(TCCx); + + // Set PER to maximum counter value (resolution : 0xFFF = 12 bits) + // =48e6/2^12=11kHz frequency + TCCx->PER.reg = DAC_MAX; + syncTCC(TCCx); + + // Enable TCCx + TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; + syncTCC(TCCx); + +} + + +void A5995::begin() +{ + //setup the A5995 pins + digitalWrite(PIN_A5995_ENABLE1,LOW); + pinMode(PIN_A5995_ENABLE1,OUTPUT); + digitalWrite(PIN_A5995_ENABLE2,LOW); + pinMode(PIN_A5995_ENABLE2,OUTPUT); + digitalWrite(PIN_A5995_MODE1,LOW); + pinMode(PIN_A5995_MODE1,OUTPUT); + digitalWrite(PIN_A5995_MODE2,LOW); + pinMode(PIN_A5995_MODE2,OUTPUT); + digitalWrite(PIN_A5995_PHASE1,LOW); + pinMode(PIN_A5995_PHASE1,OUTPUT); + digitalWrite(PIN_A5995_PHASE2,LOW); + pinMode(PIN_A5995_PHASE2,OUTPUT); + + digitalWrite(PIN_A5995_SLEEPn,HIGH); + pinMode(PIN_A5995_SLEEPn,OUTPUT); + + + + //setup the PWM for current on the A4954, set for low current + digitalWrite(PIN_A5995_VREF1,LOW); + digitalWrite(PIN_A5995_VREF2,LOW); + pinMode(PIN_A5995_VREF1, OUTPUT); + pinMode(PIN_A5995_VREF2, OUTPUT); + + enabled=true; + lastStepMicros=0; + forwardRotation=true; + + setupDAC(); + + +// +// GPIO_HIGH(PIN_A5995_ENABLE1); +// GPIO_HIGH(PIN_A5995_ENABLE2); +// GPIO_LOW(PIN_A5995_MODE1); +// GPIO_LOW(PIN_A5995_MODE2); +// GPIO_HIGH(PIN_A5995_PHASE1); +// GPIO_HIGH(PIN_A5995_PHASE2); +// int i=0;; +// while (1) +// { +// int32_t x; +// WARNING("MA %d",i); +// x=(int32_t)((int64_t)i*(DAC_MAX))/3300; +// setDAC(x,x); +// delay(1000); +// i=i+10; +// if (i>1000) +// { +// i=0; +// } +// +// } + + + return; +} + + + +void A5995::enable(bool enable) +{ + enabled=enable; + if (enabled == false) + { + WARNING("A4954 disabled"); + setDAC(0,0); //turn current off + GPIO_LOW(PIN_A5995_ENABLE1); + GPIO_LOW(PIN_A5995_ENABLE2); + GPIO_LOW(PIN_A5995_MODE1); + GPIO_LOW(PIN_A5995_MODE2); + GPIO_LOW(PIN_A5995_PHASE1); + GPIO_LOW(PIN_A5995_PHASE2); + } +} + + + +//this is precise move and modulo of A4954_NUM_MICROSTEPS is a full step. +// stepAngle is in A4954_NUM_MICROSTEPS units.. +// The A4954 has no idea where the motor is, so the calling function has to +// to tell the A4954 what phase to drive motor coils. +// A4954_NUM_MICROSTEPS is 256 by default so stepAngle of 1024 is 360 degrees +// Note you can only move up to +/-A4954_NUM_MICROSTEPS from where you +// currently are. +int32_t A5995::move(int32_t stepAngle, uint32_t mA) +{ + uint16_t angle; + int32_t cos,sin; + int32_t dacSin,dacCos; + static int32_t lastSin=0,lastCos=0; + static int i=1; + + if (enabled == false) + { + WARNING("A4954 disabled"); + setDAC(0,0); //turn current off + GPIO_LOW(PIN_A5995_ENABLE1); + GPIO_LOW(PIN_A5995_ENABLE2); + GPIO_LOW(PIN_A5995_MODE1); + GPIO_LOW(PIN_A5995_MODE2); + GPIO_LOW(PIN_A5995_PHASE1); + GPIO_LOW(PIN_A5995_PHASE2); + return stepAngle; + } + + //WARNING("move %d %d",stepAngle,mA); + + stepAngle=(stepAngle) % SINE_STEPS; + //figure out our sine Angle + // note our SINE_STEPS is 4x of microsteps for a reason + //angle=(stepAngle+(SINE_STEPS/8)) % SINE_STEPS; + angle=stepAngle; + + if (i==0) + { + WARNING("angle %d ",angle); + } + //calculate the sine and cosine of our angle + sin=sine(angle); + cos=cosine(angle); + + //if we are reverse swap the sign of one of the angels + if (false == forwardRotation) + { + cos=-cos; + } + + //scale sine result by current(mA) + dacSin=((int32_t)mA*(int64_t)(sin))/SINE_MAX; + + if (i==0) + { + WARNING("dacsine %d ",dacSin); + } +// if ((lastSin-dacSin)>100) //decreasing current +// { +// GPIO_LOW(PIN_A5995_MODE2); //fast decay +// } else +// { +// GPIO_HIGH(PIN_A5995_MODE2); //slow decay +// } + lastSin=dacSin; + + //convert value into DAC scaled to 3300mA max + dacSin=(int32_t)((int64_t)abs(dacSin)*(DAC_MAX))/3300; + + + //scale cosine result by current(mA) + dacCos=((int32_t)mA*(int64_t)(cos))/SINE_MAX; + + if (i==0) + { + WARNING("daccos %d ",dacCos); + } +// if ((lastCos-dacCos)>100) //decreasing current +// { +// GPIO_LOW(PIN_A5995_MODE1); //fast decay +// } else +// { +// GPIO_HIGH(PIN_A5995_MODE1); //slow decay +// } + lastCos=dacCos; + + //convert value into DAC scaled to 3300mA max + dacCos=(int32_t)((int64_t)abs(dacCos)*(DAC_MAX))/3300; + + +if (i==0) +{ + WARNING("dacs are %d %d",dacSin,dacCos); +} + setDAC(dacSin,dacCos); + + GPIO_HIGH(PIN_A5995_ENABLE1); + GPIO_HIGH(PIN_A5995_ENABLE2); + GPIO_LOW(PIN_A5995_MODE1); + GPIO_LOW(PIN_A5995_MODE2); + + +if (i==0) +{ + WARNING("sins are %d %d",sin,cos); +} + + if (sin>0) + { + GPIO_HIGH(PIN_A5995_PHASE2); + }else + { + GPIO_LOW(PIN_A5995_PHASE2); + + } + if (cos>0) + { + GPIO_HIGH(PIN_A5995_PHASE1); + + }else + { + GPIO_LOW(PIN_A5995_PHASE1); + + } + +// i++; +// if (i>3000) i=0; + // YELLOW_LED(led); + // led=(led+1) & 0x01; + lastStepMicros=micros(); + return stepAngle; +} +#pragma GCC pop_options + + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.h b/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.h new file mode 100644 index 0000000..756513c --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/A5995.h @@ -0,0 +1,92 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef A5995_H_ +#define A5995_H_ + +#include +#include "board.h" +#include "angle.h" +#include "sine.h" + +#define A5995_NUM_MICROSTEPS (256) + + +//prevent someone for making a mistake with the code +#if ((A5995_NUM_MICROSTEPS*4) != SINE_STEPS) +#error "SINE_STEPS must be 4x of Micro steps for the move function" +#endif + + + +/* + * When it comes to the stepper driver if we use angles + * we will always have a rounding error. For example + * a 0-65536(360) angle for 1.8 degree step is 327.68 so + * if you increment 200 of these as 327 you have a 13.6 error + * after one rotation. + * If you use floating point the effect is the same but takes longer. + * + * The only error-less accumulation system is to use native units, ie full + * steps and microsteps. + * + */ + +class A5995 +{ +private: + uint32_t lastStepMicros; // time in microseconds that last step happened + bool forwardRotation=true; + volatile bool enabled=true; + +public: + void begin(void); + + //moves motor where the modulo of A4954_NUM_MICROSTEPS is a full step. + int32_t move(int32_t stepAngle, uint32_t mA); + + uint32_t microsSinceStep(void) {return micros()-lastStepMicros;}; + void setRotationDirection(bool forward) {forwardRotation=forward;}; + + void enable(bool enable); + void limitCurrent(uint8_t percent) {return;}; //Not used +}; + + + +#endif /* A5995_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_GFX.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_GFX.cpp new file mode 100644 index 0000000..46d4d54 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_GFX.cpp @@ -0,0 +1,1071 @@ +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef __AVR__ + #include +#elif defined(ESP8266) + #include +#endif +#include "Adafruit_GFX.h" +#include "glcdfont.c" + +// Many (but maybe not all) non-AVR board installs define macros +// for compatibility with existing PROGMEM-reading AVR code. +// Do our own checks and defines here for good measure... + +#ifndef pgm_read_byte + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word + #define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword + #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif + +// Pointers are a peculiar case...typically 16-bit on AVR boards, +// 32 bits elsewhere. Try to accommodate both... + +#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) + #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) +#else + #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) +#endif + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } +#endif + +Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): + WIDTH(w), HEIGHT(h) +{ + _width = WIDTH; + _height = HEIGHT; + rotation = 0; + cursor_y = cursor_x = 0; + textsize = 1; + textcolor = textbgcolor = 0xFFFF; + wrap = true; + _cp437 = false; + gfxFont = NULL; +} + +// Draw a circle outline +void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + drawPixel(x0 , y0+r, color); + drawPixel(x0 , y0-r, color); + drawPixel(x0+r, y0 , color); + drawPixel(x0-r, y0 , color); + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 - x, y0 + y, color); + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 - x, y0 - y, color); + drawPixel(x0 + y, y0 + x, color); + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 + y, y0 - x, color); + drawPixel(x0 - y, y0 - x, color); + } +} + +void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, + int16_t r, uint8_t cornername, uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + drawPixel(x0 + x, y0 + y, color); + drawPixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) { + drawPixel(x0 + x, y0 - y, color); + drawPixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) { + drawPixel(x0 - y, y0 + x, color); + drawPixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) { + drawPixel(x0 - y, y0 - x, color); + drawPixel(x0 - x, y0 - y, color); + } + } +} + +void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + drawFastVLine(x0, y0-r, 2*r+1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); +} + +// Used to do circles and roundrects +void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t cornername, int16_t delta, uint16_t color) { + + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x1) { + drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); + } + if (cornername & 0x2) { + drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); + drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); + } + } +} + +// Bresenham's algorithm - thx wikpedia +void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) { + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0<=x1; x0++) { + if (steep) { + drawPixel(y0, x0, color); + } else { + drawPixel(x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +// Draw a rectangle +void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + drawFastHLine(x, y, w, color); + drawFastHLine(x, y+h-1, w, color); + drawFastVLine(x, y, h, color); + drawFastVLine(x+w-1, y, h, color); +} + +void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, + int16_t h, uint16_t color) { + // Update in subclasses if desired! + drawLine(x, y, x, y+h-1, color); +} + +void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, + int16_t w, uint16_t color) { + // Update in subclasses if desired! + drawLine(x, y, x+w-1, y, color); +} + +void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + // Update in subclasses if desired! + for (int16_t i=x; i= y1 >= y0) + if (y0 > y1) { + _swap_int16_t(y0, y1); _swap_int16_t(x0, x1); + } + if (y1 > y2) { + _swap_int16_t(y2, y1); _swap_int16_t(x2, x1); + } + if (y0 > y1) { + _swap_int16_t(y0, y1); _swap_int16_t(x0, x1); + } + + if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if(x1 < a) a = x1; + else if(x1 > b) b = x1; + if(x2 < a) a = x2; + else if(x2 > b) b = x2; + drawFastHLine(a, y0, b-a+1, color); + return; + } + + int16_t + dx01 = x1 - x0, + dy01 = y1 - y0, + dx02 = x2 - x0, + dy02 = y2 - y0, + dx12 = x2 - x1, + dy12 = y2 - y1; + int32_t + sa = 0, + sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if(y1 == y2) last = y1; // Include y1 scanline + else last = y1-1; // Skip it + + for(y=y0; y<=last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) _swap_int16_t(a,b); + drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for(; y<=y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if(a > b) _swap_int16_t(a,b); + drawFastHLine(a, y, b-a+1, color); + } +} + +// Draw a 1-bit image (bitmap) at the specified (x,y) position from the +// provided bitmap buffer (must be PROGMEM memory) using the specified +// foreground color (unset bits are transparent). +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, + const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) { + + int16_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for(j=0; j>= 1; + else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); + if(byte & 0x01) drawPixel(x+i, y+j, color); + } + } +} + +#if ARDUINO >= 100 +size_t Adafruit_GFX::write(uint8_t c) { +#else +void Adafruit_GFX::write(uint8_t c) { +#endif + + if(!gfxFont) { // 'Classic' built-in font + + if(c == '\n') { + cursor_y += textsize*8; + cursor_x = 0; + } else if(c == '\r') { + // skip em + } else { + if(wrap && ((cursor_x + textsize * 6) >= _width)) { // Heading off edge? + cursor_x = 0; // Reset x to zero + cursor_y += textsize * 8; // Advance y one line + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); + cursor_x += textsize * 6; + } + + } else { // Custom font + + if(c == '\n') { + cursor_x = 0; + cursor_y += (int16_t)textsize * + (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } else if(c != '\r') { + uint8_t first = pgm_read_byte(&gfxFont->first); + if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { + uint8_t c2 = c - pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height); + if((w > 0) && (h > 0)) { // Is there an associated bitmap? + int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic + if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) { + // Drawing character would go off right edge; wrap to new line + cursor_x = 0; + cursor_y += (int16_t)textsize * + (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); + } + cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize; + } + } + + } +#if ARDUINO >= 100 + return 1; +#endif +} + +// Draw a character +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size) { + + if(!gfxFont) { // 'Classic' built-in font + + if((x >= _width) || // Clip right + (y >= _height) || // Clip bottom + ((x + 6 * size - 1) < 0) || // Clip left + ((y + 8 * size - 1) < 0)) // Clip top + return; + + if(!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior + + for(int8_t i=0; i<6; i++ ) { + uint8_t line; + if(i < 5) line = pgm_read_byte(font+(c*5)+i); + else line = 0x0; + for(int8_t j=0; j<8; j++, line >>= 1) { + if(line & 0x1) { + if(size == 1) drawPixel(x+i, y+j, color); + else fillRect(x+(i*size), y+(j*size), size, size, color); + } else if(bg != color) { + if(size == 1) drawPixel(x+i, y+j, bg); + else fillRect(x+i*size, y+j*size, size, size, bg); + } + } + } + + } else { // Custom font + + // Character is assumed previously filtered by write() to eliminate + // newlines, returns, non-printable characters, etc. Calling drawChar() + // directly with 'bad' characters of font may cause mayhem! + + c -= pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height), + xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + uint8_t xx, yy, bits, bit = 0; + int16_t xo16, yo16; + + if(size > 1) { + xo16 = xo; + yo16 = yo; + } + + // Todo: Add character clipping here + + // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. + // THIS IS ON PURPOSE AND BY DESIGN. The background color feature + // has typically been used with the 'classic' font to overwrite old + // screen contents with new data. This ONLY works because the + // characters are a uniform size; it's not a sensible thing to do with + // proportionally-spaced fonts with glyphs of varying sizes (and that + // may overlap). To replace previously-drawn text when using a custom + // font, use the getTextBounds() function to determine the smallest + // rectangle encompassing a string, erase the area with fillRect(), + // then draw new text. This WILL infortunately 'blink' the text, but + // is unavoidable. Drawing 'background' pixels will NOT fix this, + // only creates a new set of problems. Have an idea to work around + // this (a canvas object type for MCUs that can afford the RAM and + // displays supporting setAddrWindow() and pushColors()), but haven't + // implemented this yet. + + for(yy=0; yy 0) ? s : 1; +} + +void Adafruit_GFX::setTextColor(uint16_t c) { + // For 'transparent' background, we'll set the bg + // to the same as fg instead of using a flag + textcolor = textbgcolor = c; +} + +void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { + textcolor = c; + textbgcolor = b; +} + +void Adafruit_GFX::setTextWrap(boolean w) { + wrap = w; +} + +uint8_t Adafruit_GFX::getRotation(void) const { + return rotation; +} + +void Adafruit_GFX::setRotation(uint8_t x) { + rotation = (x & 3); + switch(rotation) { + case 0: + case 2: + _width = WIDTH; + _height = HEIGHT; + break; + case 1: + case 3: + _width = HEIGHT; + _height = WIDTH; + break; + } +} + +// Enable (or disable) Code Page 437-compatible charset. +// There was an error in glcdfont.c for the longest time -- one character +// (#176, the 'light shade' block) was missing -- this threw off the index +// of every character that followed it. But a TON of code has been written +// with the erroneous character indices. By default, the library uses the +// original 'wrong' behavior and old sketches will still work. Pass 'true' +// to this function to use correct CP437 character values in your code. +void Adafruit_GFX::cp437(boolean x) { + _cp437 = x; +} + +void Adafruit_GFX::setFont(const GFXfont *f) { + if(f) { // Font struct pointer passed in? + if(!gfxFont) { // And no current font struct? + // Switching from classic to new font behavior. + // Move cursor pos down 6 pixels so it's on baseline. + cursor_y += 6; + } + } else if(gfxFont) { // NULL passed. Current font struct defined? + // Switching from new to classic font behavior. + // Move cursor pos up 6 pixels so it's at top-left of char. + cursor_y -= 6; + } + gfxFont = (GFXfont *)f; +} + +// Pass string and a cursor position, returns UL corner and W,H. +void Adafruit_GFX::getTextBounds(char *str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { + uint8_t c; // Current character + + *x1 = x; + *y1 = y; + *w = *h = 0; + + if(gfxFont) { + + GFXglyph *glyph; + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last), + gw, gh, xa; + int8_t xo, yo; + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1, + gx1, gy1, gx2, gy2, ts = (int16_t)textsize, + ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + + while((c = *str++)) { + if(c != '\n') { // Not a newline + if(c != '\r') { // Not a carriage return, is normal char + if((c >= first) && (c <= last)) { // Char present in current font + c -= first; + glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + gw = pgm_read_byte(&glyph->width); + gh = pgm_read_byte(&glyph->height); + xa = pgm_read_byte(&glyph->xAdvance); + xo = pgm_read_byte(&glyph->xOffset); + yo = pgm_read_byte(&glyph->yOffset); + if(wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) { + // Line wrap + x = 0; // Reset x to 0 + y += ya; // Advance y by 1 line + } + gx1 = x + xo * ts; + gy1 = y + yo * ts; + gx2 = gx1 + gw * ts - 1; + gy2 = gy1 + gh * ts - 1; + if(gx1 < minx) minx = gx1; + if(gy1 < miny) miny = gy1; + if(gx2 > maxx) maxx = gx2; + if(gy2 > maxy) maxy = gy2; + x += xa * ts; + } + } // Carriage return = do nothing + } else { // Newline + x = 0; // Reset x + y += ya; // Advance y by 1 line + } + } + // End of string + *x1 = minx; + *y1 = miny; + if(maxx >= minx) *w = maxx - minx + 1; + if(maxy >= miny) *h = maxy - miny + 1; + + } else { // Default font + + uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines + + while((c = *str++)) { + if(c != '\n') { // Not a newline + if(c != '\r') { // Not a carriage return, is normal char + if(wrap && ((x + textsize * 6) >= _width)) { + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line + lineWidth = textsize * 6; // First char on new line + } else { // No line wrap, just keep incrementing X + lineWidth += textsize * 6; // Includes interchar x gap + } + } // Carriage return = do nothing + } else { // Newline + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line + lineWidth = 0; // Reset lineWidth for new line + } + } + // End of string + if(lineWidth) y += textsize * 8; // Add height of last (or only) line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest? + *w = maxWidth - 1; // Don't include last interchar x gap + *h = y - *y1; + + } // End classic vs custom font +} + +// Same as above, but for PROGMEM strings +void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, + int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { + uint8_t *s = (uint8_t *)str, c; + + *x1 = x; + *y1 = y; + *w = *h = 0; + + if(gfxFont) { + + GFXglyph *glyph; + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last), + gw, gh, xa; + int8_t xo, yo; + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1, + gx1, gy1, gx2, gy2, ts = (int16_t)textsize, + ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + + while((c = pgm_read_byte(s++))) { + if(c != '\n') { // Not a newline + if(c != '\r') { // Not a carriage return, is normal char + if((c >= first) && (c <= last)) { // Char present in current font + c -= first; + glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + gw = pgm_read_byte(&glyph->width); + gh = pgm_read_byte(&glyph->height); + xa = pgm_read_byte(&glyph->xAdvance); + xo = pgm_read_byte(&glyph->xOffset); + yo = pgm_read_byte(&glyph->yOffset); + if(wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) { + // Line wrap + x = 0; // Reset x to 0 + y += ya; // Advance y by 1 line + } + gx1 = x + xo * ts; + gy1 = y + yo * ts; + gx2 = gx1 + gw * ts - 1; + gy2 = gy1 + gh * ts - 1; + if(gx1 < minx) minx = gx1; + if(gy1 < miny) miny = gy1; + if(gx2 > maxx) maxx = gx2; + if(gy2 > maxy) maxy = gy2; + x += xa * ts; + } + } // Carriage return = do nothing + } else { // Newline + x = 0; // Reset x + y += ya; // Advance y by 1 line + } + } + // End of string + *x1 = minx; + *y1 = miny; + if(maxx >= minx) *w = maxx - minx + 1; + if(maxy >= miny) *h = maxy - miny + 1; + + } else { // Default font + + uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines + + while((c = pgm_read_byte(s++))) { + if(c != '\n') { // Not a newline + if(c != '\r') { // Not a carriage return, is normal char + if(wrap && ((x + textsize * 6) >= _width)) { + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line + lineWidth = textsize * 6; // First char on new line + } else { // No line wrap, just keep incrementing X + lineWidth += textsize * 6; // Includes interchar x gap + } + } // Carriage return = do nothing + } else { // Newline + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line + lineWidth = 0; // Reset lineWidth for new line + } + } + // End of string + if(lineWidth) y += textsize * 8; // Add height of last (or only) line + if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest? + *w = maxWidth - 1; // Don't include last interchar x gap + *h = y - *y1; + + } // End classic vs custom font +} + +// Return the size of the display (per current rotation) +int16_t Adafruit_GFX::width(void) const { + return _width; +} + +int16_t Adafruit_GFX::height(void) const { + return _height; +} + +void Adafruit_GFX::invertDisplay(boolean i) { + // Do nothing, must be subclassed if supported by hardware +} + +/***************************************************************************/ +// code for the GFX button UI element + +Adafruit_GFX_Button::Adafruit_GFX_Button(void) { + _gfx = 0; +} + +void Adafruit_GFX_Button::initButton( + Adafruit_GFX *gfx, int16_t x, int16_t y, uint8_t w, uint8_t h, + uint16_t outline, uint16_t fill, uint16_t textcolor, + char *label, uint8_t textsize) +{ + _x = x; + _y = y; + _w = w; + _h = h; + _outlinecolor = outline; + _fillcolor = fill; + _textcolor = textcolor; + _textsize = textsize; + _gfx = gfx; + strncpy(_label, label, 9); + _label[9] = 0; +} + +void Adafruit_GFX_Button::drawButton(boolean inverted) { + uint16_t fill, outline, text; + + if(!inverted) { + fill = _fillcolor; + outline = _outlinecolor; + text = _textcolor; + } else { + fill = _textcolor; + outline = _outlinecolor; + text = _fillcolor; + } + + _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill); + _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline); + + _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize); + _gfx->setTextColor(text); + _gfx->setTextSize(_textsize); + _gfx->print(_label); +} + +boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y) { + if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false; + if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false; + return true; +} + +void Adafruit_GFX_Button::press(boolean p) { + laststate = currstate; + currstate = p; +} + +boolean Adafruit_GFX_Button::isPressed() { return currstate; } +boolean Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); } +boolean Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); } + +// ------------------------------------------------------------------------- + +// GFXcanvas1 and GFXcanvas16 (currently a WIP, don't get too comfy with the +// implementation) provide 1- and 16-bit offscreen canvases, the address of +// which can be passed to drawBitmap() or pushColors() (the latter appears +// to only be in Adafruit_TFTLCD at this time). This is here mostly to +// help with the recently-added proportionally-spaced fonts; adds a way to +// refresh a section of the screen without a massive flickering clear-and- +// redraw...but maybe you'll find other uses too. VERY RAM-intensive, since +// the buffer is in MCU memory and not the display driver...GXFcanvas1 might +// be minimally useful on an Uno-class board, but this and GFXcanvas16 are +// much more likely to require at least a Mega or various recent ARM-type +// boards (recomment, as the text+bitmap draw can be pokey). GFXcanvas1 +// requires 1 bit per pixel (rounded up to nearest byte per scanline), +// GFXcanvas16 requires 2 bytes per pixel (no scanline pad). +// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND. + +GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint16_t bytes = ((w + 7) / 8) * h; + if((buffer = (uint8_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +GFXcanvas1::~GFXcanvas1(void) { + if(buffer) free(buffer); +} + +uint8_t* GFXcanvas1::getBuffer(void) { + return buffer; +} + +void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) { + // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR + static const uint8_t PROGMEM + GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, + GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE }; + + if(buffer) { + if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return; + + int16_t t; + switch(rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; + if(color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]); + else *ptr &= pgm_read_byte(&GFXclrBit[x & 7]); + } +} + +void GFXcanvas1::fillScreen(uint16_t color) { + if(buffer) { + uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT; + memset(buffer, color ? 0xFF : 0x00, bytes); + } +} + +GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint16_t bytes = w * h * 2; + if((buffer = (uint16_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +GFXcanvas16::~GFXcanvas16(void) { + if(buffer) free(buffer); +} + +uint16_t* GFXcanvas16::getBuffer(void) { + return buffer; +} + +void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) { + if(buffer) { + if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return; + + int16_t t; + switch(rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + buffer[x + y * WIDTH] = color; + } +} + +void GFXcanvas16::fillScreen(uint16_t color) { + if(buffer) { + uint8_t hi = color >> 8, lo = color & 0xFF; + if(hi == lo) { + memset(buffer, lo, WIDTH * HEIGHT * 2); + } else { + uint16_t i, pixels = WIDTH * HEIGHT; + for(i=0; i= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif + +#include "gfxfont.h" + +class Adafruit_GFX : public Print { + + public: + + Adafruit_GFX(int16_t w, int16_t h); // Constructor + + // This MUST be defined by the subclass: + virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; + + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void + drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color), + drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color), + drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color), + drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), + fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color), + fillScreen(uint16_t color), + invertDisplay(boolean i); + + // These exist only with Adafruit_GFX (no subclass overrides) + void + drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), + drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + uint16_t color), + fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), + fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, + int16_t delta, uint16_t color), + drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color), + fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color), + drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color), + fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, + int16_t radius, uint16_t color), + drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color), + drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color, uint16_t bg), + drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color), + drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color, uint16_t bg), + drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, + int16_t w, int16_t h, uint16_t color), + drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, + uint16_t bg, uint8_t size), + setCursor(int16_t x, int16_t y), + setTextColor(uint16_t c), + setTextColor(uint16_t c, uint16_t bg), + setTextSize(uint8_t s), + setTextWrap(boolean w), + setRotation(uint8_t r), + cp437(boolean x=true), + setFont(const GFXfont *f = NULL), + getTextBounds(char *string, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h), + getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + +#if ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + + int16_t height(void) const; + int16_t width(void) const; + + uint8_t getRotation(void) const; + + // get current cursor position (get rotation safe maximum values, using: width() for x, height() for y) + int16_t getCursorX(void) const; + int16_t getCursorY(void) const; + + protected: + const int16_t + WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes + int16_t + _width, _height, // Display w/h as modified by current rotation + cursor_x, cursor_y; + uint16_t + textcolor, textbgcolor; + uint8_t + textsize, + rotation; + boolean + wrap, // If set, 'wrap' text at right edge of display + _cp437; // If set, use correct CP437 charset (default is off) + GFXfont + *gfxFont; +}; + +class Adafruit_GFX_Button { + + public: + Adafruit_GFX_Button(void); + void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, + uint8_t w, uint8_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize); + void drawButton(boolean inverted = false); + boolean contains(int16_t x, int16_t y); + + void press(boolean p); + boolean isPressed(); + boolean justPressed(); + boolean justReleased(); + + private: + Adafruit_GFX *_gfx; + int16_t _x, _y; + uint16_t _w, _h; + uint8_t _textsize; + uint16_t _outlinecolor, _fillcolor, _textcolor; + char _label[10]; + + boolean currstate, laststate; +}; + +class GFXcanvas1 : public Adafruit_GFX { + + public: + GFXcanvas1(uint16_t w, uint16_t h); + ~GFXcanvas1(void); + void drawPixel(int16_t x, int16_t y, uint16_t color), + fillScreen(uint16_t color); + uint8_t *getBuffer(void); + private: + uint8_t *buffer; +}; + +class GFXcanvas16 : public Adafruit_GFX { + GFXcanvas16(uint16_t w, uint16_t h); + ~GFXcanvas16(void); + void drawPixel(int16_t x, int16_t y, uint16_t color), + fillScreen(uint16_t color); + uint16_t *getBuffer(void); + private: + uint16_t *buffer; +}; + +#endif // _ADAFRUIT_GFX_H diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.cpp new file mode 100644 index 0000000..2a78892 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.cpp @@ -0,0 +1,750 @@ +/********************************************************************* +This is a library for our Monochrome OLEDs based on SSD1306 drivers + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/category/63_98 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen below must be included in any redistribution + *********************************************************************/ + +#ifdef __AVR__ +#include +#elif defined(ESP8266) +#include +#else +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif + +#if !defined(__ARM_ARCH) && !defined(ENERGIA) && !defined(ESP8266) +#include +#endif + +#include + +#include +#include +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" +#include "syslog.h" + +// the memory buffer for the LCD + +static uint8_t buffer[SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH / 8] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x80, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xF8, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0xFF, +#if (SSD1306_LCDHEIGHT * SSD1306_LCDWIDTH > 96*16) + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, + 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x8C, 0x8E, 0x84, 0x00, 0x00, 0x80, 0xF8, + 0xF8, 0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xE0, 0xE0, 0xC0, 0x80, + 0x00, 0xE0, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0x01, 0x01, + 0x01, 0x01, 0x83, 0xFF, 0xFF, 0x00, 0x00, 0x7C, 0xFE, 0xC7, 0x01, 0x01, 0x01, 0x01, 0x83, 0xFF, + 0xFF, 0xFF, 0x00, 0x38, 0xFE, 0xC7, 0x83, 0x01, 0x01, 0x01, 0x83, 0xC7, 0xFF, 0xFF, 0x00, 0x00, + 0x01, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0xFF, 0xFF, 0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x7F, 0xFF, + 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0xFF, + 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x0F, 0x3F, 0x7F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xC7, 0xC7, 0x8F, + 0x8F, 0x9F, 0xBF, 0xFF, 0xFF, 0xC3, 0xC0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFC, 0xFC, + 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF8, 0xF0, 0xF0, 0xE0, 0xC0, 0x00, 0x01, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x01, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +#if (SSD1306_LCDHEIGHT == 64) + 0x00, 0x00, 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x1F, 0x0F, + 0x87, 0xC7, 0xF7, 0xFF, 0xFF, 0x1F, 0x1F, 0x3D, 0xFC, 0xF8, 0xF8, 0xF8, 0xF8, 0x7C, 0x7D, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x0F, 0x07, 0x00, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x3F, 0x1F, + 0x0F, 0x07, 0x1F, 0x7F, 0xFF, 0xFF, 0xF8, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xF8, 0xE0, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, + 0x00, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x0E, 0xFC, 0xF8, 0x00, 0x00, 0xF0, 0xF8, 0x1C, 0x0E, + 0x06, 0x06, 0x06, 0x0C, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0xFE, 0xFC, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0xE6, 0xCE, 0x84, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0x06, + 0x06, 0xFC, 0xFE, 0xFC, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00, 0xC0, 0xF8, + 0xFC, 0x4E, 0x46, 0x46, 0x46, 0x4E, 0x7C, 0x78, 0x40, 0x18, 0x3C, 0x76, 0xE6, 0xCE, 0xCC, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x0F, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, + 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x07, 0x0E, 0x0C, + 0x18, 0x18, 0x0C, 0x06, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, + 0x07, 0x01, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, + 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x07, + 0x07, 0x0C, 0x0C, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x00, 0x04, 0x0E, 0x0C, 0x18, 0x0C, 0x0F, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#endif +#endif +}; + +#define ssd1306_swap(a, b) { int16_t t = a; a = b; b = t; } + +// the most basic function, set a single pixel +void Adafruit_SSD1306::drawPixel(int16_t x, int16_t y, uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) + return; + + // check rotation, move pixel around if necessary + switch (getRotation()) { + case 1: + ssd1306_swap(x, y); + x = WIDTH - x - 1; + break; + case 2: + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + break; + case 3: + ssd1306_swap(x, y); + y = HEIGHT - y - 1; + break; + } + + // x is which column + switch (color) + { + case WHITE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] |= (1 << (y&7)); break; + case BLACK: buffer[x+ (y/8)*SSD1306_LCDWIDTH] &= ~(1 << (y&7)); break; + case INVERSE: buffer[x+ (y/8)*SSD1306_LCDWIDTH] ^= (1 << (y&7)); break; + } + +} + +Adafruit_SSD1306::Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { + cs = CS; + rst = RST; + dc = DC; + sclk = SCLK; + sid = SID; + hwSPI = false; +} + +// constructor for hardware SPI - we indicate DataCommand, ChipSelect, Reset +Adafruit_SSD1306::Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS) : Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { + dc = DC; + rst = RST; + cs = CS; + hwSPI = true; +} + +// initializer for I2C - we only indicate the reset pin! +Adafruit_SSD1306::Adafruit_SSD1306(int8_t reset) : + Adafruit_GFX(SSD1306_LCDWIDTH, SSD1306_LCDHEIGHT) { + sclk = dc = cs = sid = -1; + rst = reset; +} + + +bool Adafruit_SSD1306::begin(uint8_t vccstate, uint8_t i2caddr, bool reset) { + _vccstate = vccstate; + _i2caddr = i2caddr; + + // set pin directions + if (sid != -1){ + pinMode(dc, OUTPUT); + pinMode(cs, OUTPUT); +#ifdef HAVE_PORTREG + csport = portOutputRegister(digitalPinToPort(cs)); + cspinmask = digitalPinToBitMask(cs); + dcport = portOutputRegister(digitalPinToPort(dc)); + dcpinmask = digitalPinToBitMask(dc); +#endif + if (!hwSPI){ + // set pins for software-SPI + pinMode(sid, OUTPUT); + pinMode(sclk, OUTPUT); +#ifdef HAVE_PORTREG + clkport = portOutputRegister(digitalPinToPort(sclk)); + clkpinmask = digitalPinToBitMask(sclk); + mosiport = portOutputRegister(digitalPinToPort(sid)); + mosipinmask = digitalPinToBitMask(sid); +#endif + } + if (hwSPI){ + SPI.begin(); +#ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); +#else + SPI.setClockDivider (4); +#endif + } + } + else + { + // I2C Init + Wire.begin(); +#ifdef __SAM3X8E__ + // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL) + TWI1->TWI_CWGR = 0; + TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101; +#endif + } + if ((reset) && (rst >= 0)) { + // Setup reset pin direction (used by both SPI and I2C) + pinMode(rst, OUTPUT); + digitalWrite(rst, HIGH); + // VDD (3.3V) goes high at start, lets just chill for a ms + delay(1); + // bring reset low + digitalWrite(rst, LOW); + // wait 10ms + delay(10); + // bring out of reset + digitalWrite(rst, HIGH); + // turn on VCC (9V?) + } + + uint8_t ret; + // Init sequence + LOG("Sending LCD display off"); + ret=ssd1306_command(SSD1306_DISPLAYOFF); // 0xAE + LOG("Display off returned %d",ret); + if (ret != 0) + { + + return false; + } + ssd1306_command(SSD1306_SETDISPLAYCLOCKDIV); // 0xD5 + ssd1306_command(0x80); // the suggested ratio 0x80 + + ssd1306_command(SSD1306_SETMULTIPLEX); // 0xA8 + ssd1306_command(SSD1306_LCDHEIGHT - 1); + + ssd1306_command(SSD1306_SETDISPLAYOFFSET); // 0xD3 + ssd1306_command(0x0); // no offset + ssd1306_command(SSD1306_SETSTARTLINE | 0x0); // line #0 + ssd1306_command(SSD1306_CHARGEPUMP); // 0x8D + if (vccstate == SSD1306_EXTERNALVCC) + { ssd1306_command(0x10); } + else + { ssd1306_command(0x14); } + ssd1306_command(SSD1306_MEMORYMODE); // 0x20 + ssd1306_command(0x00); // 0x0 act like ks0108 + ssd1306_command(SSD1306_SEGREMAP | 0x1); + ssd1306_command(SSD1306_COMSCANDEC); + +#if defined SSD1306_128_32 + ssd1306_command(SSD1306_SETCOMPINS); // 0xDA + ssd1306_command(0x02); + ssd1306_command(SSD1306_SETCONTRAST); // 0x81 + ssd1306_command(0x8F); + +#elif defined SSD1306_128_64 + ssd1306_command(SSD1306_SETCOMPINS); // 0xDA + ssd1306_command(0x12); + ssd1306_command(SSD1306_SETCONTRAST); // 0x81 + if (vccstate == SSD1306_EXTERNALVCC) + { ssd1306_command(0x9F); } + else + { ssd1306_command(0xCF); } + +#elif defined SSD1306_96_16 + ssd1306_command(SSD1306_SETCOMPINS); // 0xDA + ssd1306_command(0x2); //ada x12 + ssd1306_command(SSD1306_SETCONTRAST); // 0x81 + if (vccstate == SSD1306_EXTERNALVCC) + { ssd1306_command(0x10); } + else + { ssd1306_command(0xAF); } + +#endif + + ssd1306_command(SSD1306_SETPRECHARGE); // 0xd9 + if (vccstate == SSD1306_EXTERNALVCC) + { ssd1306_command(0x22); } + else + { ssd1306_command(0xF1); } + ssd1306_command(SSD1306_SETVCOMDETECT); // 0xDB + ssd1306_command(0x40); + ssd1306_command(SSD1306_DISPLAYALLON_RESUME); // 0xA4 + ssd1306_command(SSD1306_NORMALDISPLAY); // 0xA6 + + ssd1306_command(SSD1306_DEACTIVATE_SCROLL); + + ssd1306_command(SSD1306_DISPLAYON);//--turn on oled panel + return true; +} + + +void Adafruit_SSD1306::invertDisplay(uint8_t i) { + if (i) { + ssd1306_command(SSD1306_INVERTDISPLAY); + } else { + ssd1306_command(SSD1306_NORMALDISPLAY); + } +} + +// Errors: +// 0 : Success +// 1 : Data too long +// 2 : NACK on transmit of address +// 3 : NACK on transmit of data +// 4 : Other error +uint8_t Adafruit_SSD1306::ssd1306_command(uint8_t c) { + if (sid != -1) + { + // SPI +#ifdef HAVE_PORTREG + *csport |= cspinmask; + *dcport &= ~dcpinmask; + *csport &= ~cspinmask; +#else + digitalWrite(cs, HIGH); + digitalWrite(dc, LOW); + digitalWrite(cs, LOW); +#endif + fastSPIwrite(c); +#ifdef HAVE_PORTREG + *csport |= cspinmask; +#else + digitalWrite(cs, HIGH); +#endif + } + else + { + // I2C + uint8_t control = 0x00; // Co = 0, D/C = 0 + //LOG("wire begin"); + Wire.beginTransmission(_i2caddr); + //LOG("wire write"); + Wire.write(control); + //LOG("wire write c"); + Wire.write(c); + //LOG("wire end"); + Wire.endTransmission(); + //LOG("wire done"); + } +} + +// startscrollright +// Activate a right handed scroll for rows start through stop +// Hint, the display is 16 rows tall. To scroll the whole display, run: +// display.scrollright(0x00, 0x0F) +void Adafruit_SSD1306::startscrollright(uint8_t start, uint8_t stop){ + ssd1306_command(SSD1306_RIGHT_HORIZONTAL_SCROLL); + ssd1306_command(0X00); + ssd1306_command(start); + ssd1306_command(0X00); + ssd1306_command(stop); + ssd1306_command(0X00); + ssd1306_command(0XFF); + ssd1306_command(SSD1306_ACTIVATE_SCROLL); +} + +// startscrollleft +// Activate a right handed scroll for rows start through stop +// Hint, the display is 16 rows tall. To scroll the whole display, run: +// display.scrollright(0x00, 0x0F) +void Adafruit_SSD1306::startscrollleft(uint8_t start, uint8_t stop){ + ssd1306_command(SSD1306_LEFT_HORIZONTAL_SCROLL); + ssd1306_command(0X00); + ssd1306_command(start); + ssd1306_command(0X00); + ssd1306_command(stop); + ssd1306_command(0X00); + ssd1306_command(0XFF); + ssd1306_command(SSD1306_ACTIVATE_SCROLL); +} + +// startscrolldiagright +// Activate a diagonal scroll for rows start through stop +// Hint, the display is 16 rows tall. To scroll the whole display, run: +// display.scrollright(0x00, 0x0F) +void Adafruit_SSD1306::startscrolldiagright(uint8_t start, uint8_t stop){ + ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); + ssd1306_command(0X00); + ssd1306_command(SSD1306_LCDHEIGHT); + ssd1306_command(SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL); + ssd1306_command(0X00); + ssd1306_command(start); + ssd1306_command(0X00); + ssd1306_command(stop); + ssd1306_command(0X01); + ssd1306_command(SSD1306_ACTIVATE_SCROLL); +} + +// startscrolldiagleft +// Activate a diagonal scroll for rows start through stop +// Hint, the display is 16 rows tall. To scroll the whole display, run: +// display.scrollright(0x00, 0x0F) +void Adafruit_SSD1306::startscrolldiagleft(uint8_t start, uint8_t stop){ + ssd1306_command(SSD1306_SET_VERTICAL_SCROLL_AREA); + ssd1306_command(0X00); + ssd1306_command(SSD1306_LCDHEIGHT); + ssd1306_command(SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL); + ssd1306_command(0X00); + ssd1306_command(start); + ssd1306_command(0X00); + ssd1306_command(stop); + ssd1306_command(0X01); + ssd1306_command(SSD1306_ACTIVATE_SCROLL); +} + +void Adafruit_SSD1306::stopscroll(void){ + ssd1306_command(SSD1306_DEACTIVATE_SCROLL); +} + +// Dim the display +// dim = true: display is dimmed +// dim = false: display is normal +void Adafruit_SSD1306::dim(boolean dim) { + uint8_t contrast; + + if (dim) { + contrast = 0; // Dimmed display + } else { + if (_vccstate == SSD1306_EXTERNALVCC) { + contrast = 0x9F; + } else { + contrast = 0xCF; + } + } + // the range of contrast to too small to be really useful + // it is useful to dim the display + ssd1306_command(SSD1306_SETCONTRAST); + ssd1306_command(contrast); +} + +void Adafruit_SSD1306::display(void) { + ssd1306_command(SSD1306_COLUMNADDR); + ssd1306_command(0); // Column start address (0 = reset) + ssd1306_command(SSD1306_LCDWIDTH-1); // Column end address (127 = reset) + + ssd1306_command(SSD1306_PAGEADDR); + ssd1306_command(0); // Page start address (0 = reset) +#if SSD1306_LCDHEIGHT == 64 + ssd1306_command(7); // Page end address +#endif +#if SSD1306_LCDHEIGHT == 32 + ssd1306_command(3); // Page end address +#endif +#if SSD1306_LCDHEIGHT == 16 + ssd1306_command(1); // Page end address +#endif + + if (sid != -1) + { + // SPI +#ifdef HAVE_PORTREG + *csport |= cspinmask; + *dcport |= dcpinmask; + *csport &= ~cspinmask; +#else + digitalWrite(cs, HIGH); + digitalWrite(dc, HIGH); + digitalWrite(cs, LOW); +#endif + + for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { + fastSPIwrite(buffer[i]); + } +#ifdef HAVE_PORTREG + *csport |= cspinmask; +#else + digitalWrite(cs, HIGH); +#endif + } + else + { + // save I2C bitrate +#ifdef TWBR + uint8_t twbrbackup = TWBR; + TWBR = 12; // upgrade to 400KHz! +#endif + + //Serial.println(TWBR, DEC); + //Serial.println(TWSR & 0x3, DEC); + + // I2C + for (uint16_t i=0; i<(SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) { + // send a bunch of data in one xmission + Wire.beginTransmission(_i2caddr); + WIRE_WRITE(0x40); + for (uint8_t x=0; x<16; x++) { + WIRE_WRITE(buffer[i]); + i++; + } + i--; + Wire.endTransmission(); + } +#ifdef TWBR + TWBR = twbrbackup; +#endif + } +} + +// clear everything +void Adafruit_SSD1306::clearDisplay(void) { + memset(buffer, 0, (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8)); +} + + +inline void Adafruit_SSD1306::fastSPIwrite(uint8_t d) { + + if(hwSPI) { + (void)SPI.transfer(d); + } else { + for(uint8_t bit = 0x80; bit; bit >>= 1) { +#ifdef HAVE_PORTREG + *clkport &= ~clkpinmask; + if(d & bit) *mosiport |= mosipinmask; + else *mosiport &= ~mosipinmask; + *clkport |= clkpinmask; +#else + digitalWrite(sclk, LOW); + if(d & bit) digitalWrite(sid, HIGH); + else digitalWrite(sid, LOW); + digitalWrite(sclk, HIGH); +#endif + } + } +} + +void Adafruit_SSD1306::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { + boolean bSwap = false; + switch(rotation) { + case 0: + // 0 degree rotation, do nothing + break; + case 1: + // 90 degree rotation, swap x & y for rotation, then invert x + bSwap = true; + ssd1306_swap(x, y); + x = WIDTH - x - 1; + break; + case 2: + // 180 degree rotation, invert x and y - then shift y around for height. + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + x -= (w-1); + break; + case 3: + // 270 degree rotation, swap x & y for rotation, then invert y and adjust y for w (not to become h) + bSwap = true; + ssd1306_swap(x, y); + y = HEIGHT - y - 1; + y -= (w-1); + break; + } + + if(bSwap) { + drawFastVLineInternal(x, y, w, color); + } else { + drawFastHLineInternal(x, y, w, color); + } +} + +void Adafruit_SSD1306::drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) { + // Do bounds/limit checks + if(y < 0 || y >= HEIGHT) { return; } + + // make sure we don't try to draw below 0 + if(x < 0) { + w += x; + x = 0; + } + + // make sure we don't go off the edge of the display + if( (x + w) > WIDTH) { + w = (WIDTH - x); + } + + // if our width is now negative, punt + if(w <= 0) { return; } + + // set up the pointer for movement through the buffer + register uint8_t *pBuf = buffer; + // adjust the buffer pointer for the current row + pBuf += ((y/8) * SSD1306_LCDWIDTH); + // and offset x columns in + pBuf += x; + + register uint8_t mask = 1 << (y&7); + + switch (color) + { + case WHITE: while(w--) { *pBuf++ |= mask; }; break; + case BLACK: mask = ~mask; while(w--) { *pBuf++ &= mask; }; break; + case INVERSE: while(w--) { *pBuf++ ^= mask; }; break; + } +} + +void Adafruit_SSD1306::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { + bool bSwap = false; + switch(rotation) { + case 0: + break; + case 1: + // 90 degree rotation, swap x & y for rotation, then invert x and adjust x for h (now to become w) + bSwap = true; + ssd1306_swap(x, y); + x = WIDTH - x - 1; + x -= (h-1); + break; + case 2: + // 180 degree rotation, invert x and y - then shift y around for height. + x = WIDTH - x - 1; + y = HEIGHT - y - 1; + y -= (h-1); + break; + case 3: + // 270 degree rotation, swap x & y for rotation, then invert y + bSwap = true; + ssd1306_swap(x, y); + y = HEIGHT - y - 1; + break; + } + + if(bSwap) { + drawFastHLineInternal(x, y, h, color); + } else { + drawFastVLineInternal(x, y, h, color); + } +} + + +void Adafruit_SSD1306::drawFastVLineInternal(int16_t x, int16_t __y, int16_t __h, uint16_t color) { + + // do nothing if we're off the left or right side of the screen + if(x < 0 || x >= WIDTH) { return; } + + // make sure we don't try to draw below 0 + if(__y < 0) { + // __y is negative, this will subtract enough from __h to account for __y being 0 + __h += __y; + __y = 0; + + } + + // make sure we don't go past the height of the display + if( (__y + __h) > HEIGHT) { + __h = (HEIGHT - __y); + } + + // if our height is now negative, punt + if(__h <= 0) { + return; + } + + // this display doesn't need ints for coordinates, use local byte registers for faster juggling + register uint8_t y = __y; + register uint8_t h = __h; + + + // set up the pointer for fast movement through the buffer + register uint8_t *pBuf = buffer; + // adjust the buffer pointer for the current row + pBuf += ((y/8) * SSD1306_LCDWIDTH); + // and offset x columns in + pBuf += x; + + // do the first partial byte, if necessary - this requires some masking + register uint8_t mod = (y&7); + if(mod) { + // mask off the high n bits we want to set + mod = 8-mod; + + // note - lookup table results in a nearly 10% performance improvement in fill* functions + // register uint8_t mask = ~(0xFF >> (mod)); + static uint8_t premask[8] = {0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + register uint8_t mask = premask[mod]; + + // adjust the mask if we're not going to reach the end of this byte + if( h < mod) { + mask &= (0XFF >> (mod-h)); + } + + switch (color) + { + case WHITE: *pBuf |= mask; break; + case BLACK: *pBuf &= ~mask; break; + case INVERSE: *pBuf ^= mask; break; + } + + // fast exit if we're done here! + if(h= 8) { + if (color == INVERSE) { // separate copy of the code so we don't impact performance of the black/white write version with an extra comparison per loop + do { + *pBuf=~(*pBuf); + + // adjust the buffer forward 8 rows worth of data + pBuf += SSD1306_LCDWIDTH; + + // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) + h -= 8; + } while(h >= 8); + } + else { + // store a local value to work with + register uint8_t val = (color == WHITE) ? 255 : 0; + + do { + // write our value in + *pBuf = val; + + // adjust the buffer forward 8 rows worth of data + pBuf += SSD1306_LCDWIDTH; + + // adjust h & y (there's got to be a faster way for me to do this, but this should still help a fair bit for now) + h -= 8; + } while(h >= 8); + } + } + + // now do the final partial byte, if necessary + if(h) { + mod = h & 7; + // this time we want to mask the low bits of the byte, vs the high bits we did above + // register uint8_t mask = (1 << mod) - 1; + // note - lookup table results in a nearly 10% performance improvement in fill* functions + static uint8_t postmask[8] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; + register uint8_t mask = postmask[mod]; + switch (color) + { + case WHITE: *pBuf |= mask; break; + case BLACK: *pBuf &= ~mask; break; + case INVERSE: *pBuf ^= mask; break; + } + } +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.h b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.h new file mode 100644 index 0000000..7d7a5fe --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/Adafruit_SSD1306.h @@ -0,0 +1,182 @@ +/********************************************************************* +This is a library for our Monochrome OLEDs based on SSD1306 drivers + + Pick one up today in the adafruit shop! + ------> http://www.adafruit.com/category/63_98 + +These displays use SPI to communicate, 4 or 5 pins are required to +interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above, and the splash screen must be included in any redistribution +*********************************************************************/ +#ifndef _Adafruit_SSD1306_H_ +#define _Adafruit_SSD1306_H_ + +#if ARDUINO >= 100 + #include "Arduino.h" + #define WIRE_WRITE Wire.write +#else + #include "WProgram.h" + #define WIRE_WRITE Wire.send +#endif + +#if defined(__SAM3X8E__) + typedef volatile RwReg PortReg; + typedef uint32_t PortMask; + #define HAVE_PORTREG +#elif defined(ARDUINO_ARCH_SAMD) +// not supported +#elif defined(ESP8266) || defined(ARDUINO_STM32_FEATHER) + typedef volatile uint32_t PortReg; + typedef uint32_t PortMask; +#else + typedef volatile uint8_t PortReg; + typedef uint8_t PortMask; + #define HAVE_PORTREG +#endif + +#include +#include "Adafruit_GFX.h" + +#define BLACK 0 +#define WHITE 1 +#define INVERSE 2 + +#define SSD1306_I2C_ADDRESS 0x3C // 011110+SA0+RW - 0x3C or 0x3D +// Address for 128x32 is 0x3C +// Address for 128x64 is 0x3D (default) or 0x3C (if SA0 is grounded) + +/*========================================================================= + SSD1306 Displays + ----------------------------------------------------------------------- + The driver is used in multiple displays (128x64, 128x32, etc.). + Select the appropriate display below to create an appropriately + sized framebuffer, etc. + + SSD1306_128_64 128x64 pixel display + + SSD1306_128_32 128x32 pixel display + + SSD1306_96_16 + + -----------------------------------------------------------------------*/ + #define SSD1306_128_64 +// #define SSD1306_128_32 +// #define SSD1306_96_16 +/*=========================================================================*/ + +#if defined SSD1306_128_64 && defined SSD1306_128_32 + #error "Only one SSD1306 display can be specified at once in SSD1306.h" +#endif +#if !defined SSD1306_128_64 && !defined SSD1306_128_32 && !defined SSD1306_96_16 + #error "At least one SSD1306 display must be specified in SSD1306.h" +#endif + +#if defined SSD1306_128_64 + #define SSD1306_LCDWIDTH 128 + #define SSD1306_LCDHEIGHT 64 +#endif +#if defined SSD1306_128_32 + #define SSD1306_LCDWIDTH 128 + #define SSD1306_LCDHEIGHT 32 +#endif +#if defined SSD1306_96_16 + #define SSD1306_LCDWIDTH 96 + #define SSD1306_LCDHEIGHT 16 +#endif + +#define SSD1306_SETCONTRAST 0x81 +#define SSD1306_DISPLAYALLON_RESUME 0xA4 +#define SSD1306_DISPLAYALLON 0xA5 +#define SSD1306_NORMALDISPLAY 0xA6 +#define SSD1306_INVERTDISPLAY 0xA7 +#define SSD1306_DISPLAYOFF 0xAE +#define SSD1306_DISPLAYON 0xAF + +#define SSD1306_SETDISPLAYOFFSET 0xD3 +#define SSD1306_SETCOMPINS 0xDA + +#define SSD1306_SETVCOMDETECT 0xDB + +#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 +#define SSD1306_SETPRECHARGE 0xD9 + +#define SSD1306_SETMULTIPLEX 0xA8 + +#define SSD1306_SETLOWCOLUMN 0x00 +#define SSD1306_SETHIGHCOLUMN 0x10 + +#define SSD1306_SETSTARTLINE 0x40 + +#define SSD1306_MEMORYMODE 0x20 +#define SSD1306_COLUMNADDR 0x21 +#define SSD1306_PAGEADDR 0x22 + +#define SSD1306_COMSCANINC 0xC0 +#define SSD1306_COMSCANDEC 0xC8 + +#define SSD1306_SEGREMAP 0xA0 + +#define SSD1306_CHARGEPUMP 0x8D + +#define SSD1306_EXTERNALVCC 0x1 +#define SSD1306_SWITCHCAPVCC 0x2 + +// Scrolling #defines +#define SSD1306_ACTIVATE_SCROLL 0x2F +#define SSD1306_DEACTIVATE_SCROLL 0x2E +#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3 +#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26 +#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27 +#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29 +#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A + +class Adafruit_SSD1306 : public Adafruit_GFX { + public: + Adafruit_SSD1306(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS); + Adafruit_SSD1306(int8_t DC, int8_t RST, int8_t CS); + Adafruit_SSD1306(int8_t RST = -1); + + bool begin(uint8_t switchvcc = SSD1306_SWITCHCAPVCC, uint8_t i2caddr = SSD1306_I2C_ADDRESS, bool reset=true); + uint8_t ssd1306_command(uint8_t c); + + void clearDisplay(void); + void invertDisplay(uint8_t i); + void display(); + + void startscrollright(uint8_t start, uint8_t stop); + void startscrollleft(uint8_t start, uint8_t stop); + + void startscrolldiagright(uint8_t start, uint8_t stop); + void startscrolldiagleft(uint8_t start, uint8_t stop); + void stopscroll(void); + + void dim(boolean dim); + + void drawPixel(int16_t x, int16_t y, uint16_t color); + + virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + private: + int8_t _i2caddr, _vccstate, sid, sclk, dc, rst, cs; + void fastSPIwrite(uint8_t c); + + boolean hwSPI; +#ifdef HAVE_PORTREG + PortReg *mosiport, *clkport, *csport, *dcport; + PortMask mosipinmask, clkpinmask, cspinmask, dcpinmask; +#endif + + inline void drawFastVLineInternal(int16_t x, int16_t y, int16_t h, uint16_t color) __attribute__((always_inline)); + inline void drawFastHLineInternal(int16_t x, int16_t y, int16_t w, uint16_t color) __attribute__((always_inline)); + +}; + +#endif /* _Adafruit_SSD1306_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.cpp new file mode 100644 index 0000000..2604732 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.cpp @@ -0,0 +1,192 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "Flash.h" +#include "syslog.h" + +bool flashInit(void){ + if (NVMCTRL->PARAM.bit.PSZ != 3) + { + ERROR("FLASH PAGE SIZE is not 64 bytes"); + return false; + } + return true; +} + + +static void erase(const volatile void *flash_ptr) +{ + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr) / 2; + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_ER; + while (!NVMCTRL->INTFLAG.bit.READY) { } +} + +bool flashErase(const volatile void *flash_ptr, uint32_t size) +{ + const uint8_t *ptr = (const uint8_t *)flash_ptr; + while (size > FLASH_ROW_SIZE) { + erase(ptr); + ptr += FLASH_ROW_SIZE; + size -= FLASH_ROW_SIZE; + } + if (size>0) + { + erase(ptr); + } + return true; //TODO should verify the erase +} + +static inline uint32_t read_unaligned_uint32(const void *data) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } res; + const uint8_t *d = (const uint8_t *)data; + res.u8[0] = d[0]; + res.u8[1] = d[1]; + res.u8[2] = d[2]; + res.u8[3] = d[3]; + return res.u32; +} + + +void flashWrite(const volatile void *flash_ptr,const void *data, uint32_t size) +{ + uint32_t *ptrPage; + uint8_t *destPtr; + uint8_t *srcPtr; + uint32_t bytesInBlock; + __attribute__((__aligned__(4))) uint8_t buffer[FLASH_ROW_SIZE]; + uint32_t offset; + + destPtr=(uint8_t *)flash_ptr; + srcPtr=(uint8_t *)data; + + //LOG("flash write called"); + while(size>0) + { + uint32_t i,j; + + //calculate the maximum number of bytes we can write in page + offset=((uint32_t)destPtr)%(FLASH_ROW_SIZE); //offset into page + bytesInBlock=FLASH_ROW_SIZE-offset; //this is how many bytes we need to overwrite in this page + + //LOG("offset %d, bytesInBlock %d size %d", offset, bytesInBlock,size); + //get pointer to start of page + ptrPage=(uint32_t *) ((((uint32_t)destPtr)/(FLASH_ROW_SIZE)) * FLASH_ROW_SIZE); + + //LOG("pointer to page %d(0x%08x) %d",(uint32_t)ptrPage,(uint32_t)ptrPage,destPtr); + + //fill page buffer with data from flash + memcpy(buffer,ptrPage,FLASH_ROW_SIZE); + + //now fill buffer with new data that needs changing + i=bytesInBlock; + if (sizeCTRLB.bit.MANW = 1; + + // Do writes in pages + while (size) + { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + + // Fill page buffer + uint32_t i; + for (i=0; i<(FLASH_PAGE_SIZE/4) && size; i++) //we write 4 bytes at a time + { + *dst_addr = read_unaligned_uint32(src_addr); + src_addr += 4; + dst_addr++; + size--; //size is set to number of 32bit words in first line above + } + + // Execute "WP" Write Page + NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | NVMCTRL_CTRLA_CMD_WP; + while (NVMCTRL->INTFLAG.bit.READY == 0) { } + } + + +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.h b/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.h new file mode 100644 index 0000000..c95d700 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/Flash.h @@ -0,0 +1,68 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __FLASH__H__ +#define __FLASH__H__ + +#include +#include "syslog.h" + + +#define FLASH_PAGE_SIZE_NZS (64) //bytes +#define FLASH_ROW_SIZE (FLASH_PAGE_SIZE_NZS*4) //defined in the datasheet as 4x page size +#define FLASH_ERASE_VALUE (0xFF) //value of flash after an erase + +#define FLASH_ALLOCATE(name, size) \ + __attribute__((__aligned__(FLASH_ROW_SIZE))) \ + const uint8_t name[(size+(FLASH_ROW_SIZE-1))/FLASH_ROW_SIZE*FLASH_ROW_SIZE] = { }; + +bool flashInit(void); //this checks that our assumptions are true + +bool flashErase(const volatile void *flash_ptr, uint32_t size); +void flashWrite(const volatile void *flash_ptr,const void *data,uint32_t size); +void flashWritePage(const volatile void *flash_ptr, const void *data, uint32_t size); + +//you can read by dereferencing pointer but we will add a read +static inline int32_t flashRead(const volatile void *flash_ptr, void *data, uint32_t size) +{ + memcpy(data, (const void *)flash_ptr, size); +} + + + + +#endif //__FLASH__H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/angle.h b/firmware_smartstepper_trikarus/stepper_nano_zero/angle.h new file mode 100644 index 0000000..34e0226 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/angle.h @@ -0,0 +1,147 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef ANGLE_H_ +#define ANGLE_H_ +#include +#include +#include + +#define ANGLE_STEPS (0x010000UL) +#define ANGLE_MAX ((uint16_t)0x0FFFF) + +#define ANGLE_FROM_DEGREES(x) ((int32_t) ( ((float)ANGLE_STEPS*(float)(x)+180.0)/360.0 ) ) +#define ANGLE_T0_DEGREES(x) ( (float) ((float(x)*360.0)/((float)ANGLE_STEPS) )) +class Angle +{ +private: + uint16_t angle; +public: + Angle(void) {angle=0;} + Angle(int32_t x) {angle=(uint16_t)x;} + Angle(const Angle &x) {angle=x.angle;} + + int16_t operator-( const Angle &a2) + { + int32_t x,y,dx; + x=(int32_t)angle; + y=(int32_t)a2.angle; + dx=x-y; + if (abs(x-y)>ANGLE_STEPS/2) + { + //we have a wrap condition + if (x>y) + { + dx=x-(y+ANGLE_STEPS); + }else if (xANGLE_MAX) +// { +// y=y-ANGLE_STEPS; +// } +// while(y<-ANGLE_MAX) +// { +// y=y+ANGLE_STEPS; +// } +// +// dx=x-y; +// if (abs(x-y)>ANGLE_STEPS/2) +// { +// //we have a wrap condition +// if (x>y) +// { +// dx=x-(y+ANGLE_STEPS); +// }else if (x=ANGLE_STEPS) + { + a=a-ANGLE_STEPS; + } + while (a<0) + { + a=a+ANGLE_STEPS; + } + return Angle((uint16_t)a); + } + Angle operator+(const unsigned long int x) + { + uint32_t a; + a=(uint32_t)angle+ x; + while (a>=ANGLE_STEPS) + { + a=a-ANGLE_STEPS; + } + return Angle((uint16_t)a); + } + + operator uint16_t() const {return angle;} + operator uint32_t() const {return (uint32_t)angle;} + operator int32_t() const {return (int32_t)angle;} + + + +}; + + +#endif /* ANGLE_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.cpp new file mode 100644 index 0000000..0812c36 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.cpp @@ -0,0 +1,322 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include +#include "syslog.h" +#include "as5047d.h" +#include "SPI.h" +#include +#include "board.h" + +#define AS5047D_CMD_NOP (0x0000) +#define AS5047D_CMD_ERRFL (0x0001) +#define AS5047D_CMD_PROG (0x0003) +#define AS5047D_CMD_DIAAGC (0x3FFC) +#define AS5047D_CMD_MAG (0x3FFD) +#define AS5047D_CMD_ANGLEUNC (0x3FFE) +#define AS5047D_CMD_ANGLECOM (0x3FFF) + + +#define AS5048A_CMD_NOP (0x0000) +#define AS5048A_CMD_ERRFL (0x0001) +#define AS5048A_CMD_PROG (0x0003) +#define AS5048A_CMD_DIAAGC (0x3FFD) +#define AS5048A_CMD_MAG (0x3FFE) +#define AS5048A_CMD_ANGLE (0x3FFF) + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +static int getBit(int16_t data, int bit) +{ + return (data>>bit) & 0x01; +} + +static int getParity(uint16_t data) +{ + int i,bits; + data=data & 0x7FFF; //mask out upper bit + + //count number of bits, brute force + bits=0; + for(i=0; i<16; i++) + { + if (0 != (data & ((0x0001)<0) + { + delay(1); + t0--; + if (t0==0) + { + ERROR("LF bit not set"); + error=true; + break; + //return false; + } + LOG("AS5047D diag data is 0x%04X",data); + data=readAddress(AS5047D_CMD_DIAAGC); + } + + if (error) + { + error=false; + uint16_t data=0,t0=100; + while (getBit(data,8)==0 && t0>0) + { + delay(1); + t0--; + if (t0==0) + { + ERROR("AS5048A OCF bit not set"); + error=true; + return false; + } + data=readAddress(AS5048A_CMD_DIAAGC); + LOG("AS5048A diag data is 0x%04X",data); + } + as5047d=false; + + } + + +#ifdef NZS_AS5047_PIPELINE + //read encoder a few times to flush the pipeline + readEncoderAnglePipeLineRead(); + readEncoderAnglePipeLineRead(); +#endif + return true; +} + + +//read the encoders +int16_t AS5047D::readAddress(uint16_t addr) +{ + uint16_t data; + error=false; + //make sure it is a read by setting bit 14 + addr=addr | 0x4000; + + //add the parity to the command + if (1 == getParity(addr)) + { + addr=(addr & 0x7FFF) | 0x8000; //add parity bit to make command even number of bits + } + + digitalWrite(chipSelectPin, LOW); + delayMicroseconds(1); + //clock out the address to read + SPI.transfer16(addr); + digitalWrite(chipSelectPin, HIGH); + delayMicroseconds(1); + digitalWrite(chipSelectPin, LOW); + //clock out zeros to read in the data from address + data=SPI.transfer16(0x00); + + digitalWrite(chipSelectPin, HIGH); + + if (data & (1<<14)) + { + //if bit 14 is set then we have an error + ERROR("read command 0x%04X failed",addr); + error=true; + return -1; + } + + if (data>>15 != getParity(data)) + { + //parity did not match + ERROR("read command parity error 0x%04X ",addr); + error=true; + return -2; + } + + data=data & 0x3FFF; //mask off the error and parity bits + + return data; +} + +//read the encoders +int16_t AS5047D::readEncoderAngle(void) +{ + if (as5047d) + { + return readAddress(AS5047D_CMD_ANGLECOM); + } + return readAddress(AS5048A_CMD_ANGLE); +} + +//pipelined read of the encoder angle used for high speed reads, but value is always one read behind +int16_t AS5047D::readEncoderAnglePipeLineRead(void) +{ + + int16_t data; + int error, t0=10; + GPIO_LOW(chipSelectPin);//(chipSelectPin, LOW); + //delayMicroseconds(1); + do { + + // doing two 8 bit transfers is faster than one 16 bit + data =(uint16_t)SPI.transfer(0xFF)<<8 | ((uint16_t)SPI.transfer(0xFF) & 0x0FF); + t0--; + if (t0<=0) + { + ERROR("AS5047D problem"); + break; + } + //data=SPI.transfer16(0xFFFF); //to speed things up we know the parity and address for the read + }while(data & (1<<14)); //while error bit is set + + data=data & 0x3FFF; //mask off the error and parity bits + GPIO_HIGH(chipSelectPin); + //digitalWrite(chipSelectPin, HIGH); + //TODO we really should check for errors and return a negative result or something + return data; +} + + +void AS5047D::diagnostics(char *ptrStr) +{ + int16_t data; + int m,d; + + if (as5047d) + { + + data=readAddress(AS5047D_CMD_DIAAGC); + + if (NULL == ptrStr) + { + LOG("DIAAGC: 0x%04X", data); + LOG("MAGL: %d", getBit(data,11)); + LOG("MAGH: %d", getBit(data,10)); + LOG("COF: %d", getBit(data,9)); + LOG("LFGL: %d", getBit(data,8)); + LOG("AGC: %d", data & 0x0FF); + + data=readAddress(AS5047D_CMD_MAG); + LOG("CMAG: 0x%04X(%d)",data,data); + + data=readAddress(AS5047D_CMD_ANGLEUNC); + m=(int)((float)data*AS5047D_DEGREES_PER_BIT); + d=(int)((float)data*AS5047D_DEGREES_PER_BIT*100 -m*100); + LOG("CORDICANG: 0x%04X(%d) %d.%02d deg(est)",data,data,m,d); + + data=readAddress(AS5047D_CMD_ANGLECOM); + m=(int)((float)data*AS5047D_DEGREES_PER_BIT); + d=(int)((float)data*AS5047D_DEGREES_PER_BIT*100 -m*100); + LOG("DAECANG: 0x%04X(%d) %d.%02d deg(est)",data,data,m,d); + }else + { + sprintf(ptrStr,"DIAAGC: 0x%04X\n\r", data); + sprintf(ptrStr,"%sMAGL: %d\n\r", ptrStr,getBit(data,11)); + sprintf(ptrStr,"%sMAGH: %d\n\r", ptrStr,getBit(data,10)); + sprintf(ptrStr,"%sCOF: %d\n\r", ptrStr, getBit(data,9)); + sprintf(ptrStr,"%sLFGL: %d\n\r", ptrStr, getBit(data,8)); + sprintf(ptrStr,"%sAGC: %d\n\r", ptrStr,data & 0x0FF); + + data=readAddress(AS5047D_CMD_MAG); + sprintf(ptrStr,"%sCMAG: 0x%04X(%d)\n\r", ptrStr,data,data); + + data=readAddress(AS5047D_CMD_ANGLEUNC); + m=(int)((float)data*AS5047D_DEGREES_PER_BIT); + d=(int)((float)data*AS5047D_DEGREES_PER_BIT*100 -m*100); + sprintf(ptrStr,"%sCORDICANG: 0x%04X(%d) %d.%02d deg(est)\n\r", ptrStr,data,data,m,d); + + data=readAddress(AS5047D_CMD_ANGLECOM); + m=(int)((float)data*AS5047D_DEGREES_PER_BIT); + d=(int)((float)data*AS5047D_DEGREES_PER_BIT*100 -m*100); + sprintf(ptrStr,"%sDAECANG: 0x%04X(%d) %d.%02d deg(est)\n\r", ptrStr,data,data,m,d); + + } + } else + { + data=readAddress(AS5048A_CMD_DIAAGC); + sprintf(ptrStr,"AS5048A DIAAGC: 0x%04X\n\r", data); + data=readAddress(AS5048A_CMD_MAG); + sprintf(ptrStr,"%sMagnitude: %d\n\r", ptrStr,data); + data=readAddress(AS5048A_CMD_ANGLE); + sprintf(ptrStr,"%sAngle: %d\n\r", ptrStr,data); + } + +} + +#pragma GCC pop_options + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.h b/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.h new file mode 100644 index 0000000..8252c93 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/as5047d.h @@ -0,0 +1,58 @@ +/********************************************************************** + Copyright (C) 2019 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __AS5047D_H__ +#define __AS5047D_H__ + +#include +#define AS5047D_DEGREES_PER_BIT (360.0/(float)(0x3FFF)) + +class AS5047D { + private: + int chipSelectPin; + int16_t readAddress(uint16_t addr); + bool error=false; + bool as5047d=true; + public: + boolean begin(int csPin); + int16_t readEncoderAngle(void); + void diagnostics(char *ptrStr); + int16_t readEncoderAnglePipeLineRead(void); + bool getError(void) {return error;}; +}; + +#endif //__AS5047D_H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/board.h b/firmware_smartstepper_trikarus/stepper_nano_zero/board.h new file mode 100644 index 0000000..cd7a87d --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/board.h @@ -0,0 +1,564 @@ +/********************************************************************** +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __BOARD_H__ +#define __BOARD_H__ + +#include + + +//uncomment this if you are using the Mechaduino hardware +//#define MECHADUINO_HARDWARE + + +//uncomment the follow lines if using the NEMA 23 10A hardware +//#define NEMA_23_10A_HW + +//uncomment the following if the board uses the A5995 driver (NEMA 23 3.2A boards) +//#define A5995_DRIVER + +//The March 21 2017 NEMA 17 Smart Stepper has changed some pin outs +// A1 was changed to read motor voltage, hence SW4 is now using D4 +// comment out this next line if using the older hardware +#define NEMA17_SMART_STEPPER_3_21_2017 + +#if defined(MECHADUINO_HARDWARE) && defined(NEMA17_SMART_STEPPER_3_21_2017) +#error "Cannot have both MECHADUINO_HARDWARE and NEMA17_SMART_STEPPER_3_21_2017 defined in board.h" +#endif + +//The MKS Servo42 uses the A1333_Encoder +// Please uncomment this line and make sure the NEMA17_SMART_STEPPER_3_21_2017 is +// uncommented for the Servo42 +//#define A1333_ENCODER + +#ifdef A5995_DRIVER +#ifdef NEMA17_SMART_STEPPER_3_21_2017 +#error "Only NEMA17_SMART_STEPPER_3_21_2017 or A5595_DRIVER may be defined" +#endif +#endif + +#define NZS_FAST_CAL // define this to use 32k of flash for fast calibration table +#define NZS_FAST_SINE //uses 2048 extra bytes to implement faster sine tables + + +#define NZS_AS5047_PIPELINE //does a pipeline read of encoder, which is slightly faster + +#define NZS_CONTROL_LOOP_HZ (6000) //update rate of control loop + + +#define NZS_LCD_ABSOULTE_ANGLE //define this to show angle from zero in positive and negative direction +// for example 2 rotations from start will be angle of 720 degrees + +//#define ENABLE_PHASE_PREDICTION //this enables prediction of phase at high velocity to increase motor speed +//as of FW0.11 it is considered development only + +#define VERSION "FW: 0.40" //this is what prints on LCD during splash screen + +//Define this to allow command out serial port, else hardware serial is debug log +//#define CMD_SERIAL_PORT + +#define SERIAL_BAUD (115200) //baud rate for the serial ports + +//This section is for using the step and dir pins as serial port +// when the enable pin is inactive. +#ifndef MECHADUINO_HARDWARE +#define USE_STEP_DIR_SERIAL +#define STEP_DIR_BAUD (19200) //this is the baud rate we will use +#endif + + +// These are used as an attempt to use TC4 to count steps +// currently this is not working. +//#define USE_NEW_STEP //define this to use new step method +#define USE_TC_STEP //use timer counter for step pin + +#ifndef F_CPU +#define F_CPU (48000000UL) +#endif + +/* TODO are flaged with TODO + * TODO - add detection of magnet to make sure PCB is on motor + */ + +/* change log + * 0.02 added fixes for 0.9 degree motor + * 0.03 added code for using error pin as an enable pin, enable feedback by default + * 0.04 + * 0.05 added different modes added support for mechaduino + * 0.06 added time out pipeline read, add some error logging on encoder failure for mechaduino + * 0.07 many changes including + * - fixed error on display when doing a move 99999 + * - added velocity and position PID modes + * - fixed LCD menu and put LCD code in own file + * - include LCD source files from adafruit as that ssd1306 need lcd resoultion fix + * - added motor parameters to NVM such step size and rotation are only check on first boot + * - added test on power up to see if motor power is applied. + * - added factory reset command + * - pPID is not stable in my testing. + * 0.08 + * - moved enable pin processing out of interrupt context + * - added mode for inverted logic on the enable pin + * - added pin definitions for NEMA23 10A hardware + * - Changed enable such that it does not move motor but just sets current posistion + * 0.09 + * - enabled auto detection of LCD + * - cleaned up the commands, made motorparams and systemparams individual commands + * - added the option to the move command to move at a constant RPM + * - Added the setzero command to zero the relative location of motor + * - Added the stop command to stop the planner based moves. + * 0.10 + * -Fixed bug in switching control mode to 3 + * 0.11 + * - Fixed bug where output current was half of what it should have been (sine.h) + * - Added #define for phase predictive advancement + * - Changed calibration to be done with one coil/phase on + * - Added smoothing for calibration + * - Continue to work on the Fet Driver code. + * 0.12 + * - Continue to work on the FET driver code + * - fixed a constant issue with the DAC for the A4954 driver + * - added command for setting the operational mode of the enable pin + * - added the start of the A5995 driver. + * 0.13 + * - Added delay in for the 0.9 degree motor calibration and testing + * - changed calibration to move 1/2 step at time as it was causing problems on A5995 due to current ramp down + * 0.14 - Added in data logging + * - Averaged the encoder when the motor is stationary to reduce noise/vibrations + * 0.15 - Fixed some fet driver code + * - Added support for the NEMA17 smart stepper + * - Fixed RPM display bug on the LCD + * 0.16 - Added support for enable and error pins on the 3-21-2017 hardware + * + * 0.17 - Added the ability for the command line to go over the hardwired serial port + * - Fixed a bug where step and direction pin were setup as pulled down pins + * which could cause false stepping in nosiey environments + * 0.18 - Added support for EEPROM writting of last location during brown out - currently brown out is too fast to write + * - Added commands to support reading and restoring location from eeprom + * - Check for pull up on SDA/SCL before doing a I2C read as that SERCOM driver has not time outs and locks. + * - Added faster detection of USB not being plugged in, reduces power up time with no USB + * 0.19 - removed debug information in the ssd1306 driver which caused LCD not always to be found + * 0.20 - Fixed bug in calibration, thanks to Oliver E. + * 0.21 - Fixed issues compiling for mechaduino, including disabling LCD for MEchaduino + * 0.22 - Added home command; + * 0.23 -- added motor voltage sense to remove stepping on power up + * 0.24 - Disabled the home command which used the enable pin if you do not have enable pin + * 0.25 - Added pin read command + * 0.26 - changed the step/dir pins to be input_pullups + * 0.27 - added the option to make the step/dir uart when enable is low. + * - fixed enable to line to disable the A4954 driver + * 0.28 - Enabled some homing options (still under development) + * 0.29 - fixed rounding bug in ANGLE_T0_DEGREES + * 0.30 - Added support for the AS5048A encoder + * 0.31 - Added reading enable pin on during main loop + * 0.32 - Fixed issue where steps were not being counted correctly + * 0.33 - changed sPID parameters back to 0.9 0.0001 0.01 + * 0.34 - Added board type to the splash screen + * 0.35 - fixed usign TC4 (USE_TC_STEP) for counting steps. We can measure steps + * - at over 125khz, however the dir pin has ~8us setup time due to interrupt latency. + * - Added debug command to allow debug messages out the USB serial port + * 0.36 - eeprom set location math was wrong. + * 0.37 - fixed bug where the motor would pause periodically do the the TC4 counter. + * 0.38 - fixed bug in the velocity feedback mode. + * 0.39 - changed step count to TCC2, improved the dir pin setup/hold times + * - added support for the MKS Servo42 (A1333 encoder) + * 0.40 - fixed compiling errors for Mechaduino. Added sanity checks for different hardware boards (AK) + */ + + +/* + * Typedefs that are used across multiple files/modules + */ +typedef enum { + CW_ROTATION=0, + CCW_ROTATION=1, +} RotationDir_t; + +typedef enum { + ERROR_PIN_MODE_ENABLE=0, //error pin works like enable on step sticks + ERROR_PIN_MODE_ACTIVE_LOW_ENABLE=1, //error pin works like enable on step sticks + ERROR_PIN_MODE_ERROR=2, //error pin is low when there is angle error + ERROR_PIN_MODE_BIDIR=3, //error pin is bidirection open collector + +} ErrorPinMode_t; + +typedef enum { + CTRL_OFF =0, //controller is disabled + CTRL_OPEN=1, //controller is in open loop mode + CTRL_SIMPLE = 2, //simple error controller + CTRL_POS_PID =3, //PID Position controller + CTRL_POS_VELOCITY_PID =4, //PID Velocity controller + CTRL_TORQUE =5 +} feedbackCtrl_t; + +// ******** EVENT SYS USAGAE ************ +// Channel 0 - Step pin event + +// ******** TIMER USAGE A4954 versions ************ +//TCC1 is used for DAC PWM to the A4954 +//TCC0 can be used as PWM for the input pins on the A4954 +//TCC2 is used for the step count +//D0 step input could use TCC1 or TCC0 if not used +//TC3 is used for planner tick +//TC5 is use for timing the control loop + +// ******** TIMER USAGE NEMA23 10A versions ************ +//TCC0 PWM for the FET IN pins +//D10 step input could use TC3 or TCC0 if not used +//TC3 is used for planner tick +//TC4 is used for step count +//TC5 is use for timing the control loop + + +//mechaduio and Arduino Zero has defined serial ports differently than NZS +#ifdef MECHADUINO_HARDWARE +#warning "Compiling source for Mechaduino NOT NZS" +#define DISABLE_LCD +#undef Serial5 +#define Serial5 Serial +#else +#define SerialUSB Serial +#endif + +#define PIN_TXD (30) +#define PIN_RXD (31) + +#define PIN_STEP_INPUT (0) +#define PIN_DIR_INPUT (1) + +#define PIN_MOSI (23) +#define PIN_SCK (24) +#define PIN_MISO (22) + +#ifdef MECHADUINO_HARDWARE +#ifdef USE_STEP_DIR_SERIAL +#error "Step/Dir UART not supported on Mechaduino yet" +#endif + +#define PIN_ERROR (19) //analogInputToDigitalPin(PIN_A5)) +#else //not Mechaduino hardware +#ifdef NEMA17_SMART_STEPPER_3_21_2017 +#define PIN_SW1 (19)//analogInputToDigitalPin(PIN_A5)) +#define PIN_SW3 (14)//analogInputToDigitalPin(PIN_A0)) + +#ifdef A1333_ENCODER //the MKS Servo42 uses A1 for this switch +#define PIN_SW4 (15)//analogInputToDigitalPin(PIN_A1)) +#else +#define PIN_SW4 (2)//D2 +#endif + +#define PIN_ENABLE (10) +#define PIN_ERROR (3) + +#define PIN_VMOTOR (A1) //analog pin for the motor + +#else +#define PIN_SW1 (19)//analogInputToDigitalPin(PIN_A5)) +#define PIN_SW3 (14)//analogInputToDigitalPin(PIN_A0)) +#define PIN_SW4 (15)//analogInputToDigitalPin(PIN_A1)) +#define PIN_ERROR (10) +#endif + +#endif + +#ifdef A5995_DRIVER +#define PIN_ENABLE (3) +#endif + +#define PIN_SCL (21) +#define PIN_SDA (20) +#define PIN_USB_PWR (38) // this pin is high when usb is connected + +#define PIN_AS5047D_CS (16)//analogInputToDigitalPin(PIN_A2)) +#ifndef MECHADUINO_HARDWARE +#define PIN_AS5047D_PWR (11) //pull low to power on AS5047D +#endif + +//these pins use the TIMER in the A4954 driver +// changing the pin definitions here may require changes in the A4954.cpp file + +#define PIN_FET_IN1 (5) //PA15 TC3/WO[1] TCC0/WO[5]1 +#define PIN_FET_IN2 (6) //PA20 TC7/W0[0] TCC0/WO[6]2 +#define PIN_FET_IN3 (7) //PA21 TC7/WO[1] TCC0/WO[7]3 +#define PIN_FET_IN4 (2) //PA14 TC3/W0[0] TCC0/WO[4] 0 +#define PIN_FET_VREF1 (4) +#define PIN_FET_VREF2 (3) +#define PIN_FET_ENABLE (12) +//current sense pin from each H-bridge +#define ISENSE_FET_A (17) //analogInputToDigitalPin(PIN_A3) +#define ISENSE_FET_B (8) +//Comparators analog inputs +//#define COMP_FET_A (18)//analogInputToDigitalPin(PIN_A4)) +//#define COMP_FET_B (9) + + +//these are the pins used on the A5995 driver +#define PIN_A5995_ENABLE1 (2) //PA14 +#define PIN_A5995_ENABLE2 (18) //PA05 analogInputToDigitalPin(PIN_A4)) +#define PIN_A5995_MODE1 (8) //PA06 TCC1 WO[0] +#define PIN_A5995_MODE2 (7) //PA21 TCC0 WO[4] //3 +#define PIN_A5995_PHASE1 (6) //PA20 TCC0 WO[6] //2 +#define PIN_A5995_PHASE2 (5) //PA15 TCC0 W0[5] //1 +#define PIN_A5995_VREF1 (4) //PA08 +#define PIN_A5995_VREF2 (9) //PA07 +#define PIN_A5995_SLEEPn (25) //RXLED + + +#ifndef MECHADUINO_HARDWARE +#define PIN_YELLOW_LED (8) +#endif + + + + +#ifdef NEMA_23_10A_HW +#undef PIN_YELLOW_LED +#define PIN_YELLOW_LED (26) //TXLED (PA27) +#endif //NEMA_23_10A_HW + + +#define PIN_RED_LED (13) +#define PIN_A4954_IN3 (5) +#define PIN_A4954_IN4 (6) +#define PIN_A4954_IN2 (7) +#ifdef MECHADUINO_HARDWARE +#define PIN_A4954_IN1 (8) +#else +#define PIN_A4954_IN1 (18) //analogInputToDigitalPin(PIN_A4)) +#endif +#define PIN_A4954_VREF34 (4) +#define PIN_A4954_VREF12 (9) + + + +//Here are some useful macros +#define DIVIDE_WITH_ROUND(x,y) (((x)+(y)/2)/(y)) + + +#define GPIO_LOW(pin) {PORT->Group[g_APinDescription[(pin)].ulPort].OUTCLR.reg = (1ul << g_APinDescription[(pin)].ulPin);} +#define GPIO_HIGH(pin) {PORT->Group[g_APinDescription[(pin)].ulPort].OUTSET.reg = (1ul << g_APinDescription[(pin)].ulPin);} +#define GPIO_OUTPUT(pin) {PORT->Group[g_APinDescription[(pin)].ulPort].PINCFG[g_APinDescription[(pin)].ulPin].reg &=~(uint8_t)(PORT_PINCFG_INEN) ; PORT->Group[g_APinDescription[(pin)].ulPort].DIRSET.reg = (uint32_t)(1<Group[g_APinDescription[(pin)].ulPort].PINCFG[g_APinDescription[(pin)].ulPin].reg &=~(uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PMUXEN) ; PORT->Group[g_APinDescription[(pin)].ulPort].DIRSET.reg = (uint32_t)(1<Group[g_APinDescription[(pin)].ulPort].PINCFG[g_APinDescription[(pin)].ulPin].reg &=~(uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PMUXEN);} +#define GPIO_READ(ulPin) {(PORT->Group[g_APinDescription[ulPin].ulPort].IN.reg & (1ul << g_APinDescription[ulPin].ulPin)) != 0} +#define PIN_PERIPH(pin) {PORT->Group[g_APinDescription[(pin)].ulPort].PINCFG[g_APinDescription[(pin)].ulPin].reg |= PORT_PINCFG_PMUXEN;} +//sets up the pins for the board +static void boardSetupPins(void) +{ + //setup switch pins +#ifdef PIN_SW1 + pinMode(PIN_SW1, INPUT_PULLUP); + pinMode(PIN_SW3, INPUT_PULLUP); + pinMode(PIN_SW4, INPUT_PULLUP); +#endif + + pinMode(PIN_STEP_INPUT, INPUT_PULLUP); + pinMode(PIN_DIR_INPUT, INPUT_PULLUP); + +#ifdef PIN_ENABLE + pinMode(PIN_ENABLE, INPUT_PULLUP); //default error pin as enable pin with pull up +#endif + pinMode(PIN_ERROR, INPUT_PULLUP); //default error pin as enable pin with pull up + + pinMode(PIN_AS5047D_CS,OUTPUT); + digitalWrite(PIN_AS5047D_CS,LOW); //pull CS LOW by default (chip powered off) + + //turn the AS5047D off by default +#ifdef PIN_AS5047D_PWR + pinMode(PIN_AS5047D_PWR,OUTPUT); + digitalWrite(PIN_AS5047D_PWR,HIGH); +#endif + + + + pinMode(PIN_MOSI,OUTPUT); + digitalWrite(PIN_MOSI,LOW); + pinMode(PIN_SCK,OUTPUT); + digitalWrite(PIN_SCK,LOW); + pinMode(PIN_MISO,INPUT); + + //setup the A4954 pins + digitalWrite(PIN_A4954_IN3,LOW); + pinMode(PIN_A4954_IN3,OUTPUT); + digitalWrite(PIN_A4954_IN4,LOW); + pinMode(PIN_A4954_IN4,OUTPUT); + digitalWrite(PIN_A4954_IN2,LOW); + pinMode(PIN_A4954_IN2,OUTPUT); + digitalWrite(PIN_A4954_IN1,LOW); + pinMode(PIN_A4954_IN1,OUTPUT); + + //setup the PWM for current on the A4954, set for low current + digitalWrite(PIN_A4954_VREF12,LOW); + digitalWrite(PIN_A4954_VREF34,LOW); + pinMode(PIN_A4954_VREF34, OUTPUT); + pinMode(PIN_A4954_VREF12, OUTPUT); + + + + pinMode(PIN_RED_LED,OUTPUT); +#ifdef PIN_YELLOW_LED + pinMode(PIN_YELLOW_LED,OUTPUT); + digitalWrite(PIN_YELLOW_LED,HIGH); +#endif +} + +#ifdef NEMA17_SMART_STEPPER_3_21_2017 +static float GetMotorVoltage(void) +{ + uint32_t x; + float f; + //the motor voltage is 1/101 of the adc + x=analogRead(PIN_VMOTOR); //this should be a 10bit value mapped to 3.3V + f=(float)x*3.3/1024.0*101.0; + return f; +} +#endif + +static void inline YELLOW_LED(bool state) +{ +#ifdef PIN_YELLOW_LED + digitalWrite(PIN_YELLOW_LED,!state); +#endif +} + +static void inline RED_LED(bool state) +{ + digitalWrite(PIN_RED_LED,state); +} + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) +#define ABS(a) (((a)>(0))?(a):(-(a))) +#define DIV(x,y) (((y)>(0))?((x)/(y)):(4294967295)) +#define SIGN(x) (((x) > 0) - ((x) < 0)) + +#define NVIC_IS_IRQ_ENABLED(x) (NVIC->ISER[0] & (1 << ((uint32_t)(x) & 0x1F)))!=0 + +static inline uint8_t getPinMux(uint16_t ulPin) +{ + uint8_t temp; + if ((ulPin & 0x01)==0) + { + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ; + }else + { + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg)>>4 & 0xF; + } + return temp; +} + + +static inline uint8_t getPinCfg(uint16_t ulPin) +{ + uint8_t temp; + + temp = PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg; + return temp; +} + +static inline void setPinCfg(uint16_t ulPin, uint8_t val) +{ + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=val; +} + + + +static inline void setPinMux(uint16_t ulPin, uint8_t val) +{ + uint8_t temp; + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg); + if ((ulPin & 0x01)==0) + { + //if an even pin + temp = (temp & 0xF0) | (val & 0x0F); + }else + { + temp = (temp & 0x0F) | ((val<<4) & 0x0F); + } + PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg=temp; + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux +} + +static inline void SET_PIN_PERHERIAL(uint16_t ulPin,EPioType ulPeripheral) +{ + if ( g_APinDescription[ulPin].ulPin & 1 ) // is pin odd? + { + uint32_t temp ; + + // Get whole current setup for both odd and even pins and remove odd one + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXE( 0xF ) ; + // Set new muxing + PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXO( ulPeripheral ) ; + // Enable port mux + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; + } + else // even pin + { + uint32_t temp ; + + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO( 0xF ) ; + PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp|PORT_PMUX_PMUXE( ulPeripheral ) ; + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN ; // Enable port mux + } +} + + +//the Arduino delay function requires interrupts to work. +// if interrupts are disabled use the delayMicroseconds which is a spin loop +static inline void DelayMs(uint32_t ms) +{ + uint32_t prim; + /* Read PRIMASK register, check interrupt status before you disable them */ + /* Returns 0 if they are enabled, or non-zero if disabled */ + prim = __get_PRIMASK(); + + if (prim==0) + { + delay(ms); + }else + { + while(ms) + { + delayMicroseconds(1000); + ms--; + } + } +} + +#endif//__BOARD_H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.cpp new file mode 100644 index 0000000..e9ae16c --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.cpp @@ -0,0 +1,599 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "calibration.h" +#include "Flash.h" +#include "nonvolatile.h" +#include "board.h" //for divide with rounding macro +#include "utils.h" + + +static uint16_t getTableIndex(uint16_t value) +{ + int32_t x; + + x=((int32_t)value*CALIBRATION_TABLE_SIZE)/CALIBRATION_STEPS; //the divide is a floor not a round which is what we want + return (uint16_t)x; + +} +static uint16_t interp(Angle x1, Angle y1, Angle x2, Angle y2, Angle x) +{ + int32_t dx,dy,dx2,y; + dx=x2-x1; + dy=y2-y1; + dx2=x-x1; + y=(int32_t)y1+DIVIDE_WITH_ROUND((dx2*dy),dx); + if (y<0) + { + y=y+CALIBRATION_STEPS; + } + return (uint16_t)y; +} + +static void printData(int32_t *data, int32_t n) +{ + int32_t i; + Serial.print("\n\r"); + for (i=0; iFastCal.angle[x]; + }else + { + return reverseLookup(encoderAngle); + } +#else + return reverseLookup(encoderAngle) +#endif +} + +Angle CalibrationTable::reverseLookup(Angle encoderAngle) +{ + + int32_t i=0; + int32_t a1,a2; + int32_t x; + int16_t y; + int32_t min,max; + min=(uint16_t)table[0].value; + max=min; + + + + for (i=0; imax) + { + max=x; + } + } + + + x=(uint16_t)encoderAngle; + if (xCALIBRATION_STEPS/2) + { + if (a1=a1 && x<=a2) || + (x>=a2 && x<=a1) ) + { + //LOG("%d", i); + // inerpolate results and return + //LOG("%d %d %d",a1,a2,x); + //LOG("%d,%d",(i*CALIBRATION_MAX)/CALIBRATION_TABLE_SIZE,((i+2)*CALIBRATION_MAX)/CALIBRATION_TABLE_SIZE); + + y=interp(a1, DIVIDE_WITH_ROUND((i*CALIBRATION_STEPS),CALIBRATION_TABLE_SIZE), a2, DIVIDE_WITH_ROUND( ((i+1)*CALIBRATION_STEPS),CALIBRATION_TABLE_SIZE), x); + + return y; + } + i++; + } + ERROR("WE did some thing wrong"); + + + + +} + + +void CalibrationTable::smoothTable(void) +{ + uint16_t b[]={1,2,4,5,4,2,1}; + uint16_t sum_b=19; //sum of b filter + + int32_t data[CALIBRATION_TABLE_SIZE]; + int32_t table2[CALIBRATION_TABLE_SIZE]; + + int32_t i; + int32_t offset=0; + int32_t startNum; + + //first lets handle the wrap around in the table + for (i=0; i0 && offset==0) + { + if(((uint16_t)table[i-1].value-(uint16_t)table[i].value) <-32768) + { + offset=-65536; + } + + if (((uint16_t)table[i-1].value-(uint16_t)table[i].value) > 32768) + { + offset=65536; + } + } + table2[i]=(int32_t)((uint16_t)table[i].value)+offset; + } + + //Serial.print("after wrap\n\r"); + //printData(table2,CALIBRATION_TABLE_SIZE); + + //remove the starting offset and compensate table for index + startNum=table2[0]; + for (i=0; i=CALIBRATION_TABLE_SIZE) + { + ix=ix-CALIBRATION_TABLE_SIZE; + } + if (i==0) + { + LOG("index %d",ix); + } + sum=sum+table2[ix]*b[ib]; + ib++; + } + sum=DIVIDE_WITH_ROUND(sum,sum_b); + data[i]=sum; + } + + //Serial.print("after filter\n\r"); + //printData(data,CALIBRATION_TABLE_SIZE); + + //add in offset and the phase compenstation + for (i=0; i=65536) + { + data[i]=data[i]-65536; + } + } + + //Serial.print("after wrap added\n\r"); + //printData(data,CALIBRATION_TABLE_SIZE); + + //save new table + for (i=0; iCalibrationTable,sizeof(data)); + createFastCal(); + + LOG("after writting status is %d",data.status); + loadFromFlash(); + +} + +void CalibrationTable::loadFromFlash(void) +{ + FlashCalData_t data; + int i; + LOG("Reading Calbiration to Flash"); + memcpy(&data, &NVM->CalibrationTable,sizeof(data)); + for (i=0; iCalibrationTable.status); + return NVM->CalibrationTable.status; +} + + +void CalibrationTable::createFastCal(void) +{ +#ifdef NZS_FAST_CAL + int32_t i; + uint16_t cs=0; + uint16_t data[256]; + int32_t j; + j=0; + cs=0; + LOG("setting fast calibration"); + for (i=0; i<16384; i++) + { + + uint16_t x; + x=reverseLookup(i*4); + data[j]=x; + j++; + if (j>=256) + { + flashWrite(&NVM->FastCal.angle[i-255],data,256*sizeof(uint16_t)); + //LOG("Wrote fastcal at index %d-%d", i-255, i); + j=0; + } + cs+=x; + } + //update the checksum + flashWrite(&NVM->FastCal.checkSum,&cs,sizeof(uint16_t)); + fastCalVaild=true; + + //this is a quick test + /* + for (i=0; i<16384; i++) + { + LOG("fast Cal %d,%d,%d",i,NVM->FastCal.angle[i],(uint32_t)reverseLookup(i*4)); + } + */ +#endif +} +void CalibrationTable::updateFastCal(void) +{ +#ifdef NZS_FAST_CAL + int32_t i; + uint16_t cs=0; + uint16_t data[256]; + int32_t j; + bool NonZero=false; + for (i=0; i<16384; i++) + { + cs+=NVM->FastCal.angle[i]; + if (cs != 0) + { + NonZero=true; + } + } + if (cs!=NVM->FastCal.checkSum || NonZero==false) + { + createFastCal(); + } + else + { + LOG("fast cal is valid"); + fastCalVaild=true; + } +#endif +} + +void CalibrationTable::init(void) +{ + int i; + + if (true == flashGood()) + { + loadFromFlash(); + updateFastCal(); + }else + { + for (i=0; iCALIBRATION_STEPS/2) + { + dist=dist-CALIBRATION_STEPS; + } + + //if our distance is larger than size between calibration points in table we will ignore this sample + if (dist>CALIBRATION_STEPS/CALIBRATION_TABLE_SIZE) + { + //spans two or more table calibration points for this implementation we will not use + lastIndex=(int32_t)index; + lastValue=value; + return; + } + + //now lets see if the values are above and below a table calibration point + dist= abs(getTableIndex(lastAngle)-getTableIndex(actualAngle)); + if (dist != 0) //if the two indexs into table are not the same it spans a calibration point in table. + { + //the two span a set calibation table point. + uint16_t newValue; + newValue=interp(lastAngle, lastEncoderValue, actualAngle, encoderValue, getTableIndex(actualAngle)*(CALIBRATION_STEPS/CALIBRATION_TABLE_SIZE)) + //this new value is our best guess as to the correct calibration value. + updateTableValue(getTableIndex(actualAngle),newValue); + } else + { + //we should calibate the table value for the point the closest + } + + + + + + } + lastAngle=(int32_t)actualAngle; + lastEncoderValue=encoderValue; + +} +#endif + +//when we are microstepping and are in between steps the probability the stepper motor did not move +// is high. That is the actualAngle will be correct but the encoderValue will be behind due to not having enough torque to move motor. +// Therefore we only want to update the calibration on whole steps where we have highest probability of things being correct. +void CalibrationTable::updateTable(Angle actualAngle, Angle encoderValue) +{ + int32_t dist, index; + Angle tableAngle; + + index = getTableIndex((uint32_t)actualAngle+CALIBRATION_STEPS/CALIBRATION_TABLE_SIZE/2); //add half of distance to next entry to round to closest table index + + tableAngle=(index*CALIBRATION_STEPS)/CALIBRATION_TABLE_SIZE; //calculate the angle for this index + + dist=tableAngle-actualAngle; //distance to calibration table angle + + //LOG("Dist is %d",dist); + if (abs(dist)=CALIBRATION_TABLE_SIZE) + { + indexHigh -= CALIBRATION_TABLE_SIZE; + } + + //LOG("AngleLow %d, AngleHigh %d",angleLow,angleHigh); + //LOG("TableLow %u, TableHigh %d",(uint16_t)table[indexLow].value,(uint16_t)table[indexHigh].value); + y1=table[indexLow].value; + y2=table[indexHigh].value; + + //handle the wrap condition + if (abs(y2-y1)>CALIBRATION_STEPS/2) + { + if (y2=CALIBRATION_STEPS) + { + value=value-CALIBRATION_STEPS; + } + + err=table[indexLow].error; + if (table[indexHigh].error > err) + { + err=table[indexHigh].error; + } + + if (table[indexLow].error == CALIBRATION_ERROR_NOT_SET || + table[indexHigh].error == CALIBRATION_ERROR_NOT_SET) + { + err=CALIBRATION_ERROR_NOT_SET; + } + ptrData->value=value; + ptrData->error=err; + + return 0; + +} + +Angle CalibrationTable::getCal(Angle actualAngle) +{ + CalData_t data; + getValue(actualAngle, &data); + return data.value; +} + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.h b/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.h new file mode 100644 index 0000000..eaba5a6 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/calibration.h @@ -0,0 +1,104 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __CALIBRAITON_H__ +#define __CALIBRAITON_H__ + +#include +#include "syslog.h" +#include "angle.h" + + +//this file implements a table that is linearly interpolated circular calibration table +// it is assumed the data wraps around, ie you interpolated 65536==0 +//we want this to be "whole" steps, for 1.8 degree motors this should be 200. +// 200 will work for 0.9 degree too, but could be 400. However 400 is not good for 1.8 degree motors +#define CALIBRATION_TABLE_SIZE (200) + +#define CALIBRATION_STEPS ((uint32_t)ANGLE_STEPS) // this is one rotation ie 0-65535 aka 65536 steps is 0-360 degrees + +#define CALIBRATION_ERROR_NOT_SET (-1) //indicated that the calibration value is not set. + +#define CALIBRATION_UPDATE_RATE (32) //number of samples to keep 1 pole running average +#define CALIBRATION_MIN_ERROR (4) //the minimal expected error on our calibration 4 ~=+/0.2 degrees + + +typedef struct { + uint16_t table[CALIBRATION_TABLE_SIZE]; + bool status; +} FlashCalData_t; + + + + + +typedef struct { + Angle value; //cal value + int16_t error; //error assuming it is constantly updated +} CalData_t; + +class CalibrationTable +{ + private: + CalData_t table[CALIBRATION_TABLE_SIZE]; + + bool fastCalVaild=false; + void loadFromFlash(void); + bool flashGood(void); //returns true if the flash copy of calibration is valid + + void updateFastCal(void); + void createFastCal(void); + + public: + void init(void); + void saveToFlash(void); //saves the calibration to flash + bool updateTableValue(int32_t index, int32_t value); + void updateTable(Angle actualAngle, Angle encoderValue); + int getValue(Angle actualAngle, CalData_t *ptrData); + Angle getCal(Angle actualAngle); + bool calValid(void); + Angle reverseLookup(Angle encoderAngle); //this turns encoder angle into real angle + void printCalTable(void); + void smoothTable(void); + + Angle fastReverseLookup(Angle encoderAngle); +}; + + + + +#endif //__CALIBRAITON_H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/command.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/command.cpp new file mode 100644 index 0000000..bc6412a --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/command.cpp @@ -0,0 +1,381 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#include "command.h" +#include + + +#define ASCII_BACKSPACE 0x08 +#define ASCII_ESC 0x1B +#define ASCII_UP_ARROW 0x9b +//const char CMD_ANSI_UP[]= {ASCII_ESC,'[','A',0}; + +int strcicmp(char const *a, char const *b) +{ + for (;; a++, b++) { + int d = tolower(*a) - tolower(*b); + if (d != 0 || !*a) + return d; + } +} + +int CommandInit(sCmdUart *ptrUart, uint8_t (*kbhit)(void), uint8_t (*getch)(void),uint8_t (*putch)(char data),uint8_t (*puts)(uint8_t *buffer, uint8_t size) ) +{ + ptrUart->kbhit=kbhit; + ptrUart->getch=getch; + ptrUart->putch=putch; + ptrUart->puts=puts; + ptrUart->histIndex=0; + ptrUart->buffIndex=0; + return 0; +} + +#ifdef PGM_P //check and see if the PGM_P is defined for the AVR + +int CommandPrintf(sCmdUart *ptrUart, const char *fmt, ...) +{ + int ret=0; + char vastr[MAX_STRING]={0}; + //char str[MAX_STRING]={0}; + char *ptr; + va_list ap; + + //LOG("Command printf"); + memset(vastr,0,MAX_STRING); + va_start(ap,fmt); + ret=vsprintf(vastr,(const char *)fmt,ap); + //ret=sprintf(vastr,"%s\r\n",str); + //LOG("%s",vastr); + if (ptrUart->puts!=NULL) + { + return ptrUart->puts((uint8_t *)vastr, (uint8_t)ret); + } + + if (ptrUart->putch!=NULL) + { + ptr=vastr; + while(*ptr) + { + ptrUart->putch(*ptr++); + } + + return ret; + } + return 0; +} + + +#else +int CommandPrintf(sCmdUart *ptrUart, char *fmt, ...) +{ + int ret=0; + char vastr[MAX_STRING]={0}; + char *ptr; + va_list ap; + + + memset(vastr,0,MAX_STRING); + va_start(ap,fmt); + ret=vsprintf(vastr,(char *)fmt,ap); + if (ptrUart->puts!=NULL) + { + return ptrUart->puts((uint8_t *)vastr, (uint8_t)ret); + } + + if (ptrUart->putch!=NULL) + { + ptr=vastr; + while(*ptr) + { + ptrUart->putch(*ptr++); + } + + return ret; + } + return 0; +} +#endif + + +// the delimiter is command/parameter delimiter +// by default a ' '0x20 is used but for the TDR with GUI a ':' was preferred, not sure why +// set to ' '/0x20 if you want normal command parsing, like DOS +unsigned int CommandParse(sCmdUart *ptrUart,sCommand *ptrCmds, char *str, char delimitor ) +{ + char *ptr; + char *ptr2; + unsigned int i; + //char cmd[MAX_STRING]; + char buff[MAX_CMD_LENGTH]; + char argv[MAX_ARGS][MAX_ARG_LENGTH]; + char *ptrArgv[MAX_ARGS]; + unsigned int numArgs; + int emptyArg=0; + + sCommand cmd_list; + + + while (*str==0x20 || *str=='\n' || *str=='\r' || *str=='\t') str++; + //first we need find command and arguments + ptr=strchr(str,delimitor); //find first char + + //LOG("2parsing %s",str); + + + if (ptr==0) + { + //we have two options, frist whole thing is command + //second bad command + if(strlen(str)>0) + ptr=str+strlen(str); + else + return 0; //bad command + } + + //copy string to command buffer. + i=0; + ptr2=str; + while(ptr!=0 && ptr!=ptr2 && i<(MAX_CMD_LENGTH-1)) + { + //if (*ptr2!='\n' && *ptr2!='\r') //do not include newlines + { + buff[i++]=*ptr2; + } + ptr2++; + } + buff[i]=0; + + //now buff contains the command let's get the args + numArgs=0; + while(*ptr!=0 && (*ptr==' ' || *ptr==delimitor)) + ptr++; //increment pointer past ' ' + if (*ptr!=0) + { + if (*ptr==34) // " char + { + ptr++; + ptr2=strchr(ptr,34); //find match + } else if (*ptr==39) // 'char + { + ptr++; + ptr2=strchr(ptr,39); //find match + } else + { + ptr2=strchr(ptr,delimitor); + } + if (ptr2==0) + { + //we have two options, frist whole thing is command + //second bad command + //LOG("strlen ptr is %d",strlen(ptr)); + if(strlen(ptr)>0) + ptr2=ptr+strlen(ptr); + } + emptyArg=0; + while((ptr2!=0 && numArgs0) + ptr2=ptr+strlen(ptr); + } + } + } + } + + for(i=0; ikbhit()) + { + ptrUart->data=ptrUart->getch(); + + //echo the data + ptrUart->putch(ptrUart->data); + + //if the data is the CR we need to process buffer + if (ptrUart->data==0x0D) + { + ptrUart->putch(0x0A); + if (strlen(ptrUart->buffer)>0) + { + if (ptrUart->lastChar!=ASCII_UP_ARROW) + { + strcpy(ptrUart->bufferHist[ptrUart->histIndex],ptrUart->buffer); + ptrUart->histIndex=(ptrUart->histIndex+1) % CMD_HISTORY; + } + CommandParse(ptrUart,ptrCmds,ptrUart->buffer,delimitor); + } + + CommandPrintf(ptrUart,PSTR("\n\r%s"),cmdPrompt); + ptrUart->buffIndex=0; + ptrUart->buffer[ptrUart->buffIndex]=0; + } + + if (ptrUart->data==ASCII_BACKSPACE) //backspace + { + if (ptrUart->buffIndex>0) + { + ptrUart->buffIndex--; + ptrUart->buffer[ptrUart->buffIndex]='\0'; + //Echo the backspace + ptrUart->putch(' '); + ptrUart->putch(ASCII_BACKSPACE); + } + }else if (ptrUart->data != 0x0A && ptrUart->data !=0x0D && ptrUart->data<127) + { + ptrUart->buffer[ptrUart->buffIndex++]=ptrUart->data; + ptrUart->buffer[ptrUart->buffIndex]=0; + } + if (ptrUart->buffIndex>=(MAX_CMD_LENGTH-1)) + { + CommandPrintf(ptrUart,PSTR("\n\rERROR: Command buffer overflow\n\r"));\ + ERROR("Command buffer overflow"); + ptrUart->buffIndex=0; + ptrUart->buffer[0]=0; + CommandPrintf(ptrUart,PSTR("\n\r%s"),cmdPrompt); + } + } + + + if (strstr(ptrUart->buffer,ANSI_UP)) //up arrow + { + uint8_t i; + + CommandPrintf(ptrUart,PSTR("\n\r%s"),cmdPrompt); + i=CMD_HISTORY-1; + if (ptrUart->histIndex>0) + { + i=ptrUart->histIndex-1; + } + if (strlen(ptrUart->bufferHist[i])>0) + { + strcpy(ptrUart->buffer,ptrUart->bufferHist[i]); + ptrUart->buffIndex=strlen(ptrUart->buffer); + CommandPrintf(ptrUart,PSTR("%s"),ptrUart->buffer); + }else + { + ptrUart->buffIndex=0; + ptrUart->buffer[0]=0; + } + ptrUart->data=ASCII_UP_ARROW; + } + + + ptrUart->lastChar=ptrUart->data; + return 0; +} + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/command.h b/firmware_smartstepper_trikarus/stepper_nano_zero/command.h new file mode 100644 index 0000000..3af3df2 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/command.h @@ -0,0 +1,179 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __COMMAND_H +#define __COMMAND_H + +#include +#include +#include "syslog.h" +/* + * Usage: + * + #include + #include "uart_e0.h" + + sCmdUart KeyfobCmdUart; // UART used for the keyfob command line interface + + CMD_STR(help,"Displays this message"); + + //List of supported commands + sCommand KeyfobCmds[] = + { + COMMAND(help), + {"",0,""}, //End of list signal + }; + + // print out the help strings for the commands + static int help_cmd(sCmdUart *ptrUart,int argc, char * argv[]) + { + sCommand cmd_list; + int i; + + //now let's parse the command + i=0; + memcpy(&cmd_list, &KeyfobCmds[i], sizeof(sCommand)); + while(cmd_list.function!=0) + { + + CommandPrintf(ptrUart,(cmd_list.name)); + CommandPrintf(ptrUart,PSTR(" - ")); + CommandPrintf(ptrUart,(cmd_list.help)); + CommandPrintf(ptrUart,PSTR("\n\r")); + i=i+1; + memcpy(&cmd_list, &KeyfobCmds[i], sizeof(sCommand)); + } + return 0; + } + + uint8_t KeyfobCmdGetChar(void) + { + uint8_t c; + if (UARTE0_getc(&c)!=0) + { + ERROR("Uart getchar failed"); + return 0; + } + return c; + } + int KeyfobCmdInit(PIN tx_pin, PIN rx_pin, uint32_t baud) + { + LOG("UARTE0 init"); + UARTE0_Init(tx_pin, rx_pin, baud); + CommandInit(&KeyfobCmdUart, UARTE0_kbhit, KeyfobCmdGetChar, UARTE0_putc,NULL); //set up the UART structure + return 0; + } + + int KeyfobCmdProcess(void) + { + return CommandProcess(&KeyfobCmdUart,KeyfobCmds,' ',KEYFOB_CMD_PROMPT); + } + + Advantages: + 1. You can actually have more than one UART/device connected to same command line interface. + 2. works with harvard machines to save SRAM space using the PSTR functionality + 3. You can swap out commands "on the fly" + + + */ +#define MAX_CMD_LENGTH 60 +#define MAX_ARGS 10 +#define MAX_ARG_LENGTH 40 +#define CMD_HISTORY 3 //number of commands in history buffer +#define ASCII_BACKSPACE 0x08 +#define ASCII_ESC 0x1B +#define ASCII_UP_ARROW 0x9b +#define ANSI_UP "\x1B[A\0" + +#define MAX_STRING 255 +//const char ANSI_UP[]= {ASCII_ESC,'[','A',0}; + +typedef struct { + uint8_t (*kbhit)(void); + uint8_t (*getch)(void); + uint8_t (*putch)(char data); + uint8_t (*puts)(uint8_t *buffer, uint8_t size); + uint8_t data; + char buffer[MAX_CMD_LENGTH]; + + char bufferHist[CMD_HISTORY][MAX_CMD_LENGTH]; + uint8_t histIndex; + uint8_t buffIndex; + uint8_t lastChar; +}sCmdUart; + + +#define COMMAND(NAME) { NAME ## _str, NAME ## _cmd, NAME ## _help} + + +#ifdef PGM_P //check and see if the PGM_P is defined for the AVR + +//If so then we use the strings in flash not SRAM +#define CMD_STR(NAME,STR) static const char NAME ## _help[] PROGMEM = STR; static const char NAME ## _str[] PROGMEM = #NAME; static int NAME ##_cmd(sCmdUart *ptrUart,int, char **); +//Command structure +typedef struct +{ + PGM_P name; + int (*function) (sCmdUart *ptrUart,int, char **); + PGM_P help; +} sCommand; +int CommandPrintf(sCmdUart *ptrUart, const char *fmt, ...); + +#else + +#define CMD_STR(NAME,STR) static char NAME ## _help[] = STR; static char NAME ## _str[] = #NAME; static int NAME ##_cmd(sCmdUart *ptrUart,int, char **); + +//Command structure +typedef struct +{ + char *name; + int (*function) (sCmdUart *ptrUart,int, char **); + char *help; +} sCommand; + +int CommandPrintf(sCmdUart *ptrUart, char *fmt, ...); +#endif + + +int CommandInit(sCmdUart *ptrUart, uint8_t (*kbhit)(void), uint8_t (*getch)(void),uint8_t (*putch)(char data),uint8_t (*puts)(uint8_t *buffer, uint8_t size)); +unsigned int CommandParse(sCmdUart *ptrUart,sCommand *ptrCmds, char *str, char delimitor); +int CommandProcess(sCmdUart *ptrUart,sCommand *ptrCmds, char delimitor, char *cmdPrompt); + + + +#endif + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/commands.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/commands.cpp new file mode 100644 index 0000000..a6c1c56 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/commands.cpp @@ -0,0 +1,1658 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "commands.h" +#include "command.h" +#include "calibration.h" +#include "stepper_controller.h" +#include +#include "nonvolatile.h" +#include "Reset.h" +#include "nzs.h" +#include "ftoa.h" +#include "board.h" +#include "eeprom.h" +#include "steppin.h" + +extern int32_t dataEnabled; + +#define COMMANDS_PROMPT (":>") +sCmdUart UsbUart; +sCmdUart SerialUart; +sCmdUart HostUart; //uart on the step/dir pins + +static int isPowerOfTwo (unsigned int x) +{ + while (((x % 2) == 0) && x > 1) /* While x is even and > 1 */ + x /= 2; + return (x == 1); +} + + +CMD_STR(help,"Displays this message"); +CMD_STR(getcal,"Prints the calibration table"); +CMD_STR(calibrate,"Calbirates the encoder, should be done with motor disconnected from machine"); +CMD_STR(testcal,"tests the calibaration of the encoder"); +CMD_STR(microsteps,"gets/sets the microstep size, example 'microsteps 16'"); +CMD_STR(step, "Steps motor one step, optionally direction can be set is 'step 1' for reverse"); +CMD_STR(feedback, "enable or disable feedback controller, 'feedback 0' - disables, 'feedback 1' - enables"); +CMD_STR(readpos, "reads the current angle, applies calibration if valid"); +CMD_STR(encoderdiag, "Prints encoder diagnostic") +CMD_STR(spid, "with no arguments prints SIMPLE PID parameters, with arguments sets PID 'sPID Kp Ki Kd' " + "Where Kp,Ki,Kd are floating point numbers"); +CMD_STR(vpid, "with no arguments prints VELOCITY PID parameters, with arguments sets PID 'sPID Kp Ki Kd' " + "Where Kp,Ki,Kd are floating point numbers"); +CMD_STR(ppid, "with no arguments prints POSITIONAL PID parameters, with arguments sets PID 'sPID Kp Ki Kd' " + "Where Kp,Ki,Kd are floating point numbers"); +//CMD_STR(testringing ,"Steps motor at various currents and measures encoder"); +//CMD_STR(microsteperror ,"test error on microstepping") +CMD_STR(dirpin, "with no arguments read dirpin setting, with argument sets direction pin rotation. " + "Changing this also inverts torque mode direction."); +#ifndef PIN_ENABLE +CMD_STR(errorpinmode,"gets/sets the functionality of the error/enable pin"); +#else +CMD_STR(enablepinmode,"gets/sets the functionality of the enable pin"); +#endif + +CMD_STR(errorlimit, "gets/set the error limit which will assert error pin (when error pin is set for error output)"); +CMD_STR(ctrlmode, "gets/set the feedback controller mode of operation"); +CMD_STR(maxcurrent, "gets/set the maximum motor current allowed in milliAmps"); +CMD_STR(holdcurrent, "gets/set the motor holding current in milliAmps, only used in the simple positional PID mode"); +CMD_STR(homecurrent, "gets/set the motor moving and holding currents that will be used when pin A3 is low"); +CMD_STR(motorwiring, "gets/set the motor wiring direction, should only be used by experts"); +CMD_STR(stepsperrotation, "gets/set the motor steps per rotation, should only be used by experts"); + +//CMD_STR(sysparams, "with no arguments read parameters, will set with arguments"); +//CMD_STR(motorparams, "with no arguments read parameters, will set with arguments"); +CMD_STR(boot, "Enters the bootloader"); +CMD_STR(move, "moves encoder to absolute angle in degrees 'move 400.1'"); +//CMD_STR(printdata, "prints last n error terms"); +CMD_STR(velocity, "gets/set velocity in RPMs"); +CMD_STR(torque, "prints torque parameter, with argument sets 'torque t' " + "Where torque is an integer between -128 and 127. The special value 0 disables torque mode and enables position mode."); +CMD_STR(factoryreset, "resets board to factory defaults"); +CMD_STR(stop, "stops the motion planner"); +CMD_STR(setzero, "set the reference angle to zero"); +CMD_STR(data, "enables/disables binary data output"); +CMD_STR(looptime, "returns the control loop processing time"); +CMD_STR(eepromerror, "returns error in degreees from eeprom at power up realtive to current encoder"); +CMD_STR(eepromloc, "returns location in degreees eeprom on power up"); +CMD_STR(eepromwrite, "forces write of location to eeprom"); +CMD_STR(eepromsetloc, "sets the device angle based on EEPROM last reading, compenstates for error") +CMD_STR(setpos, "sets the current angle in degrees"); +CMD_STR(reboot, "reboots the unit"); +CMD_STR(homepin, "sets the pin used to drop to homing current"); +CMD_STR(homeangledelay, "sets the angle delay in dropping to homing current"); +#ifdef PIN_ENABLE +CMD_STR(home, "moves the motor until home switch (enable pin) is pulled low. example 'home 360 0.5' move up to 360 degrees at 0.5 RPM ") +#endif +CMD_STR(pinread, "reads pins as binary (bit 0-step, bit 1 - Dir, bit 2 - Enable, bit 3 - Error, bit 4 - A3, bit 5- TX, bit 6 - RX") +CMD_STR(errorpin, "Sets the logic level of error pin") +CMD_STR(geterror, "gets current error") +CMD_STR(getsteps, "returns number of steps seen") +CMD_STR(debug, "enables debug commands out USB") +//List of supported commands +sCommand Cmds[] = +{ + COMMAND(help), + COMMAND(calibrate), + COMMAND(getcal), + COMMAND(testcal), + COMMAND(microsteps), + COMMAND(step), + COMMAND(feedback), + COMMAND(readpos), + COMMAND(encoderdiag), + COMMAND(spid), + COMMAND(vpid), + COMMAND(ppid), + //COMMAND(testringing), + //COMMAND(microsteperror), + COMMAND(dirpin), +#ifndef PIN_ENABLE + COMMAND(errorpinmode), +#else + COMMAND(enablepinmode), +#endif + COMMAND(errorlimit), + COMMAND(ctrlmode), + COMMAND(maxcurrent), + COMMAND(holdcurrent), + COMMAND(homecurrent), + COMMAND(motorwiring), + COMMAND(stepsperrotation), + + //COMMAND(sysparams), + //COMMAND(motorparams), + COMMAND(boot), + COMMAND(move), + //COMMAND(printdata), + COMMAND(velocity), + COMMAND(torque), + COMMAND(factoryreset), + COMMAND(stop), + COMMAND(setzero), + COMMAND(data), + COMMAND(looptime), + COMMAND(eepromerror), + COMMAND(eepromloc), + COMMAND(eepromwrite), + COMMAND(setpos), + COMMAND(reboot), + COMMAND(eepromsetloc), + COMMAND(homepin), + COMMAND(homeangledelay), +#ifdef PIN_ENABLE + COMMAND(home), +#endif + COMMAND(pinread), + COMMAND(errorpin), + COMMAND(geterror), + COMMAND(getsteps), + COMMAND(debug), + {"",0,""}, //End of list signal +}; + +static int debug_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + uint32_t i; + if (argc>=1) + { + i=atol(argv[0]); + SysLogDebug(i); + } +} + +static int getsteps_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + int32_t s; + s=(int32_t)getSteps(); +// s=(int32_t)stepperCtrl.getSteps(); + CommandPrintf(ptrUart,"steps %" PRIi32 "\n\r",s); + return 0; +} +static int geterror_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + float f; + char str[30]; + f=ANGLE_T0_DEGREES(stepperCtrl.getLoopError()); + ftoa(f,str,2,'f'); + CommandPrintf(ptrUart,"error %s deg",str); + return 0; +} + + +static int errorpin_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (argc==1) + { + + SystemParams_t params; + + memcpy(¶ms,&NVM->SystemParams, sizeof(SystemParams_t) ); + params.errorLogic=atol(argv[0]); + + nvmWriteSystemParms(params); + stepperCtrl.updateParamsFromNVM(); + + } + CommandPrintf(ptrUart,"error pin assert level is %d\n\r",NVM->SystemParams.errorLogic); + return 0; + +} + +static int pinread_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + uint8_t ret=0; + + if (digitalRead(PIN_STEP_INPUT)) + { + ret |= 0x01; + } + if (digitalRead(PIN_DIR_INPUT)) + { + ret |= 0x02; + } +#ifdef PIN_ENABLE + if (digitalRead(PIN_ENABLE)) + { + ret |= 0x04; + } +#endif + if (digitalRead(PIN_ERROR)) + { + ret |= 0x08; + } + if (digitalRead(PIN_A3)) + { + ret |= 0x10; + } + if (digitalRead(30)) + { + ret |= 0x20; + } + if (digitalRead(31)) + { + ret |= 0x40; + } + CommandPrintf(ptrUart,"0x%02X\n\r",ret); + return 0; +} + +#ifdef PIN_ENABLE +static void errorPinISR(void) +{ + SmartPlanner.stop(); //stop the planner +} + + + + +static int home_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + float rpm=1; + float startDegrees=ANGLE_T0_DEGREES(stepperCtrl.getCurrentAngle()); + float finalDegrees=startDegrees+360.0; + char str[20]; + float deg; + + if (argc>=1) + { + finalDegrees=startDegrees+atof(argv[0]); + } + + if (argc>=2) + { + rpm=atof(argv[1]); + } + + //setup a interrupt for the enable pin + attachInterrupt(digitalPinToInterrupt(PIN_ENABLE), errorPinISR, FALLING); + + SmartPlanner.moveConstantVelocity(finalDegrees,rpm); + + while(!SmartPlanner.done()) + { + //do nothing + } + detachInterrupt(digitalPinToInterrupt(PIN_ENABLE)); + deg=ANGLE_T0_DEGREES(stepperCtrl.getCurrentAngle()); + ftoa(deg,str,2,'f'); + CommandPrintf(ptrUart,"home is %s deg\n\r",str); + stepperCtrl.setZero(); + + return 0; +} +#endif + +static int reboot_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + NVIC_SystemReset(); + return 0; +} + +static int setpos_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (argc>=1) + { + int64_t a; + float x; + x=fabs(atof(argv[0])); + a=ANGLE_FROM_DEGREES(x); + stepperCtrl.setAngle(a); + return 0; + } + return 1; +} + +static int eepromwrite_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + eepromFlush(); + return 0; +} +static int eepromerror_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + Angle a; + uint16_t error; + float deg; + char str[20]; + a=(Angle)PowerupEEPROM.encoderAngle; + + LOG("EEPROM encoder %d",(uint16_t)a); + LOG("start encoder %d",(uint16_t)stepperCtrl.getStartupEncoder()); + LOG("current encoder %d",(uint16_t)stepperCtrl.getEncoderAngle()); + a=(a-(Angle)stepperCtrl.getStartupEncoder()); + + + deg=ANGLE_T0_DEGREES((uint16_t)a) ; + if (deg>360.0) + { + deg=deg-360.0; + } + + ftoa(deg,str,2,'f'); + CommandPrintf(ptrUart,"startup error(+/-) %s deg\n\r",str); + + a=(Angle)PowerupEEPROM.encoderAngle; + a=(a-(Angle)stepperCtrl.getEncoderAngle()); + deg=ANGLE_T0_DEGREES((uint16_t)a); + if (deg>360.0) + { + deg=deg-360.0; + } + ftoa(deg,str,2,'f'); + CommandPrintf(ptrUart,"current error(+/-) %s deg\n\r",str); + + return 0; +} + +static int eepromsetloc_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + Angle a; + int64_t deg; + int32_t x; + + x=(uint32_t)PowerupEEPROM.encoderAngle-(uint32_t)stepperCtrl.getEncoderAngle(); + + deg=PowerupEEPROM.angle-x; + + stepperCtrl.setAngle(deg); + return 0; +} + +static int eepromloc_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + Angle a; + int64_t deg; + int32_t x,y; + + deg=PowerupEEPROM.angle; + + deg=(deg*360*100)/(int32_t)ANGLE_STEPS; + x=(deg)/100; + y=abs(deg-(x*100)); + CommandPrintf(ptrUart,"%d.%0.2d deg\n\r",x,y); + return 0; +} +static int looptime_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + + CommandPrintf(ptrUart,"%dus",stepperCtrl.getLoopTime()); + return 0; +} + +static int setzero_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + stepperCtrl.setZero(); + return 0; +} + + +static int stop_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + SmartPlanner.stop(); + return 0; +} + +static int data_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + dataEnabled=x; + return 0; + } + return 1; +} + + + +static int stepsperrotation_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + + if (argc == 0) + { + uint32_t x; + x=NVM->motorParams.fullStepsPerRotation; + CommandPrintf(ptrUart,"full steps per rotation %u\n\r",x); + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + + if (x==200 || x==400) + { + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + motorParams.fullStepsPerRotation=x; + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.fullStepsPerRotation; + CommandPrintf(ptrUart,"full steps per rotation %u\n\r",x); + CommandPrintf(ptrUart,"please power cycle board\n\r"); + return 0; + } + + } + CommandPrintf(ptrUart,"usage 'stepsperrotation 200' or 'stepsperrotation 400'\n\r"); + + return 1; +} + +static int motorwiring_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + + if (argc == 0) + { + uint32_t x; + x=NVM->motorParams.motorWiring; + CommandPrintf(ptrUart,"motor wiring %u\n\r",x); + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + + if (x<=1) + { + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + motorParams.motorWiring=x; + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.motorWiring; + CommandPrintf(ptrUart,"motor wiring %u\n\r",x); + CommandPrintf(ptrUart,"please power cycle board\n\r"); + return 0; + } + + } + CommandPrintf(ptrUart,"usage 'motorwiring 0' or 'motorwiring 1'\n\r"); + + return 1; +} + + +static int homeangledelay_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + float f; + char str[30]; + + if (argc == 1) + { + f=atof(argv[0]); + + SystemParams_t params; + + memcpy(¶ms,&NVM->SystemParams, sizeof(SystemParams_t) ); + params.homeAngleDelay=ANGLE_FROM_DEGREES(f); + + nvmWriteSystemParms(params); + stepperCtrl.updateParamsFromNVM(); + + } + + f=ANGLE_T0_DEGREES(NVM->SystemParams.homeAngleDelay); + ftoa(f,str,2,'f'); + CommandPrintf(ptrUart,"home angle delay %s\n\r",str); + return 0; +} + +static int homepin_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + int32_t x; + if (argc == 0) + { + x=NVM->SystemParams.homePin; + CommandPrintf(ptrUart,"home pin %d\n\r",x); + return 0; + } + + if (argc == 1) + { + x=atol(argv[0]); + + SystemParams_t params; + + memcpy(¶ms,&NVM->SystemParams, sizeof(SystemParams_t) ); + params.homePin=x; + + nvmWriteSystemParms(params); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->SystemParams.homePin; + CommandPrintf(ptrUart,"home pin %d\n\r",x); + return 0; + + } + + CommandPrintf(ptrUart, "use 'sethomepin 17' to set maximum home pin to A3"); + + return 1; +} + + +static int homecurrent_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + uint32_t x,y; + if (argc == 0) + { + x=NVM->motorParams.homeMa; + y=NVM->motorParams.homeHoldMa; + CommandPrintf(ptrUart,"current %umA, %umA\n\r",x,y); + return 0; + } + + if (argc == 1) + { + x=atol(argv[0]); + + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + motorParams.homeMa=x; + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.homeMa; + y=NVM->motorParams.homeHoldMa; + CommandPrintf(ptrUart,"current %umA, %umA\n\r",x,y); + return 0; + + } + if (argc == 2) + { + x=atol(argv[0]); + y=atol(argv[1]); + + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + motorParams.homeMa=x; + motorParams.homeHoldMa=y; + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.homeMa; + y=NVM->motorParams.homeHoldMa; + CommandPrintf(ptrUart,"current %umA, %umA\n\r",x,y); + return 0; + + } + CommandPrintf(ptrUart, "use 'homecurrent 1000 500' to set maximum home current to 1.0A and hold to 500ma"); + + return 1; +} + +static int holdcurrent_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + + if (argc == 0) + { + uint32_t x; + x=NVM->motorParams.currentHoldMa; + CommandPrintf(ptrUart,"hold current %u mA\n\r",x); + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + motorParams.currentHoldMa=x; + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.currentHoldMa; + CommandPrintf(ptrUart,"hold current %u mA\n\r",x); + return 0; + + + } + CommandPrintf(ptrUart, "use 'holdcurrent 1000' to set maximum current to 1.0A"); + + return 1; +} + + +static int maxcurrent_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + + if (argc == 0) + { + uint32_t x; + x=NVM->motorParams.currentMa; + CommandPrintf(ptrUart,"max current %u mA\n\r",x); + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + + MotorParams_t motorParams; + + memcpy(&motorParams,&NVM->motorParams, sizeof(motorParams) ); + + motorParams.currentMa=x; + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + + x=NVM->motorParams.currentMa; + CommandPrintf(ptrUart,"max current %u mA\n\r",x); + return 0; + + + } + CommandPrintf(ptrUart, "use 'maxcurrent 2000' to set maximum current to 2.0A"); + + return 1; +} + + + +static int ctrlmode_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + if (argc == 0) + { + switch(NVM->SystemParams.controllerMode) + { + case CTRL_OFF: + CommandPrintf(ptrUart,"controller Off(0)"); + return 0; + case CTRL_OPEN: + CommandPrintf(ptrUart,"controller Open-loop(1)"); + return 0; + case CTRL_SIMPLE: + CommandPrintf(ptrUart,"controller Simple-Position-PID(2)"); + return 0; + case CTRL_POS_PID: + CommandPrintf(ptrUart,"controller Current-Position-PID(3)"); + return 0; + case CTRL_POS_VELOCITY_PID: + CommandPrintf(ptrUart,"controller Velocity-PID(4)"); + return 0; + case CTRL_TORQUE: + CommandPrintf(ptrUart,"controller Torque(5)"); + return 0; + } + return 1; + } + + if (argc == 1) + { + uint32_t x; + + x=atol(argv[0]); + + if (x<=5) + { + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.controllerMode=(feedbackCtrl_t)(x); + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + switch(NVM->SystemParams.controllerMode) + { + case CTRL_OFF: + CommandPrintf(ptrUart,"controller Off(0)"); + return 0; + case CTRL_OPEN: + CommandPrintf(ptrUart,"controller Open-loop(1)"); + return 0; + case CTRL_SIMPLE: + CommandPrintf(ptrUart,"controller Simple-Position-PID(2)"); + return 0; + case CTRL_POS_PID: + CommandPrintf(ptrUart,"controller Current-Position-PID(3)"); + return 0; + case CTRL_POS_VELOCITY_PID: + CommandPrintf(ptrUart,"controller Velocity-PID(4)"); + return 0; + case CTRL_TORQUE: + CommandPrintf(ptrUart,"controller Torque(5)"); + return 0; + + } + return 1; + } + + } + CommandPrintf(ptrUart, "use 'ctrlmode [0 .. 5]' to set control mode"); + + return 1; +} +static int errorlimit_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + char str[20]; + if (argc == 0) + { + float x; + x=ANGLE_T0_DEGREES(NVM->SystemParams.errorLimit); + ftoa(x,str,2,'f'); + CommandPrintf(ptrUart,"errorLimit %s deg\n\r",str); + return 0; + } + + if (argc == 1) + { + float x; + + x=fabs(atof(argv[0])); + + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.errorLimit=ANGLE_FROM_DEGREES(x); + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + x=ANGLE_T0_DEGREES(NVM->SystemParams.errorLimit); + ftoa(x,str,2,'f'); + CommandPrintf(ptrUart,"errorLimit %s deg\n\r",str); + return 0; + + + } + CommandPrintf(ptrUart, "use 'errorlimit 1.8' to set error limit to 1.8 degrees"); + + return 1; +} + +/* Stop shaft rotation and return to default mode, + * which is one of CTRL_POS_PID or CTRL_SIMPLE, + * this should be read from nonvolative memory */ +void torqueSetToZeroSpecialBehaviour(void) +{ + if(stepperCtrl.getControlMode() == CTRL_TORQUE) // Don't do anything unless we're exiting torque mode + { + stepperCtrl.acceptPositionAndStealthSwitchMode(NVM->SystemParams.controllerMode); + } +} + + +static int dirpin_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + + if (argc == 0) + { + if (CW_ROTATION == NVM->SystemParams.dirPinRotation) + { + CommandPrintf(ptrUart,"dirpin CW(%d)\n\r",(uint32_t)NVM->SystemParams.dirPinRotation); + }else + { + CommandPrintf(ptrUart,"dirpin CCW(%d)\n\r",(uint32_t)NVM->SystemParams.dirPinRotation); + } + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=abs(atol(argv[0])); + if (x<=1) + { + + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.dirPinRotation=(RotationDir_t)x; + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + if (CW_ROTATION == NVM->SystemParams.dirPinRotation) + { + CommandPrintf(ptrUart,"dirpin CW(%d)\n\r",(uint32_t)NVM->SystemParams.dirPinRotation); + }else + { + CommandPrintf(ptrUart,"dirpin CCW(%d)\n\r",(uint32_t)NVM->SystemParams.dirPinRotation); + } + return 0; + + } + } + CommandPrintf(ptrUart, "used 'dirpin 0' for CW rotation and 'dirpin 1' for CCW"); + + + return 1; +} + +#ifndef PIN_ENABLE +static int errorpinmode_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + + if (argc == 0) + { + if (ERROR_PIN_MODE_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Enable Active High(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ACTIVE_LOW_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Enable active low(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ERROR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Error pin(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } else if (ERROR_PIN_MODE_BIDIR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Bidi error(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } + + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=abs(atol(argv[0])); + if (x<=3) + { + + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.errorPinMode=(ErrorPinMode_t)x; + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + if (ERROR_PIN_MODE_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Enable Active High(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ACTIVE_LOW_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Enable active low(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ERROR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Error pin(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } else if (ERROR_PIN_MODE_BIDIR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Error pin - Bidi error(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } + return 0; + + } + } + CommandPrintf(ptrUart, "use 'errorpinmode 0' for enable active high, 'errorpinmode 1' for enable active low and 'errorpinmode 2' for error output" ); + + + return 1; +} +#else +static int enablepinmode_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + + if (argc == 0) + { + if (ERROR_PIN_MODE_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Enable Active High(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ACTIVE_LOW_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Enable active low(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } else if (ERROR_PIN_MODE_BIDIR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Bidi error(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } else + { + CommandPrintf(ptrUart,"UNDEFINED Pin Mode error(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } + + return 0; + } + + if (argc == 1) + { + uint32_t x; + + x=abs(atol(argv[0])); + + if (x<=1) + { + + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.errorPinMode=(ErrorPinMode_t)x; + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + if (ERROR_PIN_MODE_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Enable Active High(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_ACTIVE_LOW_ENABLE == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Enable active low(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + }else if (ERROR_PIN_MODE_BIDIR == NVM->SystemParams.errorPinMode) + { + CommandPrintf(ptrUart,"Enable pin - Bidi error(%d)\n\r",(uint32_t)NVM->SystemParams.errorPinMode); + } + return 0; + + } + } + CommandPrintf(ptrUart, "use 'enablepinmode 0' for enable active high, 'enablepinmode 1' for enable active low " ); + + + return 1; +} +#endif + +static int factoryreset_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + nvmErase(); //erase all of the flash + NVIC_SystemReset(); +} +static int velocity_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + int64_t x; + + if (1 == argc) + { + float rpm; + rpm=atof(argv[0]); + x=(int64_t)(DIVIDE_WITH_ROUND(rpm*ANGLE_STEPS,60)); //divide with r + + + stepperCtrl.setVelocity(x); + } + int64_t y; + x=(stepperCtrl.getVelocity()*100 *60)/(ANGLE_STEPS); + y=abs(x-((x/100)*100)); + CommandPrintf(ptrUart,"Velocity is %d.%02d - %d\n\r",(int32_t)(x/100),(int32_t)y,(int32_t)stepperCtrl.getVelocity()); + + return 0; +} + +// +//static int printdata_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +//{ +// int32_t x; +// +// stepperCtrl.printData(); +// +// return 0; +//} + + +static int move_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + int32_t x,ma; + //CommandPrintf(ptrUart, "Move %d",argc); + + if (1 == argc) + { + float f; + + f=atof(argv[0]); + // if (f>1.8) + // f=1.8; + // if (f<-1.8) + // f=-1.8; + x=ANGLE_FROM_DEGREES(f); + LOG("moving %d", x); + + stepperCtrl.moveToAbsAngle(x); + } + if (2 == argc) + { + float f,rpm,a,y; + float pos,dx; + + f=atof(argv[0]); + rpm=atof(argv[1]); + // if (f>1.8) + // f=1.8; + // if (f<-1.8) + // f=-1.8; + + SmartPlanner.moveConstantVelocity(f,rpm); + return 0; + a=360*rpm/60/1000; //rotations/100ms + + pos=ANGLE_T0_DEGREES(stepperCtrl.getCurrentAngle()); + y=pos; + if (y>f) a=-a; + +#ifndef MECHADUINO_HARDWARE + SerialUSB.println(f); + SerialUSB.println(y); + SerialUSB.println(a); +#endif + + while (abs(y-f)>(2*abs(a))) + { + // SerialUSB.println(); + // SerialUSB.println(f); + // SerialUSB.println(y); + // SerialUSB.println(a); + y=y+a; + + x=ANGLE_FROM_DEGREES(y); + //LOG("moving %d", x); + stepperCtrl.moveToAbsAngle(x); + delay(1); + //y=stepperCtrl.getCurrentAngle(); + } + x=ANGLE_FROM_DEGREES(f); + LOG("moving %d", x); + stepperCtrl.moveToAbsAngle(x); + } + + return 0; +} + +static int boot_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + initiateReset(250); +} + +/* +static int microsteperror_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + int i,n,j; + bool feedback=stepperCtrl.getFeedback(); + n=200*stepperCtrl.getMicroSteps(); + + CommandPrintf(ptrUart, "Function needs fixed"); + return 0; + stepperCtrl.feedback(false); + for (j=0; j<2; j++) + { + for (i=0; iSystemParams.microsteps); +// CommandPrintf(ptrUart,"dirPinRotation %d\n\r",NVM->SystemParams.dirPinRotation); +// CommandPrintf(ptrUart,"errorLimit %d\n\r",NVM->SystemParams.errorLimit); +// CommandPrintf(ptrUart,"errorPinMode %d\n\r",NVM->SystemParams.errorPinMode); +// CommandPrintf(ptrUart,"controllerMode %d\n\r",NVM->SystemParams.controllerMode); +// +// } else if (5 == argc) +// { +// int32_t x; +// SystemParams_t systemParams; +// +// systemParams.microsteps=atol(argv[0]); +// x=atol(argv[1]); +// systemParams.dirPinRotation=CCW_ROTATION; +// if (x==0) +// { +// systemParams.dirPinRotation=CW_ROTATION; +// } +// systemParams.errorLimit=atol(argv[2]); +// systemParams.errorPinMode=(ErrorPinMode_t)atol(argv[3]); +// systemParams.controllerMode=(feedbackCtrl_t)atol(argv[4]); +// +// nvmWriteSystemParms(systemParams); +// stepperCtrl.updateParamsFromNVM(); +// +// CommandPrintf(ptrUart,"microsteps %d\n\r",NVM->SystemParams.microsteps); +// CommandPrintf(ptrUart,"dirPinRotation %d\n\r",NVM->SystemParams.dirPinRotation); +// CommandPrintf(ptrUart,"errorLimit %d\n\r",NVM->SystemParams.errorLimit); +// CommandPrintf(ptrUart,"errorPinMode %d\n\r",NVM->SystemParams.errorPinMode); +// CommandPrintf(ptrUart,"controllerMode %d\n\r",NVM->SystemParams.controllerMode); +// } else +// { +// CommandPrintf(ptrUart, "try 'sysparams microsteps dirPinRotation errorLimit errorPinMode controllerMode'\n\r\tlike 'sysparams 16 0 327 0 2'\n\e"); +// } +// return 0; +//} + +/* +static int motorparams_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (0 == argc) + { + CommandPrintf(ptrUart,"currentMa %d\n\r",NVM->motorParams.currentMa); + CommandPrintf(ptrUart,"currentHoldMa %d\n\r",NVM->motorParams.currentHoldMa); + CommandPrintf(ptrUart,"motorWiring %d\n\r",NVM->motorParams.motorWiring); + CommandPrintf(ptrUart,"fullStepsPerRotation %d\n\r",NVM->motorParams.fullStepsPerRotation); + + } else if (4 == argc) + { + int32_t x; + MotorParams_t motorParams; + + motorParams.currentMa=atol(argv[0]); + motorParams.currentHoldMa=atol(argv[1]); + motorParams.motorWiring=atol(argv[2]); + motorParams.fullStepsPerRotation=atol(argv[3]); + + nvmWriteMotorParms(motorParams); + stepperCtrl.updateParamsFromNVM(); + + CommandPrintf(ptrUart,"currentMa %d\n\r",NVM->motorParams.currentMa); + CommandPrintf(ptrUart,"currentHoldMa %d\n\r",NVM->motorParams.currentHoldMa); + CommandPrintf(ptrUart,"motorWiring %d\n\r",NVM->motorParams.motorWiring); + CommandPrintf(ptrUart,"fullStepsPerRotation %d\n\r",NVM->motorParams.fullStepsPerRotation); + } else + { + CommandPrintf(ptrUart, "try 'motorparams currentMa currentHoldMa motorWiring fullStepsPerRotation'\n\r\tlike 'motroparams 2200 1500 0 200'\n\e"); + } + return 0; +} + */ +static int vpid_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + CommandPrintf(ptrUart, "args %d\n\r",argc); + if (0 == argc) + { + int32_t x,y; + x=(int32_t)NVM->vPID.Kp; + y=abs(1000*NVM->vPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->vPID.Ki; + y=abs(1000*NVM->vPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->vPID.Kd; + y=abs(1000*NVM->vPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + if (3 == argc) + { + float Kp,Ki,Kd; + int32_t x,y; + + Kp=atof(argv[0]); + Ki=atof(argv[1]); + Kd=atof(argv[2]); + + nvmWrite_vPID(Kp,Ki,Kd); + stepperCtrl.updateParamsFromNVM(); //force the controller to use the new parameters + + x=(int32_t)NVM->vPID.Kp; + y=abs(1000*NVM->vPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->vPID.Ki; + y=abs(1000*NVM->vPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->vPID.Kd; + y=abs(1000*NVM->vPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + return 0; +} + +static int ppid_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (0 == argc) + { + int32_t x,y; + x=(int32_t)NVM->pPID.Kp; + y=abs(1000*NVM->pPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->pPID.Ki; + y=abs(1000*NVM->pPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->pPID.Kd; + y=abs(1000*NVM->pPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + if (3 == argc) + { + float Kp,Ki,Kd; + int32_t x,y; + + Kp=atof(argv[0]); + Ki=atof(argv[1]); + Kd=atof(argv[2]); + + nvmWrite_pPID(Kp,Ki,Kd); + stepperCtrl.updateParamsFromNVM(); //force the controller to use the new parameters + + x=(int32_t)NVM->pPID.Kp; + y=abs(1000*NVM->pPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->pPID.Ki; + y=abs(1000*NVM->pPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->pPID.Kd; + y=abs(1000*NVM->pPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + return 0; +} + +static int spid_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (0 == argc) + { + int32_t x,y; + x=(int32_t)NVM->sPID.Kp; + y=abs(1000*NVM->sPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->sPID.Ki; + y=abs(1000*NVM->sPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->sPID.Kd; + y=abs(1000*NVM->sPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + if (3 == argc) + { + float Kp,Ki,Kd; + int32_t x,y; + + Kp=atof(argv[0]); + Ki=atof(argv[1]); + Kd=atof(argv[2]); + + nvmWrite_sPID(Kp,Ki,Kd); + stepperCtrl.updateParamsFromNVM(); //force the controller to use the new parameters + + x=(int32_t)NVM->sPID.Kp; + y=abs(1000*NVM->sPID.Kp-(x*1000)); + CommandPrintf(ptrUart,"Kp %d.%03d\n\r",x,y); + + x=(int32_t)NVM->sPID.Ki; + y=abs(1000*NVM->sPID.Ki-(x*1000)); + CommandPrintf(ptrUart,"Ki %d.%03d\n\r",x,y); + + x=(int32_t)NVM->sPID.Kd; + y=abs(1000*NVM->sPID.Kd-(x*1000)); + CommandPrintf(ptrUart,"Kd %d.%03d\n\r",x,y); + } + return 0; +} + +static int torque_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (0 == argc) + { + CommandPrintf(ptrUart,"torque %d\n\r", stepperCtrl.getTorque()); + } + else if (1 == argc) + { + int32_t rec32; + int8_t rec; + rec32 = atoi(argv[0]); + if(rec32 > 127 || rec32 < -128) + { + CommandPrintf(ptrUart, "Error setting torque %d: not in valid range [-128, 127].", rec); + } + else + { + rec = (int8_t)rec32; + if (0 == rec) + { + torqueSetToZeroSpecialBehaviour(); + stepperCtrl.setTorque(0); // zero torque - used for monitoring purposes (added by vmario) + if (stepperCtrl.getControlMode() == CTRL_POS_PID) + { + CommandPrintf(ptrUart,"controller Current-Position-PID(3)"); + } + else if (stepperCtrl.getControlMode() == CTRL_SIMPLE) + { + CommandPrintf(ptrUart,"controller Simple-Position-PID(2)"); + } + } + else + { + stepperCtrl.setTorque(rec); // Units -128 - 127 + CommandPrintf(ptrUart, "torque set to %d", rec); + stepperCtrl.stealthSwitchMode(CTRL_TORQUE); + } + } + } + return 0; +} + +static int encoderdiag_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + char str[512]; + stepperCtrl.encoderDiagnostics(str); + CommandPrintf(ptrUart,"%s",str); + return 0; +} + +static int readpos_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + float pos; + int32_t x,y; + + pos=ANGLE_T0_DEGREES(stepperCtrl.getCurrentAngle()); + x=int(pos); + y=abs((pos-x)*100); + CommandPrintf(ptrUart,"encoder %d.%02d",x,y); + return 0; +} +static int feedback_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (0 == argc) + { + CommandPrintf(ptrUart,"must pass argument, 'feedback 0' - disables, 'feedback 1' - enables"); + return 1; + } + stepperCtrl.feedback(atoi(argv[0])); + return 0; +} + +static int step_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + if (argc == 0 ) + { + stepperCtrl.move(0, 1); + //stepperCtrl.step(STEPPER_FORWARD); + }else + { + int d, steps=1; + d=atoi(argv[0]); + if (argc >1) + { + steps=atoi(argv[1]); + } + if (1 == d) + { + stepperCtrl.move(1, steps); + } else + { + stepperCtrl.move(0, steps); + } + } + return 0; +} + + +static int microsteps_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + bool ret; + + if (argc != 1) + { + CommandPrintf(ptrUart,"microsteps %d\n\r",NVM->SystemParams.microsteps); + return 0; + } + + int32_t x; + + x=atol(argv[0]); + if (isPowerOfTwo(x) && x>0 && x<=256) + { + SystemParams_t systemParams; + + memcpy(&systemParams,&NVM->SystemParams, sizeof(systemParams) ); + + systemParams.microsteps=atol(argv[0]); + + nvmWriteSystemParms(systemParams); + stepperCtrl.updateParamsFromNVM(); + + CommandPrintf(ptrUart,"microsteps %d\n\r",NVM->SystemParams.microsteps); + + }else + { + CommandPrintf(ptrUart,"number of microsteps must be a power of 2 between 1 and 256"); + return 1; //return error + } + + return 0; +} + + +// print out the help strings for the commands +static int help_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + sCommand cmd_list; + int i; + + //now let's parse the command + i=0; + memcpy(&cmd_list, &Cmds[i], sizeof(sCommand)); + while(cmd_list.function!=0) + { + + CommandPrintf(ptrUart,(cmd_list.name)); + CommandPrintf(ptrUart,(" - ")); + CommandPrintf(ptrUart,(cmd_list.help)); + CommandPrintf(ptrUart,("\n\r")); + i=i+1; + memcpy(&cmd_list, &Cmds[i], sizeof(sCommand)); + } + return 0; +} + + + +static int getcal_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + stepperCtrl.calTable.printCalTable(); + return 0; +} + +static int calibrate_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + stepperCtrl.calibrateEncoder(); + CommandPrintf(ptrUart,"Calibration DONE!\n\r"); + return 0; +} + +static int testcal_cmd(sCmdUart *ptrUart,int argc, char * argv[]) +{ + Angle a; + int32_t x; + + a=stepperCtrl.maxCalibrationError(); + x=(uint16_t)a*(int32_t)360000L/(int32_t)ANGLE_MAX; + + CommandPrintf(ptrUart,"Max error is %d.%03d degrees\n\r", x/1000,abs(x)%1000); + return 0; +} + + +#ifndef MECHADUINO_HARDWARE + +uint8_t kbhit(void) +{ + return SerialUSB.available(); + //return SerialUSB.peek() != -1; +} +uint8_t getChar(void) +{ + return SerialUSB.read(); +} +uint8_t putch(char data) +{ + return SerialUSB.write((uint8_t)data); +} + +#endif +uint8_t kbhit_hw(void) +{ + return Serial5.available(); + //return SerialUSB.peek() != -1; +} +uint8_t getChar_hw(void) +{ + return Serial5.read(); +} +uint8_t putch_hw(char data) +{ + return Serial5.write((uint8_t)data); +} + + +uint8_t kbhit_step_dir(void) +{ + return Serial1.available(); + //return SerialUSB.peek() != -1; +} +uint8_t getChar_step_dir(void) +{ + return Serial1.read(); +} +uint8_t putch_step_dir(char data) +{ + return Serial1.write((uint8_t)data); +} + + + +void commandsInit(void) +{ + +#ifndef MECHADUINO_HARDWARE + CommandInit(&UsbUart, kbhit, getChar, putch ,NULL); //set up the UART structure + SerialUSB.print("\n\rPower Up\n\r"); + SerialUSB.print(COMMANDS_PROMPT); +#endif + + CommandInit(&HostUart, kbhit_step_dir, getChar_step_dir, putch_step_dir ,NULL); //set up the UART structure for step and dir pins + +#ifdef CMD_SERIAL_PORT + CommandInit(&SerialUart, kbhit_hw, getChar_hw, putch_hw ,NULL); //set up the UART structure + Serial5.print("\n\rPower Up\n\r"); + Serial5.print(COMMANDS_PROMPT); +#endif + +} + +int commandsProcess(void) +{ +#ifdef USE_STEP_DIR_SERIAL + //if the step pin is configured to the SerialCom 0 then we need to process commands + //if PA11 (D0) is configured to perpherial C then the step pin is UART + if (getPinMux(PIN_STEP_INPUT) == PORT_PMUX_PMUXE_C_Val) + { + //SerialUSB.println("host"); + CommandProcess(&HostUart,Cmds,' ',COMMANDS_PROMPT); + } +#endif //USE_STEP_DIR_SERIAL + + +#ifdef CMD_SERIAL_PORT + CommandProcess(&SerialUart,Cmds,' ',COMMANDS_PROMPT); +#endif + +#ifndef MECHADUINO_HARDWARE +if (SerialUSB.dtr()) + { + return CommandProcess(&UsbUart,Cmds,' ',COMMANDS_PROMPT); + } +#endif +} + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/commands.h b/firmware_smartstepper_trikarus/stepper_nano_zero/commands.h new file mode 100644 index 0000000..3edef45 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/commands.h @@ -0,0 +1,51 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __COMMANDS_H__ +#define __COMMANDS_H__ +#include +#include "stepper_controller.h" +#include "nzs.h" + +extern StepperCtrl stepperCtrl; +extern eepromData_t PowerupEEPROM; + +void commandsInit(void); +int commandsProcess(void); +void torqueSetToZeroSpecialBehaviour(void); + +#endif //__COMMANDS_H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.cpp new file mode 100644 index 0000000..e82b3fb --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.cpp @@ -0,0 +1,309 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "eeprom.h" +#include "calibration.h" +#include "Flash.h" +#include "board.h" //for divide with rounding macro +#include +#include "syslog.h" + +//since we will write the following structure into each page, we need to find our latest page +// to do this we will use the header to contain a checksum and write counter. +#define EEPROM_SIZE (FLASH_ROW_SIZE*2) + +typedef struct { + uint16_t checksum; + uint16_t count; +}eepromHeader_t; + +#define EEPROM_DATA_SIZE (FLASH_PAGE_SIZE_NZS-sizeof(eepromHeader_t)) +typedef struct { + eepromHeader_t header; + uint8_t data[EEPROM_DATA_SIZE]; +} eepromData_t; + + + +static eepromData_t EEPROMCache; + +static int32_t NextPageWrite=-1; + +//we need to reserve two pages for EEPROM +__attribute__((__aligned__(FLASH_ROW_SIZE))) const uint8_t NVM_eeprom[EEPROM_SIZE]={0xFF}; + + +static uint16_t checksum(uint8_t *ptrData, uint32_t nBytes) +{ + uint16_t sum=0; + uint32_t i; + i=0; + //LOG("running checksum %d",nBytes); + while(idata, EEPROM_DATA_SIZE); + //LOG("checksum is %d %d",cs,ptrData->header.checksum); + + if (cs==ptrData->header.checksum) + { + //LOG("Page good %d",page); + return true; + } + //LOG("page bad %d",page); + return false; +} + +static void printEEPROM(uint32_t page) +{ + eepromData_t *ptrData; + int i; + ptrData=(eepromData_t *)&NVM_eeprom[page]; + LOG("count %d", ptrData->header.count); + LOG("checksum %d", ptrData->header.checksum); + for (i=0; i<10; i++) + { + LOG("Data[%d]=%02X",i,ptrData->data[i]); + } +} + +static uint32_t findLastGoodPage(void) +{ + uint32_t lastGoodPage=0; + uint32_t page; + uint16_t lastCnt=0; + eepromData_t *ptrData; + + page=0; + while(page < (EEPROM_SIZE)) + { + //LOG("checking page %d",page); + if (isPageGood(page)) + { + ptrData=(eepromData_t *)&NVM_eeprom[page]; + + //check for roll over which is OK + if (lastCnt==16534 && ptrData->header.count==1) + { + lastCnt=ptrData->header.count; + lastGoodPage=page; + } + if (ptrData->header.count>lastCnt) + { + //make sure we have not rolled over. + if ((ptrData->header.count-lastCnt)<(16534/2)) + { + lastCnt=ptrData->header.count; + lastGoodPage=page; + } + } + } + page=page + FLASH_PAGE_SIZE_NZS; + } + //LOG("last good page %d",lastGoodPage); + return lastGoodPage; +} + +//find the next page to write +static uint32_t eepromGetNextWritPage(void) +{ + eepromHeader_t *ptrHeader; + uint32_t page; + uint32_t row; + int blockCount; + int done=0; + + //start at first address: + page=0; + + while(page < (EEPROM_SIZE)) + { + //LOG("checking page %d",page); + ptrHeader=(eepromHeader_t *) &NVM_eeprom[page]; + if (ptrHeader->count == 0xFFFF) + { + uint32_t i; + uint8_t *ptrData; + //uint8_t erasedByte=(uint8_t)ptrHeader->count; + bool erased=true; + + //verify page is erased + ptrData= (uint8_t *)&NVM_eeprom[page]; + + for (i=0; i=EEPROM_SIZE) + { + row=0; + //TODO we should make sure this not where good data is + // however if it is what should we do? + } + + //now we need to erase that row + //WARNING("Erasing page %d",row*FLASH_ROW_SIZE); + flashErase(&NVM_eeprom[row*FLASH_ROW_SIZE],FLASH_ROW_SIZE); + page=row*FLASH_ROW_SIZE; + //LOG("Next free page is %d",page); + return page; +} + + +eepromError_t eepromInit(void) +{ + uint32_t page; + + + //find the last good page offset in flash + page=findLastGoodPage(); + LOG("EEPROM Init found page %d",page); + if (isPageGood(page)) + { + LOG("EEPROM page good %d",page); + memcpy(&EEPROMCache, &NVM_eeprom[page], sizeof(EEPROMCache)); + + NextPageWrite=eepromGetNextWritPage(); + return EEPROM_OK; + } + //ERROR("page is bad"); + memset(&EEPROMCache, 0, sizeof(EEPROMCache)); + NextPageWrite=eepromGetNextWritPage(); + return EEPROM_CORRUPT; +} + + +int eepromWriteCache(uint8_t *ptrData, uint32_t size) +{ + //LOG("Cache write %d",size); + if (NextPageWrite==-1) //some one did not init the module + { + //lets handle gracefully and do it ourselves + eepromInit(); + } + if (size>EEPROM_DATA_SIZE) + { + size =EEPROM_DATA_SIZE; + } + memcpy(EEPROMCache.data, ptrData, size); + EEPROMCache.header.checksum=checksum(EEPROMCache.data,EEPROM_DATA_SIZE); + + + return size; +} + +int eepromRead(uint8_t *ptrData, uint32_t size) //returns number of bytes actually read, whcih could be less than size requested +{ + if (NextPageWrite==-1) //some one did not init the module + { + //lets handle gracefully and do it ourselves + eepromInit(); + } + if (size>EEPROM_DATA_SIZE) + { + size =EEPROM_DATA_SIZE; + } + if (EEPROMCache.header.count == 0) + { + return 0; //cache is new/corrupt + } + memcpy(ptrData, EEPROMCache.data, size); + return size; +} + +eepromError_t eepromFlush(void) //flush the cache to flash memory +{ + if (NextPageWrite==-1) + { + ERROR("EEPROM WRITE FAILED"); + return EEPROM_FAILED; //most likely no one has written to cache + } + EEPROMCache.header.count++; + if (EEPROMCache.header.count>=16535) + { + EEPROMCache.header.count=1; + } + //WARNING("Writting to Page %d",NextPageWrite); + flashWrite(&NVM_eeprom[NextPageWrite], &EEPROMCache, sizeof(EEPROMCache)); + + // printEEPROM(NextPageWrite); + + if (!SYSCTRL->PCLKSR.bit.BOD33DET) //if not in brown out condition find next write location + { + //LOG("getting next page to write"); + NextPageWrite=eepromGetNextWritPage(); //find next write location and erase if needed + } else + { + //LOG("BOD active"); + NextPageWrite=-1; //else we will just clear NextPageWrite location just in case we recover from brown out + } + return EEPROM_OK; +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.h b/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.h new file mode 100644 index 0000000..75154eb --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/eeprom.h @@ -0,0 +1,62 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef EEPROM_H_ +#define EEPROM_H_ +#include "Flash.h" +#include "calibration.h" +#include "board.h" + +/* + * This EEPROM implementation provides 60bytes of "eeprom space" (we reserve 4 bytes for overhead) + * The EEPROM uses two rows of flash (256 bytes per row), which + * for the SAMD21G18A this allows a minimual 200k writes, but typically 1200k + */ + +typedef enum { + EEPROM_OK =0, + EEPROM_FAILED=1, + EEPROM_CORRUPT=2, +} eepromError_t; + + +eepromError_t eepromInit(void); +int eepromWriteCache(uint8_t *ptrData, uint32_t size); //returns number bytes written to cache +eepromError_t eepromFlush(void); //flush the cache to flash memory +int eepromRead(uint8_t *ptrData, uint32_t size); //returns number of bytes actually read, whcih could be less than size requested + +#endif /* EEPROM_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.cpp new file mode 100644 index 0000000..cfe9b4e --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.cpp @@ -0,0 +1,1685 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "fet_driver.h" +#include "wiring_private.h" +#include "syslog.h" +#include "angle.h" +#include "Arduino.h" +#include "sine.h" +#include "nonvolatile.h" + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +#ifdef NEMA_23_10A_HW + +#define FET_DRIVER_FREQ (46875UL) //FET PWM pin driver frequency + +FetDriver *FetDriver::ptrInstance=0; + +// Wait for synchronization of registers between the clock domains +static __inline__ void syncDAC() __attribute__((always_inline, unused)); +static void syncDAC() { + while (DAC->STATUS.bit.SYNCBUSY == 1) + ; +} + + +volatile uint32_t coilA_Value=0; +/* + * The discrete FETs on the NEMA 23 10A board are configured such that each H-bridge has: + * IN1 - Input 1 + * IN2 - Input 2 + * Enable - Enable driver + * Isense - current sense + * + * The truth table for the H-Bridge is: + * Enable IN1 IN2 Bridge State + * 0 x x floating (FETs off) + * 1 0 0 coil shorted to Gnd + * 1 0 1 forward + * 1 1 0 reverse + * 1 1 1 coil shorted to VCC + * + * For peak current control there is two state (fast decay, and slow decay) + * + * Fast Decay + * When driving coil in forward direction and current peak is reached the fast decay turns + * The bridge in the reverse direction. This cause the reverse EMF from coil to charge + * capacitors back up and the current on the coil to drop very quickly + * + * Slow Decay + * During this mode the current decay is slower by shorting the coil leads to ground. + * This in effect shorts the coil leads and reverse EMF is converted to heat. + * + * In the Fast Decay mode we reverse the motor, this in effect is trying to drive coil + * current in the reverse direction. This in effect reduces current faster than just + * shorting the coil out. + * + * see www.misfittech.net's blog for more information on this subject + * + */ + +/* driver code's logic + * + * This driver code needs not only to control the FETs but also handle the current limits. + * + * The way the code handles limiting current is by using two comparators internal to + * the microprocessor. + * + * We first use two PWM signals to generate reference voltage for each comparator. + * Then when the current sense voltage exceeds this reference voltage an interrupt is + * generated. In the interrupt handler we will then set the decay mode as needed. + * + * It will have to be determined if we will use a fixed time decay mode like the A4954, + * or use current as the threshold. There is a lot to do here to maintain quite operation, + * that is we need this current control to be running at more than 20khz to be quite. + * + * Additionally we can use ADC on the current sense for detecting the flyback and + * get some idea of the inductance. This can be used for stall dection as well as + * auto tuning of some of the driver parameters. + */ + + + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY); + +typedef enum { + CURRENT_ON = 0, + CURRENT_FAST_DECAY = 1, + CURRENT_SLOW_DECAY = 2, +} CurrentMode_t; + +typedef enum { + COIL_FORWARD =0, + COIL_REVERSE =1, + COIL_BRAKE =2 +} CoilState_t; + +typedef struct { + bool currentIncreasing; //true when we are increasing current + CurrentMode_t currentState; //how is bridge driven +} BridgeState_t; + +volatile BridgeState_t BridgeA, BridgeB; + + +#define DAC_MAX (0x01FFL) +// Wait for synchronization of registers between the clock domains +static __inline__ void syncTCC(Tcc* TCCx) __attribute__((always_inline, unused)); +static void syncTCC(Tcc* TCCx) { + //int32_t t0=1000; + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + { + // t0--; + // if (t0==0) + // { + // break; + // } + + } +} + + + + + +static inline void coilA(CoilState_t state) +{ + PIN_GPIO_OUTPUT(PIN_FET_IN1); + PIN_GPIO_OUTPUT(PIN_FET_IN2); + switch(state){ + + case COIL_FORWARD: + GPIO_HIGH(PIN_FET_IN1); + GPIO_LOW(PIN_FET_IN2); + break; + + case COIL_REVERSE: + GPIO_HIGH(PIN_FET_IN2); + GPIO_LOW(PIN_FET_IN1); + break; + + case COIL_BRAKE: + GPIO_LOW(PIN_FET_IN2); + GPIO_LOW(PIN_FET_IN1); + break; + + default: + ERROR("Not a known state"); + break; + } + +} + +static inline void coilB(CoilState_t state) +{ + PIN_GPIO_OUTPUT(PIN_FET_IN3); + PIN_GPIO_OUTPUT(PIN_FET_IN4); + switch(state){ + case COIL_FORWARD: + GPIO_HIGH(PIN_FET_IN3); + GPIO_LOW(PIN_FET_IN4); + break; + + case COIL_REVERSE: + GPIO_HIGH(PIN_FET_IN4); + GPIO_LOW(PIN_FET_IN3); + break; + + case COIL_BRAKE: + GPIO_LOW(PIN_FET_IN3); + GPIO_LOW(PIN_FET_IN4); + break; + + default: + ERROR("Not a known state"); + break; + } +} + + +int FetDriver::coilA_PWM(int32_t value) +{ + int32_t x; + // PIN_FET_IN1 (PA15) (5) (TCC0 WO[5], aka ch1) + //PIN_FET_IN2 (PA20) (6) (TCC0 WO[6], aka ch2) + Tcc* TCCx = TCC0 ; + +// +// if (value==0) +// { +// GPIO_LOW(PIN_FET_IN1); +// GPIO_LOW(PIN_FET_IN2); +// PIN_GPIO(PIN_FET_IN1); +// PIN_GPIO(PIN_FET_IN2); +// return; +// } + + if (value<0) + { + GPIO_LOW(PIN_FET_IN1); + PIN_GPIO(PIN_FET_IN1); + PIN_PERIPH(PIN_FET_IN2); + //pinPeripheral(PIN_FET_IN2, PIO_TIMER_ALT); //TCC0 WO[7] + value=-value; + }else + { + GPIO_LOW(PIN_FET_IN2); + PIN_GPIO(PIN_FET_IN2); + PIN_PERIPH(PIN_FET_IN1); + //pinPeripheral(PIN_FET_IN1, PIO_TIMER_ALT); + } + + +#if (F_CPU/FET_DRIVER_FREQ)==1024 + x=value & 0x3FF; +#else + x=MIN(value, (int32_t)(F_CPU/FET_DRIVER_FREQ)); +#endif + + syncTCC(TCCx); + TCCx->CC[1].reg = (uint32_t)x; //ch1 == ch5 //IN3 + //syncTCC(TCCx); + TCCx->CC[2].reg = (uint32_t)x; //ch2 == ch6 //IN4 + if (x!=value) + { + return 1; + } + return 0; + +} + +void FetDriver::coilB_PWM(int32_t value) +{ + + //PIN_FET_IN3 (PA21) (7) (TCC0 WO[7], aka ch3) + //PIN_FET_IN4 (PA14) (2) (TCC0 WO[4], aka ch0) + Tcc* TCCx = TCC0 ; + + +// +// if (value==0) +// { +// GPIO_LOW(PIN_FET_IN3); +// GPIO_LOW(PIN_FET_IN4); +// PIN_GPIO(PIN_FET_IN3); +// PIN_GPIO(PIN_FET_IN4); +// return; +// } + + + if (value<=0) + { + GPIO_LOW(PIN_FET_IN3); + PIN_GPIO(PIN_FET_IN3); + PIN_PERIPH(PIN_FET_IN4); + //SET_PIN_PERHERIAL(PIN_FET_IN4, PIO_TIMER_ALT); //TCC0 WO[7] + value=-value; + }else + { + GPIO_LOW(PIN_FET_IN4); + PIN_GPIO(PIN_FET_IN4); + PIN_PERIPH(PIN_FET_IN3); + //SET_PIN_PERHERIAL(PIN_FET_IN3, PIO_TIMER_ALT); + } + + +#if (F_CPU/FET_DRIVER_FREQ)==1024 + value=value & 0x3FF; +#else + value=MIN(value, (int32_t)(F_CPU/FET_DRIVER_FREQ)); +#endif + + //LOG("value is %d",value); + // if (value> 300) //(F_CPU/FET_DRIVER_FREQ)) + // { + // value= 300; //F_CPU/FET_DRIVER_FREQ; + // } + syncTCC(TCCx); + TCCx->CC[0].reg = (uint32_t)value; //ch0 == ch4 //IN4 + //syncTCC(TCCx); + TCCx->CC[3].reg = (uint32_t)value; //ch3 == ch7 //IN3 + + +} + +static void enableTCC0(void) +{ + Tcc* TCCx = TCC0 ; + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; + + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + //ERROR("Setting TCC %d %d",ulValue,ulPin); + TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + syncTCC(TCCx); + + // Set TCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + syncTCC(TCCx); + + // Set PER to maximum counter value (resolution : 0xFF) + TCCx->PER.reg = F_CPU/FET_DRIVER_FREQ; //set frequency to 100Khz + syncTCC(TCCx); + + // Enable TCCx + TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; + syncTCC(TCCx); + //ERROR("Enable TCC0 DONE"); + +} + +static void setDAC(uint32_t DAC1, uint32_t DAC2) +{ + TCC1->CC[1].reg = (uint32_t)DAC1; //D9 PA07 - VREF12 + syncTCC(TCC1); + TCC1->CC[0].reg = (uint32_t)DAC2; //D4 - VREF34 + syncTCC(TCC1); +} + + + +static void setupDAC(void) +{ + Tcc* TCCx = TCC1 ; + + + pinPeripheral(PIN_FET_VREF1, PIO_TIMER_ALT); + pinPeripheral(PIN_FET_VREF2, PIO_TIMER_ALT); + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; + + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + //ERROR("Setting TCC %d %d",ulValue,ulPin); + TCCx->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + syncTCC(TCCx); + + // Set TCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + syncTCC(TCCx); + + // Set TCx in waveform mode Normal PWM + TCCx->CC[1].reg = (uint32_t)0; + syncTCC(TCCx); + + TCCx->CC[0].reg = (uint32_t)0; + syncTCC(TCCx); + + // Set PER to maximum counter value (resolution : 0xFFF = 12 bits) + // =48e6/2^12=11kHz frequency + TCCx->PER.reg = DAC_MAX; + syncTCC(TCCx); + + // Enable TCCx + TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; + syncTCC(TCCx); + +} + + +/* + * The SAMD21 has two analog comparators + * COMP_FET_A(A4/PA05) and COMP_FET_B(D9/PA07) are the reference voltages + * + * ISENSE_FET_A(A3/PA04) and ISENSE_FET_B(D8/PA06) are the current sense + * + */ +/* +static void setupComparators(void) +{ + //setup the pins as analog inputs + pinPeripheral(COMP_FET_A, PIO_ANALOG); //AIN[1] + pinPeripheral(COMP_FET_B, PIO_ANALOG); //AIN[3] + pinPeripheral(ISENSE_FET_A, PIO_ANALOG); //AIN[0] + pinPeripheral(ISENSE_FET_B, PIO_ANALOG); //AIN[2] + + //enable the clock for the Analog comparator + PM->APBCMASK.reg |= PM_APBCMASK_AC; //enable clock in the power manager + + //setup the GCLK for the analog and digital clock to the AC + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_AC_ANA )) ; + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_AC_DIG )) ; + while ( GCLK->STATUS.bit.SYNCBUSY == 1 ) ; + + + //we will drive the CMP0 and CMP1 high when our current is exceeded. + // To do this we will set ISense Pins as the non-inverting input + AC->CTRLA.reg=0x01; //disable AC_COMPCTRL_ENABLE and reset + while ( AC->STATUSB.bit.SYNCBUSY == 1 ) ; + AC->CTRLB.reg=0x0; // set start bits low (will not be used) + while ( AC->STATUSB.bit.SYNCBUSY == 1 ) ; + AC->COMPCTRL[0].reg = AC_COMPCTRL_FLEN_MAJ3_Val | //add a 3 bit majority digital filter + AC_COMPCTRL_HYST | //enable hysterisis + AC_COMPCTRL_MUXPOS_PIN0 | //non-inverting is AIN[0] + AC_COMPCTRL_MUXNEG_PIN1 | //inverting pin is AIN[1] + AC_COMPCTRL_INTSEL_RISING | //interrupt on the rising edge (TODO we might want on both edges) + AC_COMPCTRL_SPEED_HIGH | + AC_COMPCTRL_ENABLE; //set to high speed mode, we don't care about power consumption + while ( AC->STATUSB.bit.SYNCBUSY == 1 ) ; + AC->COMPCTRL[1].reg = //AC_COMPCTRL_FLEN_MAJ3_Val | //add a 3 bit majority digital filter + //AC_COMPCTRL_HYST | //enable hysterisis + AC_COMPCTRL_MUXPOS_PIN2 | //non-inverting is AIN[2] + AC_COMPCTRL_MUXNEG_PIN3 | //inverting pin is AIN[3] + AC_COMPCTRL_INTSEL_RISING | //interrupt on the rising edge (TODO we might want on both edges) + AC_COMPCTRL_SPEED_HIGH | + //AC_COMPCTRL_SWAP | + AC_COMPCTRL_ENABLE; //set to high speed mode, we don't care about power consumption + while ( AC->STATUSB.bit.SYNCBUSY == 1 ) ; + + //enable the comparator + AC->CTRLA.reg=AC_CTRLA_ENABLE; + while ( AC->STATUSB.bit.SYNCBUSY == 1 ); + + + + AC->INTENSET.bit.COMP0=1; + AC->INTENSET.bit.COMP1=1; + NVIC_EnableIRQ(AC_IRQn); //enable the comparator interrupt +} + */ + +static __inline__ void syncADC() __attribute__((always_inline, unused)); +static void syncADC() { + volatile int32_t t0=100; + while ((ADC->STATUS.bit.SYNCBUSY == 1))// && t0>0) + { + t0--; + if (t0>0) + { + break; + } + } + if (t0<=0) + { + ERROR("sync ADC timeout"); + } +} + + + + +static uint32_t ADCRead(uint32_t ulPin) +{ + uint32_t valueRead = 0; + uint32_t gainValue=0; + + if ( ulPin <= 5 ) // turn '0' -> 'A0' + { + ulPin += A0 ; + } + if (ulPin == 6) ulPin = PIN_A6; + if (ulPin == 7) ulPin = PIN_A7; + + pinPeripheral(PIN_A4, PIO_ANALOG); + + pinPeripheral(ulPin, PIO_ANALOG); + + syncADC(); + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV32 | // Divide Clock by 512. + ADC_CTRLB_RESSEL_12BIT; // 10 bits resolution as default + // syncADC(); + // ADC->INPUTCTRL.reg = 0; + + // syncADC(); + // ADC->INPUTCTRL.bit.MUXNEG= ADC_INPUTCTRL_MUXNEG_GND;//g_APinDescription[ulPin].ulADCChannelNumber; //ADC_INPUTCTRL_MUXNEG_GND; + //ADC_INPUTCTRL_MUXNEG_IOGND; //ADC_INPUTCTRL_MUXNEG_PIN5; // No Negative input (Internal Ground) + + + syncADC(); + ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ulPin].ulADCChannelNumber;//ADC_INPUTCTRL_MUXPOS_DAC;// g_APinDescription[ulPin].ulADCChannelNumber; // Selection for the positive ADC input + + + syncADC(); + ADC->INPUTCTRL.bit.GAIN = 0xF; //0x0F == gain of 1/2 + + syncADC(); + ADC->REFCTRL.reg=ADC_REFCTRL_REFSEL_INTVCC1; //set the ADC reference to 1/2VDDANA + + syncADC(); + ADC->SAMPCTRL.reg=0x02; + /* + * Bit 1 ENABLE: Enable + * 0: The ADC is disabled. + * 1: The ADC is enabled. + * Due to synchronization, there is a delay from writing CTRLA.ENABLE until the peripheral is enabled/disabled. The + * value written to CTRL.ENABLE will read back immediately and the Synchronization Busy bit in the Status register + * (STATUS.SYNCBUSY) will be set. STATUS.SYNCBUSY will be cleared when the operation is complete. + * + * Before enabling the ADC, the asynchronous clock source must be selected and enabled, and the ADC reference must be + * configured. The first conversion after the reference is changed must not be used. + */ + + syncADC(); + ADC->CTRLA.bit.ENABLE = 0x01; // Enable ADC + + + // Clear the Data Ready flag + syncADC(); + ADC->INTFLAG.bit.RESRDY = 1; + // Start conversion + syncADC(); + ADC->SWTRIG.bit.START = 1; + + + // wait for conversion to be done + while ( ADC->INTFLAG.bit.RESRDY == 0 ); // Waiting for conversion to complete + + // Clear the Data Ready flag + syncADC(); + ADC->INTFLAG.bit.RESRDY = 1; + // Start conversion again, since The first conversion after the reference is changed must not be used. + syncADC(); + ADC->SWTRIG.bit.START = 1; + + while ( ADC->INTFLAG.bit.RESRDY == 0 ); // Waiting for conversion to complete + valueRead = ADC->RESULT.reg; + + // syncADC(); + // ADC->CTRLA.bit.ENABLE = 0x00; // Disable ADC + // syncADC(); + + return valueRead; //mapResolution(valueRead, _ADCResolution, _readResolution); + +} + +int32_t fastADCRead(uint32_t ulPin) +{ + int32_t valueRead; + if ( ulPin <= 5 ) // turn '0' -> 'A0' + { + ulPin += A0 ; + } + if (ulPin == 6) ulPin = PIN_A6; + if (ulPin == 7) ulPin = PIN_A7; + syncADC(); + ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ulPin].ulADCChannelNumber;//ADC_INPUTCTRL_MUXPOS_DAC;// g_APinDescription[ulPin].ulADCChannelNumber; // Selection for the positive ADC input + // Clear the Data Ready flag + syncADC(); + ADC->INTFLAG.bit.RESRDY = 1; + // Start conversion again, since The first conversion after the reference is changed must not be used. + syncADC(); + ADC->SWTRIG.bit.START = 1; + + while ( ADC->INTFLAG.bit.RESRDY == 0 ); // Waiting for conversion to complete + valueRead = ADC->RESULT.reg; + return valueRead; +} + +int32_t GetMeanAdc(uint16_t pin, uint16_t samples) +{ + int32_t i=0; + int32_t mean=0; + int32_t adc; + while (i 'A0' + { + ulPin += A0 ; + } + if (ulPin == 6) ulPin = PIN_A6; + if (ulPin == 7) ulPin = PIN_A7; + + pinPeripheral(PIN_A4, PIO_ANALOG); + + pinPeripheral(ulPin, PIO_ANALOG); + + syncADC(); + ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV64 | // Divide Clock by 512. + ADC_CTRLB_RESSEL_12BIT; // 10 bits resolution as default + // syncADC(); + // ADC->INPUTCTRL.reg = 0; + + // syncADC(); + // ADC->INPUTCTRL.bit.MUXNEG= ADC_INPUTCTRL_MUXNEG_GND;//g_APinDescription[ulPin].ulADCChannelNumber; //ADC_INPUTCTRL_MUXNEG_GND; + //ADC_INPUTCTRL_MUXNEG_IOGND; //ADC_INPUTCTRL_MUXNEG_PIN5; // No Negative input (Internal Ground) + + syncADC(); + ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ulPin].ulADCChannelNumber;//ADC_INPUTCTRL_MUXPOS_DAC;// g_APinDescription[ulPin].ulADCChannelNumber; // Selection for the positive ADC input + + syncADC(); + ADC->INPUTCTRL.bit.INPUTSCAN=0; + // + // switch (gain) + // { + // case 1: + // gainValue=ADC_INPUTCTRL_GAIN_1X_Val; + // break; + // case 2: + // gainValue=ADC_INPUTCTRL_GAIN_2X_Val; + // break; + // case 4: + // gainValue=ADC_INPUTCTRL_GAIN_4X_Val; + // break; + // case 8: + // gainValue=ADC_INPUTCTRL_GAIN_8X_Val; + // break; + // case 16: + // gainValue=ADC_INPUTCTRL_GAIN_16X_Val; + // break; + // default: + // gainValue=ADC_INPUTCTRL_GAIN_1X_Val; + // break; + // } + + // syncADC(); + // ADC->CTRLB.bit.DIFFMODE = 0; //set to differential mode + + syncADC(); + ADC->INPUTCTRL.bit.GAIN = 0xF; //0x0F == gain of 1/2 + + // syncADC(); + // ADC->AVGCTRL.reg=5; + + syncADC(); + ADC->REFCTRL.reg=ADC_REFCTRL_REFSEL_INTVCC1; //set the ADC reference to 1/2VDDANA + + syncADC(); + ADC->SAMPCTRL.reg=0x0F; + /* + * Bit 1 ENABLE: Enable + * 0: The ADC is disabled. + * 1: The ADC is enabled. + * Due to synchronization, there is a delay from writing CTRLA.ENABLE until the peripheral is enabled/disabled. The + * value written to CTRL.ENABLE will read back immediately and the Synchronization Busy bit in the Status register + * (STATUS.SYNCBUSY) will be set. STATUS.SYNCBUSY will be cleared when the operation is complete. + * + * Before enabling the ADC, the asynchronous clock source must be selected and enabled, and the ADC reference must be + * configured. The first conversion after the reference is changed must not be used. + */ + syncADC(); + ADC->CTRLA.bit.ENABLE = 0x01; // Enable ADC + + + //Setup up for ISR + ADC->INTENCLR.reg=0x0F; + ADC->INTENSET.bit.RESRDY=1; + + NVIC_SetPriority(ADC_IRQn, 3); + + + // Clear the Data Ready flag + ADC->INTFLAG.bit.RESRDY = 1; + + // Start conversion + syncADC(); + ADC->SWTRIG.bit.START = 1; + + + + // Start conversion again, since The first conversion after the reference is changed must not be used. + //syncADC(); + //ADC->SWTRIG.bit.START = 1; + + //ADC->INTENSET.bit.RESRDY=1; + + // // Store the value + while ( ADC->INTFLAG.bit.RESRDY == 0 ); // Waiting for conversion to complete + // valueRead = ADC->RESULT.reg; + // + // syncADC(); + // ADC->CTRLA.bit.ENABLE = 0x00; // Disable ADC + // syncADC(); + + uint32_t reg; + + syncADC(); + reg=ADC->CTRLA.reg; + LOG("ADC CTRLA 0x%04X",reg); + + syncADC(); + reg=ADC->REFCTRL.reg; + LOG("ADC REFCTRL 0x%04X",reg); + + syncADC(); + reg=ADC->AVGCTRL.reg; + LOG("ADC AVGCTRL 0x%04X",reg); + + syncADC(); + reg=ADC->SAMPCTRL.reg; + LOG("ADC SAMPCTRL 0x%04X",reg); + + syncADC(); + reg=ADC->CTRLB.reg; + LOG("ADC CTRLB 0x%04X",reg); + + syncADC(); + reg=ADC->INPUTCTRL.reg; + LOG("ADC INPUTCTRL 0x%04X",reg); + + syncADC(); + reg=ADC->GAINCORR.reg; + LOG("ADC GAINCORR 0x%04X",reg); + + syncADC(); + reg=ADC->OFFSETCORR.reg; + LOG("ADC OFFSETCORR 0x%04X",reg); + + syncADC(); + reg=ADC->CALIB.reg; + LOG("ADC CALIB 0x%04X",reg); + + + // Enable InterruptVector + NVIC_EnableIRQ(ADC_IRQn); + + // Clear the Data Ready flag + ADC->INTFLAG.bit.RESRDY = 1; + + + // Start conversion + syncADC(); + ADC->SWTRIG.bit.START = 1; + + return 0;//valueRead; //mapResolution(valueRead, _ADCResolution, _readResolution); +} +void ADC_Handler(void) +{ + + uint16_t channel; + uint16_t value; + static uint16_t lastChannel=0; + + //static int state=0; + YELLOW_LED(1); + //state=(state+1)&0x01; + + value=ADC->RESULT.reg; + channel=ADC->INPUTCTRL.bit.MUXPOS;// + ADC->INPUTCTRL.bit.INPUTOFFSET; + + //LOG("channel is %d %d", lastChannel,value); + + FetDriver::ADC_Callback(lastChannel,value); + lastChannel=channel; + + if (channel == g_APinDescription[ISENSE_FET_B].ulADCChannelNumber) + { + syncADC(); + ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ISENSE_FET_A].ulADCChannelNumber; + } else + { + syncADC(); + ADC->INPUTCTRL.bit.MUXPOS = g_APinDescription[ISENSE_FET_B].ulADCChannelNumber; + } + + //LOG("channel is %d %d", ADC->INPUTCTRL.bit.MUXPOS ,value); + //syncADC(); + ADC->INTFLAG.bit.RESRDY = 1; + //syncADC(); + ADC->SWTRIG.bit.START = 1; + YELLOW_LED(0); + //state=(state+1)&0x01; + +} + + + +void FetDriver::ADC_Callback(uint16_t channel, uint16_t value) +{ + + //ptrInstance->begin(); + if (ptrInstance==NULL) + { + return; + } + ptrInstance->ctrl_update(channel,value); + +} + +void FetDriver::ctrl_update(uint16_t channel, uint16_t value) +{ + int32_t x,error; + + if (channel == g_APinDescription[ISENSE_FET_A].ulADCChannelNumber) + { + static int32_t iterm; + + x=value-coilA_Zero; + error=coilA_SetPoint-x; + coilA_error=x; + iterm+=error; + + x=error*15;//+iterm/10; + x=x/1024; + coilA_value+=x; + +// if (error>0) +// coilA_value++; +// else +// coilA_value--; +// +// coilA_value+= iterm/1024; + coilA_PWM(coilA_value); +// if (error>0) +// { +// coilA(COIL_FORWARD); +// }else +// { +// coilA(COIL_BRAKE); +// } + + } + + if (channel == g_APinDescription[ISENSE_FET_B].ulADCChannelNumber) + { + static int32_t itermB; + x=value-coilB_Zero; + error=coilB_SetPoint-x; + coilB_error=error; + + + x=error*15+itermB/10; + x=x/1024; + coilB_value+=x; + + //coilB_PWM(coilB_value); +// if (error>0) +// { +// coilB(COIL_FORWARD); +// }else +// { +// coilB(COIL_BRAKE); +// } + + } + return; + + //LOG("channel is %d %d", channel,value); + if (channel == g_APinDescription[ISENSE_FET_B].ulADCChannelNumber) + { + static int32_t ib=0; + static int32_t meanb=0; + int32_t error,u,de; + static int32_t itermb=0;; + static int32_t lastErrorb=0; + + adc=value; + x=value-coilB_Zero; + if (coilB_Zero==-1) + { + if(ib0) + // u=1; + // else + // u=-1; + + de=error-lastErrorb; + lastErrorb=error; + + if (ABS(error)<50) + { + itermb=itermb+1*error; + }else + { + itermb=0; + } + u=error*320 + itermb +100*de; + u=u/16382; + if (u>10) u=10; + if (u<-10) u=-10; + + coilB_value+=u;; + //LOG("coil value %d, %d",coilB_value,u); + coilB_value=MIN(coilB_value,(int32_t)(F_CPU/FET_DRIVER_FREQ)); + coilB_value=MAX(coilB_value,(int32_t)(-(F_CPU/FET_DRIVER_FREQ))); + + coilB_PWM(coilB_value); + + return; + } + + if (channel == g_APinDescription[ISENSE_FET_A].ulADCChannelNumber) + { + static int32_t i=0; + static int32_t mean=0; + int32_t error,u,de; + static int32_t iterm=0;; + static int32_t lastError=0; + + + x=value-coilA_Zero; + if (coilA_Zero==-1) + { + if(i10) u=10; + if (u<-10) u=-10; + + coilA_value+=u; + //LOG("coil value %d, %d",coilB_value,u); + coilA_value=MIN(coilA_value,(int32_t)(F_CPU/FET_DRIVER_FREQ)); + coilA_value=MAX(coilA_value,(int32_t)(-(F_CPU/FET_DRIVER_FREQ))); + + coilA_PWM(coilA_value); + return; + } + +} + + +void FetDriver::measureCoilB_zero(void) +{ + coilB_Zero=GetMeanAdc(ISENSE_FET_B,FET_DRIVER_NUM_ZERO_AVG); + LOG("Coil B Zero is %d",coilB_Zero); + return; +} + +void FetDriver::measureCoilA_zero(void) +{ + coilA_Zero=GetMeanAdc(ISENSE_FET_A,FET_DRIVER_NUM_ZERO_AVG); + LOG("Coil A Zero is %d",coilA_Zero); + return; +} + + +void FetDriver::CalTableA(int32_t maxMA) +{ + + int16_t table2[512]={0}; + int32_t pwm=0; + int32_t mA=0; + int i; + + + while (mA>-maxMA) + { + int32_t adc; + //LOG("Running %d",pwm); + adc=GetMeanAdc(ISENSE_FET_A,10)-coilA_Zero; + //LOG("ADC is %d",adc); + mA=FET_ADC_TO_MA(adc); + //LOG("mA is %d, ADC %d",mA,ADC); + pwm=pwm-1; + + if (coilA_PWM(pwm)==1) + { + ERROR("CoilA PWM maxed"); + break; + } + //delay(5); + } + + //LOG("First PWM is %d %d",pwm, mA); + PWM_Table_A[0]=pwm; + table2[0]=mA; + i=1; + while (i<512) + { + int32_t adc; + adc=GetMeanAdc(ISENSE_FET_A,10)-coilA_Zero; + mA=FET_ADC_TO_MA(adc); + + //LOG("PWM %d, %d %d",i,mA,pwm); + if (mA>((i-255)*maxMA/256)) + { + PWM_Table_A[i]=pwm; + table2[i]=mA; + i++; + }else + { + pwm=pwm+1; + coilA_PWM(pwm); + //delay(5); + } + } + coilA_PWM(0); + + Serial.print("\n\r TABLE A \n\r");; + for (i=0; i<512; i++) + { + Serial.print(PWM_Table_A[i]); + Serial.print(","); + } + Serial.print("\n\r"); + + Serial.print("\n\r"); + for (i=0; i<512; i++) + { + Serial.print(table2[i]); + Serial.print(","); + } + Serial.print("\n\r"); +} + +void FetDriver::CalTableB(int32_t maxMA) +{ + + int16_t table2[512]={0}; + int32_t pwm=0; + int32_t mA=0; + int i; + + while (mA>-maxMA) + { + int32_t adc; + adc=GetMeanAdc(ISENSE_FET_B,10)-coilB_Zero; + mA=FET_ADC_TO_MA(adc); + pwm=pwm-1; + coilB_PWM(pwm); + //delay(5); + } + + //LOG("First PWM is %d %d",pwm, mA); + PWM_Table_B[0]=pwm; + table2[0]=mA; + i=1; + while (i<512) + { + int32_t adc; + adc=GetMeanAdc(ISENSE_FET_B,10)-coilB_Zero; + mA=FET_ADC_TO_MA(adc); + + //LOG("PWM %d, %d %d",i,mA,pwm); + if (mA>((i-255)*maxMA/256)) + { + PWM_Table_B[i]=pwm; + table2[i]=mA; + i++; + }else + { + pwm=pwm+1; + coilB_PWM(pwm); + //delay(5); + } + } + + coilB_PWM(0); + Serial.print("\n\r TABLE B \n\r"); + for (i=0; i<512; i++) + { + Serial.print(PWM_Table_B[i]); + Serial.print(","); + } + Serial.print("\n\r"); + + Serial.print("\n\r"); + for (i=0; i<512; i++) + { + Serial.print(table2[i]); + Serial.print(","); + } + Serial.print("\n\r"); +} + + +void FetDriver::begin() +{ + int16_t i; + uint32_t t0; + int32_t i0=0; + uint32_t zero,x,k; + int32_t max_mA; + + + ptrInstance=(FetDriver *)this; + //enable 1V reference + SYSCTRL->VREF.reg |= SYSCTRL_VREF_BGOUTEN; + ADCRead(ISENSE_FET_A); //setup the adc with fast timing + //nt32_t min,max,avg; + //Setup the FET inputs + GPIO_OUTPUT(PIN_FET_IN1); + GPIO_OUTPUT(PIN_FET_IN2); + GPIO_OUTPUT(PIN_FET_IN3); + GPIO_OUTPUT(PIN_FET_IN4); + GPIO_OUTPUT(PIN_FET_ENABLE); + GPIO_HIGH(PIN_FET_ENABLE); + + //setup the Pin peripheral setting correct + pinPeripheral(PIN_FET_IN2, PIO_TIMER_ALT); //TCC0 WO[7] + pinPeripheral(PIN_FET_IN1, PIO_TIMER_ALT); + SET_PIN_PERHERIAL(PIN_FET_IN4, PIO_TIMER_ALT); //TCC0 WO[7] + SET_PIN_PERHERIAL(PIN_FET_IN3, PIO_TIMER_ALT); + + pinPeripheral(ISENSE_FET_A, PIO_ANALOG); //AIN[0] + pinPeripheral(ISENSE_FET_B, PIO_ANALOG); //AIN[2] + + enableTCC0(); + coilB_PWM(0); + coilA_PWM(0); + delay(100); + measureCoilA_zero(); + measureCoilB_zero(); + + +// ADCStart(ISENSE_FET_A); + + + //return; +// while(1) +// { +// LOG("tick %d %d", TCC0->CC[1].reg,TCC0->CC[0].reg); +// LOG("%d %d",coilA_error,coilB_error); +// } + +// uint16_t data[1000]; +// ADCRead(ISENSE_FET_A); +// +// t0=micros(); +// GPIO_LOW(PIN_FET_IN2); +// GPIO_GPIO_OUTPUT(PIN_FET_IN2); +// GPIO_HIGH(PIN_FET_IN1); +// GPIO_GPIO_OUTPUT(PIN_FET_IN1); +// +// for (i=0; i<1000; i++) +// { +// data[i]=fastADCRead(ISENSE_FET_A); +// } +// coilA_PWM(0); +// +// t0=micros()-t0; +// +// Serial.print("\n\r Step response \n\r"); +// Serial.print(t0); +// +// Serial.print("\n\r Step response \n\r"); +// for (i=0; i<1000; i++) +// { +// Serial.print(data[i]); +// Serial.print(","); +// } +// Serial.print("\n\r"); +// +// while(1) +// { +// +// } + max_mA=NVM->motorParams.currentMa; + WARNING("Maximum current is %d",max_mA); + + + if (NVM->motorParams.parametersVaild && max_mA!=0) + { + CalTableA(max_mA); + CalTableB(max_mA); + + }else + { + WARNING("NVM is not correct default to 1500mA"); + max_mA=1500; + WARNING("calibrating phase A %dmA",max_mA); + CalTableA(max_mA); + WARNING("calibrating phase B %dmA",max_mA); + CalTableB(max_mA); + + } + return; + + //coilA_PWM(100); + + x=0; + while(1) + { + //LOG("Trying to move motor %d",x); + delay(1); + move(x, 1000); + x=x+256; + + } + + + return; // all done + + // //set DAC to mid level + // syncDAC(); + // DAC->DATA.reg = 0x2FF; // DAC on 10 bits. + // syncDAC(); + // DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC + // syncDAC(); + + // WARNING("Running ADC ISR test"); + // ADCRead(3); + + //LOG("coil value %d %d",coilB_value,coilB_Zero); + i=47; + x=0; + while(1) + { + int32_t adc,value; + int32_t mA; + + if (0) + { + + coilB_PWM(i); + delayMicroseconds(1000); + //LOG("%d",i); + //if (i==47 ) delay(50); + + if (x==0) + { + i=i+1; + if (i>200) + { + x=1; + //i=47; + + } + } + + if (x == 1) + { + i=i-1; + if (i<47) + { + x=2; + i=-47; + } + + } + + if (x == 2) + { + i=i-1; + if (i<-200) + { + x=3; + } + } + + if (x == 3) + { + i=i+1; + if (i>-47) + { + x=0; + i=47; + } + } + }else + { + + adc=ADCRead(ISENSE_FET_A); + value=adc-coilA_Zero; + + mA=(value*2206)/1000; + + + + // + //delay(500); + //NVIC_DisableIRQ(ADC_IRQn); + + LOG("coil A %d %d, %d ",coilA_Zero, value, mA ); + + } + // NVIC_DisableIRQ(ADC_IRQn); + // + // NVIC_EnableIRQ(ADC_IRQn); + } + + x=0; + for (k=0; k<128; k++) + { + x=x+ADCRead(8); + } + zero=x/32; + + //setupDAC(); + //setDAC(5,5); + enableTCC0(); + //setupComparators(); + + + ERROR("Enable PWM"); + pinPeripheral(PIN_FET_IN4, PIO_TIMER_ALT); //TCC0 WO[7] + + // + // for (i=40; i<55; i++) + // { + // coilB_PWM(i); + // delay(200); + // ADCRead(8,16); + // LOG("COMP is 0x%04X ", AC->STATUSA.reg); + // LOG("%d ADC is %d ",i, ADCRead(8,16)); + // YELLOW_LED(0); + // } + + //ADCRead(8,16); + //AC->INTENCLR.bit.COMP1=1; + //coilA_Value=0; + + coilB_PWM(0); + + i=47; + coilB_PWM(i); + while(1) + { + int32_t x=0,k; + coilB_PWM(i); + delay(3000); + for (k=0; k<128; k++) + { + x=x+ADCRead(8); + } + x=x/32; + LOG("%d %d %d",i,x-zero,(x*3300)/(4096*4)); + LOG("%d",((x-zero)*5517)/10000); + + i=i+20; + if (i>140) + { + i=47; + } + + } + /* AC->INTENSET.bit.COMP1=1; + while(1) + { + AC->INTENCLR.bit.COMP1=1; + YELLOW_LED(0); + AC->INTENSET.bit.COMP1=1; + if ((millis()-t0)>10000) + { + int j; + min=0xFFFFFF; + max=(int16_t)ADCRead(8,16); + avg=0; + j=0; + t0=micros(); + while( (micros()-t0)<1000) + { + int16_t valueRead; + + valueRead = ADCRead(8,16); + + if (valueReadmax) + { + max=valueRead; + } + avg+=valueRead; + j++; + } + + + int32_t ma,x,duty; + duty=i-45; + duty=(1000*duty)/(F_CPU/FET_DRIVER_FREQ); + + LOG("min %d max %d, avg %d j %d, %d", min, max, (avg*10)/j, j,(avg*10)/j*(1000-duty)/1000); + + x=(avg*10)/j*(1000-duty)/1000; + x=(x*600)/1000+200; + + LOG("mA %d\n\r",x); + + if (i<150) + { + i=100; + }else + { + i=45; + } + LOG("COMP is 0x%04X ", AC->STATUSA.reg); + LOG("%d ADC is %d %d",i, ADCRead(8,16),coilA_Value); + t0=millis(); + AC->INTENCLR.bit.COMP1=1; + coilA_Value=0; + coilB_PWM(i); + AC->INTENSET.bit.COMP1=1; + } + } + */ + return; + + //setup the PWM for current on the A4954, set for low current + digitalWrite(PIN_A4954_VREF12,LOW); + digitalWrite(PIN_A4954_VREF34,LOW); + pinMode(PIN_A4954_VREF34, OUTPUT); + pinMode(PIN_A4954_VREF12, OUTPUT); + + enabled=true; + lastStepMicros=0; + forwardRotation=true; + + enableTCC0(); + setupDAC(); + // + // WARNING("Setting DAC for 500mA output"); + // setDAC((int32_t)((int64_t)1000*(DAC_MAX))/3300,(int32_t)((int64_t)1000*(DAC_MAX))/3300); + // bridge1(0); + // bridge2(0); + // while(1) + // { + // + // } + return; +} + + + + + + + + +int32_t FetDriver::getCoilB_mA(void) +{ + int32_t adc,ret; + //fastADCRead(ISENSE_FET_B); + adc=(int32_t)fastADCRead(ISENSE_FET_B); + ret=FET_ADC_TO_MA(adc-coilB_Zero); + //LOG("coilb %d %d",adc,ret); + return ret; +} +int32_t FetDriver::getCoilA_mA(void) +{ + int32_t adc,ret; + //fastADCRead(ISENSE_FET_A); + adc=(int32_t)fastADCRead(ISENSE_FET_A); + ret=FET_ADC_TO_MA(adc-coilA_Zero); + //LOG("coila %d %d",adc,ret); + return ret; +} + + +//this is precise move and modulo of A4954_NUM_MICROSTEPS is a full step. +// stepAngle is in A4954_NUM_MICROSTEPS units.. +// The A4954 has no idea where the motor is, so the calling function has to +// to tell the A4954 what phase to drive motor coils. +// A4954_NUM_MICROSTEPS is 256 by default so stepAngle of 1024 is 360 degrees +// Note you can only move up to +/-A4954_NUM_MICROSTEPS from where you +// currently are. +int32_t FetDriver::move(int32_t stepAngle, uint32_t mA) +{ + uint16_t angle; + int32_t cos,sin; + int32_t dacSin,dacCos; + int32_t dacSin_mA,dacCos_mA; + int32_t maxMa; + static int32_t last_dacSin_mA=0,last_dacCos_mA=0;; + if (enabled == false) + { + WARNING("FET Driver disabled"); + + //turn the current off to FETs + coilA_PWM(0); + coilB_PWM(0); + + //float the FET outputs by disabling FET driver. + GPIO_LOW(PIN_FET_ENABLE); + return stepAngle; + } + GPIO_HIGH(PIN_FET_ENABLE); + + + maxMa=NVM->motorParams.currentMa; + if (maxMa==0) + { + maxMa=2200; + } + + //WARNING("move %d %d",stepAngle,mA); + //handle roll overs, could do with modulo operator + //stepAngle=stepAngle%SINE_STEPS; + // while (stepAngle<0) + // { + // stepAngle=stepAngle+SINE_STEPS; + // } + // while (stepAngle>=SINE_STEPS) + // { + // stepAngle=stepAngle-SINE_STEPS; + // } + + //figure out our sine Angle + // note our SINE_STEPS is 4x of microsteps for a reason + //angle=(stepAngle+(SINE_STEPS/8)) % SINE_STEPS; + angle=(stepAngle) % SINE_STEPS; + //calculate the sine and cosine of our angle + sin=sine(angle); + cos=cosine(angle); + + //if we are reverse swap the sign of one of the angels + if (false == forwardRotation) + { + cos=-cos; + } + + //LOG("sin/cos %d %d %d", sin,cos,angle); + //scale sine result by current(mA) + dacSin_mA=((int32_t)mA*(int32_t)(sin))/SINE_MAX; + + //scale cosine result by current(mA) + dacCos_mA=((int32_t)mA*(int32_t)(cos))/SINE_MAX; + + coilA_SetPoint=FET_MA_TO_ADC(dacSin_mA); + coilB_SetPoint=FET_MA_TO_ADC(dacCos_mA); + //LOG("sin/cos %d %d", dacSin,dacCos); + + //convert value into 12bit DAC scaled to 3300mA max + dacSin=(int32_t)((int64_t)dacSin_mA*(255))/maxMa; + + //convert value into 12bit DAC scaled to 3300mA max + dacCos=(int32_t)((int64_t)dacCos_mA*(255))/maxMa; + + //LOG("sin/cos %d %d", dacSin,dacCos); + //limit the table index to +/-255 + dacCos=MIN(dacCos,(int32_t)255); + dacCos=MAX(dacCos,(int32_t)-255); + dacSin=MIN(dacSin,(int32_t)255); + dacSin=MAX(dacSin,(int32_t)-255); + + + if ((dacSin_mA-last_dacSin_mA)>200) + { + GPIO_LOW(PIN_FET_IN2); + PIN_GPIO_OUTPUT(PIN_FET_IN2); + GPIO_HIGH(PIN_FET_IN1); + PIN_GPIO_OUTPUT(PIN_FET_IN1); + }else if ((dacSin_mA-last_dacSin_mA)<-200) + { + GPIO_HIGH(PIN_FET_IN2); + PIN_GPIO_OUTPUT(PIN_FET_IN2); + GPIO_LOW(PIN_FET_IN1); + PIN_GPIO_OUTPUT(PIN_FET_IN1); + } + + if ((dacCos_mA-last_dacCos_mA)>200) + { + GPIO_LOW(PIN_FET_IN4); + PIN_GPIO_OUTPUT(PIN_FET_IN4); + GPIO_HIGH(PIN_FET_IN3); + PIN_GPIO_OUTPUT(PIN_FET_IN3); + }else if ((dacCos_mA-last_dacCos_mA)<-200) + { + GPIO_HIGH(PIN_FET_IN4); + PIN_GPIO_OUTPUT(PIN_FET_IN4); + GPIO_LOW(PIN_FET_IN3); + PIN_GPIO_OUTPUT(PIN_FET_IN3); + } + delayMicroseconds(20); + last_dacSin_mA=dacSin_mA; + last_dacCos_mA=dacCos_mA; + +// YELLOW_LED(1); +// uint32_t t0=micros(); +// int done=0; +// int32_t a,b; +// a=FET_MA_TO_ADC(dacSin_mA); +// b=FET_MA_TO_ADC(dacCos_mA); +// while ((micros()-t0)<20 && done!=0x03) +// { +// if ( (fastADCRead(ISENSE_FET_A)-a)FET_MA_TO_ADC(200)) +// { +// GPIO_HIGH(PIN_FET_IN2); +// PIN_GPIO_OUTPUT(PIN_FET_IN2); +// GPIO_LOW(PIN_FET_IN1); +// PIN_GPIO_OUTPUT(PIN_FET_IN1); +// done |=0x01; +// } +// if ((fastADCRead(ISENSE_FET_B)-b)FET_MA_TO_ADC(200)) +// { +// GPIO_HIGH(PIN_FET_IN4); +// PIN_GPIO_OUTPUT(PIN_FET_IN4); +// GPIO_LOW(PIN_FET_IN3); +// PIN_GPIO_OUTPUT(PIN_FET_IN3); +// done |=0x02; +// } +// +// } +// +// YELLOW_LED(0); + + + //LOG("sin/cos %d %d", dacSin,dacCos); + //loop up the current from table and set the PWM + coilA_PWM(PWM_Table_A[dacSin+255]); + coilB_PWM(PWM_Table_B[dacCos+255]); + + lastStepMicros=micros(); + return stepAngle; +} +#pragma GCC pop_options //fast optimization + +#endif //NEMA_23_10A_HW + +#pragma GCC pop_options diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.h b/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.h new file mode 100644 index 0000000..a056897 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/fet_driver.h @@ -0,0 +1,124 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef FET_DRIVER_H_ +#define FET_DRIVER_H_ + + + +#include +#include "board.h" +#include "angle.h" +#include "sine.h" + +#ifdef NEMA_23_10A_HW +#define FET_DRIVER_NUM_MICROSTEPS (SINE_STEPS/4) //number of steps to use for microstepping, default is 256 +#define FET_DRIVER_NUM_ZERO_AVG (100) + + +#define FET_ADC_TO_MA(x) (((x)*2537)/1000) +#define FET_MA_TO_ADC(x) (((x)*1000)/2537) +//prvent someone for making a mistake with the code +#if ((FET_DRIVER_NUM_MICROSTEPS*4) != SINE_STEPS) +#error "SINE_STEPS must be 4x of Micro steps for the move function" +#endif + +/* + * When it comes to the stepper driver if we use angles + * we will always have a rounding error. For example + * a 0-65536(360) angle for 1.8 degree step is 327.68 so + * if you increment 200 of these as 327 you have a 13.6 error + * after one rotation. + * If you use floating point the effect is the same but takes longer. + * + * The only error-less accumulation system is to use native units, ie full + * steps and microsteps. + * + */ + +class FetDriver +{ + static FetDriver *ptrInstance; +private: + uint32_t lastStepMicros; // time in microseconds that last step happened + + int32_t PWM_Table_B[512]; + int32_t PWM_Table_A[512]; + + bool forwardRotation=true; + volatile bool enabled=true; + + volatile int32_t adc; + + + volatile int32_t coilB_value=0; + volatile int32_t coilB_Zero=-1; + volatile int32_t coilB_SetPoint=100; + volatile int32_t coilB_error=0; + + volatile int32_t coilA_value=0; + volatile int32_t coilA_Zero=-1; + volatile int32_t coilA_SetPoint=200; + volatile int32_t coilA_error=0; + void ctrl_update(uint16_t channel, uint16_t value); + void measureCoilB_zero(void); + void measureCoilA_zero(void); + void CalTableB(int32_t maxMA); + void CalTableA(int32_t maxMA); + int coilA_PWM(int32_t value); + void coilB_PWM(int32_t value); + int32_t getCoilB_mA(void); + int32_t getCoilA_mA(void); +public: + + static void ADC_Callback(uint16_t channel, uint16_t value); + void begin(void); + + //moves motor where the modulo of A4954_NUM_MICROSTEPS is a full step. + int32_t move(int32_t stepAngle, uint32_t mA); + + uint32_t microsSinceStep(void) {return micros()-lastStepMicros;}; + void setRotationDirection(bool forward) {forwardRotation=forward;}; + + void enable(bool enable) {enabled=enable;}; + void limitCurrent(uint8_t x) {return;}; +}; + + +#endif //#ifdef NEMA_23_10A_HW +#endif /* FET_DRIVER_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.cpp new file mode 100644 index 0000000..8ff7f42 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.cpp @@ -0,0 +1,193 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "board.h" +#include "ftoa.h" +/******************************************************************* + * FUNCTION: ftoa + * AUTHOR = TRAMPAS STERN + * FILE = strio.c + * DATE = 2/6/2003 4:27:14 PM + * + * PARAMETERS: long,*str, int count + * + * DESCRIPTION: Convets an float to string + * format 'f', 'E', or 'e' + * + * + * RETURNS: + * + * NOTE this code was found on the web and modified to actually work + *******************************************************************/ + int ftoa (float x, char *str, char prec, char format) + { + + int ie, i, k, ndig, fstyle; + double y; + char *start; + + start=str; + + //based on percission set number digits + ndig=prec+1; + if (prec<0) + ndig=7; + if (prec>22) + ndig=23; + + fstyle = 0; //exponent 'e' + if (format == 'f' || format == 'F') + fstyle = 1; //normal 'f' + if (format=='g' || format=='G') + fstyle=2; + + ie = 0; + /* if x negative, write minus and reverse */ + if ( x < 0) + { + *str++ = '-'; + x = -x; + } + + //if (x<0.0) then increment by 10 till betwen 1.0 and 10.0 + if (x!=0.0) + { + while (x < 1.0) + { + x =x* 10.0; + ie--; + } + } + + //if x>10 then let's shift it down + while (x >= 10.0) + { + x = x*(1.0/10.0); + ie++; + } + + if (ABS(ie)>MAX_MANTISA) + { + if (fstyle==1) + { + fstyle=0; + format='e'; + //ie=2; + } + } + + + /* in f format, number of digits is related to size */ + if (fstyle) + ndig =ndig + ie; + + if(prec==0 && ie>ndig && fstyle) + { + ndig=ie; + } + + /* round. x is between 1 and 10 and ndig will be printed to + right of decimal point so rounding is ... */ + y=1; + for (i = 1; i < ndig; i++) //find lest significant digit + y = y *(1.0/10.0); //multiply by 1/10 is faster than divides + + x = x+ y *(1.0/2.0); //add rounding + + /* repair rounding disasters */ + if (x >= 10.0) + { + x = 1.0; + ie++; + ndig++; + } + + //check and see if the number is less than 1.0 + if (fstyle && ie<0) + { + *str++ = '0'; + if (prec!=0) + *str++ = '.'; + if (ndig < 0) + ie = ie-ndig; /* limit zeros if underflow */ + for (i = -1; i > ie; i--) + *str++ = '0'; + } + + //for each digit + for (i=0; i < ndig; i++) + { + float b; + k = x; //k = most significant digit + *str++ = k + '0'; //output the char representation + if (((!fstyle && i==0) || (fstyle && i==ie)) && prec!=0) + *str++ = '.'; //output a decimal point + b=(float)k; + //multiply by 10 before subtraction to remove + //errors from limited number of bits in float. + b=b*10.0; + x=x*10.0; + x =x - b; //subtract k from x + //b=x+b; + //x =x* 10.0; //get next digit + } + + /* now, in estyle, put out exponent if not zero */ + if (!fstyle && ie != 0) + { + *str++ = format; + if (ie < 0) //if number has negative exponent + { + ie = -ie; + *str++ = '-'; + } + + //now we need to convert the exponent to string + for (k=1000; k>ie; k=k/10); //find the decade of exponent + + for (; k > 0; k=k/10) + { + char t; + t=DIV(ie,k); + *str++ = t + '0'; + ie = ie -(t*k); + } + + } + *str++ = '\0'; + return (str-start); //return string length + } diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.h b/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.h new file mode 100644 index 0000000..55000ff --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/ftoa.h @@ -0,0 +1,48 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef FTOA_H_ +#define FTOA_H_ + +#define MAX_MANTISA (1000) + +int ftoa (float x, char *str, char prec, char format); + + + +#endif /* FTOA_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/gfxfont.h b/firmware_smartstepper_trikarus/stepper_nano_zero/gfxfont.h new file mode 100644 index 0000000..07381ed --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/gfxfont.h @@ -0,0 +1,24 @@ +// Font structures for newer Adafruit_GFX (1.1 and later). +// Example fonts are included in 'Fonts' directory. +// To use a font in your Arduino sketch, #include the corresponding .h +// file and pass address of GFXfont struct to setFont(). Pass NULL to +// revert to 'classic' fixed-space bitmap font. + +#ifndef _GFXFONT_H_ +#define _GFXFONT_H_ + +typedef struct { // Data stored PER GLYPH + uint16_t bitmapOffset; // Pointer into GFXfont->bitmap + uint8_t width, height; // Bitmap dimensions in pixels + uint8_t xAdvance; // Distance to advance cursor (x axis) + int8_t xOffset, yOffset; // Dist from cursor pos to UL corner +} GFXglyph; + +typedef struct { // Data stored for FONT AS A WHOLE: + uint8_t *bitmap; // Glyph bitmaps, concatenated + GFXglyph *glyph; // Glyph array + uint8_t first, last; // ASCII extents + uint8_t yAdvance; // Newline distance (y axis) +} GFXfont; + +#endif // _GFXFONT_H_ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/glcdfont.c b/firmware_smartstepper_trikarus/stepper_nano_zero/glcdfont.c new file mode 100644 index 0000000..6f88bd2 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/glcdfont.c @@ -0,0 +1,276 @@ +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ + #include + #include +#elif defined(ESP8266) + #include +#else + #define PROGMEM +#endif + +// Standard ASCII 5x7 font + +static const unsigned char font[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; +#endif // FONT5X7_H diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.cpp new file mode 100644 index 0000000..32d5465 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.cpp @@ -0,0 +1,145 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "nonvolatile.h" +#include "Flash.h" //thanks to Kent Larsen for pointing out the lower case error +#include + + + + +//we use this so we can hard code calibration table +// be sure to set the last word as status flag +// this save time calibrating each time we do a code build +#ifdef NZS_FAST_CAL +__attribute__((__aligned__(FLASH_ROW_SIZE))) const uint16_t NVM_flash[16767]={ //allocates 33280 bytes +#else +__attribute__((__aligned__(FLASH_ROW_SIZE))) const uint16_t NVM_flash[256]={ //allocates 512 bytes +#endif +25758,26078,26399,26720,27043,27372,27698,28024,28353,28688,29017,29345,29671,30009,30340,30663,30997,31335,31664,31994,32325,32666,32997,33324,33661,33997,34330,34657,34986,35324,35653,35981,36303,36637,36962,37282,37605,37938,38260,38581,38901,39232,39554,39877,40198,40528,40849,41178,41500,41835,42163,42485,42815,43149,43475,43804,44139,44476,44801,45136,45460,45804,46130,46460,46790,47119,47449,47777,48103,48442,48772,49099,49424,49759,50087,50410,50735,51067,51394,51716,52045,52379,52703,53024,53348,53680,54002,54326,54648,54987,55309,55629,55958,56292,56612,56936,57262,57594,57917,58246,58569,58902,59225,59552,59873,60206,60534,60862,61192,61531,61864,62194,62529,62873,63210,63544,63878,64222,64562,64899,65241,45,384,719,1058,1398,1733,2058,2390,2732,3060,3394,3720,4056,4386,4710,5036,5366,5693,6016,6340,6665,6989,7308,7622,7952,8263,8586,8903,9232,9551,9874,10200,10534,10859,11185,11513,11852,12184,12514,12848,13185,13511,13841,14170,14504,14830,15156,15490,15827,16153,16481,16808,17143,17474,17801,18121,18458,18783,19111,19433,19765,20084,20405,20721,21045,21360,21673,21984,22305,22614,22922,23231,23551,23861,24173,24482,24808,25118,25435, + + 0xFFFF +}; + + + +static_assert (sizeof(nvm_t)CalibrationTable,ptrData,size); + return true; +} + +bool nvmWrite_sPID(float Kp, float Ki, float Kd) +{ + PIDparams_t pid; + + pid.Kp=Kp; + pid.Ki=Ki; + pid.Kd=Kd; + pid.parametersVaild=true; + + flashWrite((void *)&NVM->sPID,&pid,sizeof(pid)); + return true; +} + +bool nvmWrite_vPID(float Kp, float Ki, float Kd) +{ + PIDparams_t pid; + + pid.Kp=Kp; + pid.Ki=Ki; + pid.Kd=Kd; + pid.parametersVaild=true; + + flashWrite((void *)&NVM->vPID,&pid,sizeof(pid)); + return true; +} + +bool nvmWrite_pPID(float Kp, float Ki, float Kd) +{ + PIDparams_t pid; + + pid.Kp=Kp; + pid.Ki=Ki; + pid.Kd=Kd; + pid.parametersVaild=true; + + flashWrite((void *)&NVM->pPID,&pid,sizeof(pid)); + return true; +} + +bool nvmWriteSystemParms(SystemParams_t &systemParams) +{ + systemParams.parametersVaild=true; + + flashWrite((void *)&NVM->SystemParams,&systemParams,sizeof(systemParams)); + return true; +} + +bool nvmWriteMotorParms(MotorParams_t &motorParams) +{ + motorParams.parametersVaild=true; + + flashWrite((void *)&NVM->motorParams,&motorParams,sizeof(motorParams)); + return true; +} + +bool nvmErase(void) +{ + bool data=false; + uint16_t cs=0; + + flashWrite((void *)&NVM->CalibrationTable.status,&data,sizeof(data)); + flashWrite((void *)&NVM->sPID.parametersVaild ,&data,sizeof(data)); + flashWrite((void *)&NVM->vPID.parametersVaild ,&data,sizeof(data)); + flashWrite((void *)&NVM->pPID.parametersVaild ,&data,sizeof(data)); + flashWrite((void *)&NVM->motorParams.parametersVaild ,&data,sizeof(data)); + flashWrite((void *)&NVM->SystemParams.parametersVaild ,&data,sizeof(data)); +#ifdef NZS_FAST_CAL + flashWrite((void *)&NVM->FastCal.checkSum,&cs,sizeof(cs)); +#endif +} + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.h b/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.h new file mode 100644 index 0000000..3e29c03 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nonvolatile.h @@ -0,0 +1,108 @@ +/********************************************************************** + Copyright (C) 2018 MisfitTech LLC, All rights reserved. + + MisfitTech uses a dual license model that allows the software to be used under + a standard GPL open source license, or a commercial license. The standard GPL + license requires that all software statically linked with MisfitTec Code is + also distributed under the same GPL V2 license terms. Details of both license + options follow: + + - Open source licensing - + MisfitTech is a free download and may be used, modified, evaluated and + distributed without charge provided the user adheres to version two of the GNU + General Public License (GPL) and does not remove the copyright notice or this + text. The GPL V2 text is available on the gnu.org web site + + - Commercial licensing - + Businesses and individuals that for commercial or other reasons cannot comply + with the terms of the GPL V2 license must obtain a low cost commercial license + before incorporating MisfitTech code into proprietary software for distribution in + any form. Commercial licenses can be purchased from www.misfittech.net + and do not require any source files to be changed. + + + This code is distributed in the hope that it will be useful. You cannot + use MisfitTech's code unless you agree that you use the software 'as is'. + MisfitTech's code is provided WITHOUT ANY WARRANTY; without even the implied + warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. MisfitTech LLC disclaims all conditions and terms, be they + implied, expressed, or statutory. + + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __NONVOLATILE__H__ +#define __NONVOLATILE__H__ + +#include "calibration.h" +#include "board.h" + + +typedef struct { + float Kp; + float Ki; + float Kd; + bool parametersVaild; +} PIDparams_t; + +typedef struct { + int32_t currentMa; //maximum current for the motor + int32_t currentHoldMa; //hold current for the motor + int32_t homeMa; //maximum current when error homing + int32_t homeHoldMa; //hold current when error homing + bool motorWiring; //forward wiring of motor or reverse + int32_t fullStepsPerRotation; //how many full steps per rotation is the motor + bool parametersVaild; +} MotorParams_t; + +typedef struct { + int32_t microsteps; //number of microsteps on the dir/step pin interface from host + RotationDir_t dirPinRotation; //is the direction pin high for clockwise or counterClockWise + int32_t errorLimit; //error limit before error pin asserts 65536==360degrees + ErrorPinMode_t errorPinMode; //is error pin used for enable, error, or bidirectional + feedbackCtrl_t controllerMode; //feedback mode for the controller + int32_t homePin; //if greater than zero this is the pin we use trigger home current settings + bool errorLogic; //if high and error will be high on output pin + int32_t homeAngleDelay; //the angle to delay before switching to lower homing current + bool parametersVaild; +} SystemParams_t; + +#ifdef NZS_FAST_CAL +typedef struct { + uint16_t angle[16384]; + uint16_t checkSum; +}FastCal_t; +#endif + +typedef struct { + FlashCalData_t CalibrationTable; + __attribute__((__aligned__(8))) PIDparams_t sPID; //simple PID parameters + __attribute__((__aligned__(8))) PIDparams_t pPID; //position PID parameters + __attribute__((__aligned__(8))) PIDparams_t vPID; //velocity PID parameters + __attribute__((__aligned__(8))) SystemParams_t SystemParams; + __attribute__((__aligned__(8))) MotorParams_t motorParams; +#ifdef NZS_FAST_CAL + __attribute__((__aligned__(8))) FastCal_t FastCal; +#endif +} nvm_t; + +#ifdef NZS_FAST_CAL +extern const uint16_t NVM_flash[16767]; +#else +extern const uint16_t NVM_flash[256]; +#endif +#define NVM ((const nvm_t *)NVM_flash) + +bool nvmWriteCalTable(void *ptrData, uint32_t size); +bool nvmWrite_sPID(float Kp, float Ki, float Kd); +bool nvmWrite_pPID(float Kp, float Ki, float Kd); +bool nvmWrite_vPID(float Kp, float Ki, float Kd); +bool nvmWriteSystemParms(SystemParams_t &systemParams); +bool nvmWriteMotorParms(MotorParams_t &motorParams); +bool nvmErase(void); + +#endif // __NONVOLATILE__H__ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.cpp new file mode 100644 index 0000000..cc2dbbd --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.cpp @@ -0,0 +1,902 @@ +/* + * nzs.cpp + * + * Created on: Dec 8, 2016 + * Author: trampas + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#include "nzs.h" +#include "commands.h" +#include "nonvolatile.h" +#include "angle.h" +#include "eeprom.h" +#include "steppin.h" +#include "wiring_private.h" + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +eepromData_t PowerupEEPROM={0}; + + +volatile bool enableState=true; + +int32_t dataEnabled=0; + +StepperCtrl stepperCtrl; +LCD Lcd; + +int menuCalibrate(int argc, char *argv[]) +{ + stepperCtrl.calibrateEncoder(); +} + +int menuTestCal(int argc, char *argv[]) +{ + Angle error; + int32_t x,y; + char str[25]; + error=stepperCtrl.maxCalibrationError(); + + x=(36000*(int32_t)error)/ANGLE_STEPS; + LOG("Error %d %d", (int32_t)error, x); + y=x/100; + x=x-(y*100); + x=abs(x); + sprintf(str, "%d.%02d deg",y,x); +#ifndef DISABLE_LCD + Lcd.lcdShow("Cal Error", str,""); +#endif + + LOG("Calibration error %s",str); +#ifndef MECHADUINO_HARDWARE + while(digitalRead(PIN_SW3)==1) + { + //wait for button press + } + while(digitalRead(PIN_SW3)==0) + { + //wait for button release + } +#endif +} + +static options_t stepOptions[] { + {"200"}, + {"400"}, + {""}, +}; + +//returns the index of the stepOptions when called +// with no arguments. +int motorSteps(int argc, char *argv[]) +{ + if (argc==0) + { + int i; + i=NVM->motorParams.fullStepsPerRotation; + if (i==400) + { + return 1; + } + return 0; //default to 200 + } + if (argc>0) + { + int32_t i; + MotorParams_t params; + memcpy((void *)¶ms, (void *)&NVM->motorParams, sizeof(params)); + i=atol(argv[0]); + if (i!=params.fullStepsPerRotation) + { + params.fullStepsPerRotation=i; + nvmWriteMotorParms(params); + } + } + + return 0; +} + +static options_t currentOptions[] { + {"0"}, + {"100"}, + {"200"}, + {"300"}, + {"400"}, + {"500"}, + {"600"}, + {"700"}, + {"800"}, + {"900"}, + {"1000"}, + {"1100"}, + {"1200"}, + {"1300"}, + {"1400"}, + {"1500"}, + {"1600"}, + {"1700"}, + {"1800"}, + {"1900"}, + {"2000"}, + {"2100"}, + {"2200"}, + {"2300"}, + {"2400"}, + {"2500"}, + {"2600"}, + {"2700"}, + {"2800"}, + {"2900"}, + {"3000"}, + {"3100"}, + {"3200"}, + {"3300"}, + {""}, +}; + +int motorCurrent(int argc, char *argv[]) +{ + LOG("called motorCurrent %d",argc); + if (argc==1) + { + int i; + LOG("called %s",argv[0]); + i=atol(argv[0]); + i=i*100; + MotorParams_t params; + memcpy((void *)¶ms, (void *)&NVM->motorParams, sizeof(params)); + if (i!=params.currentMa) + { + params.currentMa=i; + nvmWriteMotorParms(params); + } + return i/100; + } + int i; + i=NVM->motorParams.currentMa/100; + LOG(" motorCurrent return %d",i); + return i; + +} + +int motorHoldCurrent(int argc, char *argv[]) +{ + if (argc==1) + { + int i; + i=atol(argv[0]); + i=i*100; + MotorParams_t params; + memcpy((void *)¶ms, (void *)&NVM->motorParams, sizeof(params)); + if (i!=params.currentHoldMa) + { + params.currentHoldMa=i; + nvmWriteMotorParms(params); + } + return i/100; + }else + { + int i; + i=NVM->motorParams.currentHoldMa/100; + return i; + } +} + +static options_t microstepOptions[] { + {"1"}, + {"2"}, + {"4"}, + {"8"}, + {"16"}, + {"32"}, + {"64"}, + {"128"}, + {"256"}, + {""} +}; + +int microsteps(int argc, char *argv[]) +{ + if (argc==1) + { + int i,steps; + i=atol(argv[0]); + SystemParams_t params; + memcpy((void *)¶ms, (void *)&NVM->SystemParams, sizeof(params)); + steps=0x01<SystemParams.microsteps; + for (j=0; j<9; j++) + { + + if ((0x01<SystemParams, sizeof(params)); + if (i!=params.controllerMode) + { + params.controllerMode=(feedbackCtrl_t)i; + nvmWriteSystemParms(params); + } + return i; + } + return NVM->SystemParams.controllerMode; +} + + + + +#ifndef PIN_ENABLE +static options_t errorPinOptions[] { + {"Enable"}, + {"!Enable"}, //error pin works like enable on step sticks + {"Error"}, + // {"BiDir"}, //12/12/2016 not implemented yet + {""} +}; + +int errorPin(int argc, char *argv[]) +{ + if (argc==1) + { + int i; + i=atol(argv[0]); + SystemParams_t params; + memcpy((void *)¶ms, (void *)&NVM->SystemParams, sizeof(params)); + if (i!=params.errorPinMode) + { + params.errorPinMode=(ErrorPinMode_t)i; + nvmWriteSystemParms(params); + } + return i; + } + return NVM->SystemParams.errorPinMode; +} +#else + + static options_t errorPinOptions[] { + {"Enable"}, + {"!Enable"}, //error pin works like enable on step sticks + // {"Error"}, + // {"BiDir"}, //12/12/2016 not implemented yet + {""} + }; + + int enablePin(int argc, char *argv[]) + { + if (argc==1) + { + int i; + i=atol(argv[0]); + SystemParams_t params; + memcpy((void *)¶ms, (void *)&NVM->SystemParams, sizeof(params)); + if (i!=params.errorPinMode) + { + params.errorPinMode=(ErrorPinMode_t)i; + nvmWriteSystemParms(params); + } + return i; + } + return NVM->SystemParams.errorPinMode; + } + +#endif + +static options_t dirPinOptions[] { + {"High CW"}, + {"High CCW"}, + {""} +}; + +int dirPin(int argc, char *argv[]) +{ + if (argc==1) + { + int i; + i=atol(argv[0]); + SystemParams_t params; + memcpy((void *)¶ms, (void *)&NVM->SystemParams, sizeof(params)); + if (i!=params.dirPinRotation) + { + params.dirPinRotation=(RotationDir_t)i; + nvmWriteSystemParms(params); + } + return i; + } + return NVM->SystemParams.dirPinRotation; +} + + +static menuItem_t MenuMain[] { + {"Calibrate", menuCalibrate,NULL}, + {"Test Cal", menuTestCal,NULL}, + // {"Mtr steps", motorSteps,stepOptions}, NOT GOOD for user to call this + {"Motor mA", motorCurrent,currentOptions}, + {"Hold mA", motorHoldCurrent,currentOptions}, + {"Microstep", microsteps,microstepOptions}, + // {"Ctlr Mode", controlLoop,controlLoopOptions}, //this may not be good for user to call +#ifndef PIN_ENABLE + {"Error Pin", errorPin,errorPinOptions}, +#else + {"EnablePin", enablePin,errorPinOptions}, +#endif + {"Dir Pin", dirPin,dirPinOptions}, + + + { "", NULL} +}; + +static menuItem_t MenuCal[] { + {"Calibrate", menuCalibrate,NULL}, + //{"Test Cal", menuTestCal,NULL}, + { "", NULL} +}; + + + + + + +//this function is called when error pin changes as enable signal +static void enableInput(void) +{ + static bool lastState=true; +#ifdef PIN_ENABLE + if (NVM->SystemParams.errorPinMode == ERROR_PIN_MODE_ENABLE) + { + static int enable; + //read our enable pin + enable = digitalRead(PIN_ENABLE); + if (enable != enableState) + { + WARNING("Enable now %d",enable); + } + enableState=enable; + //stepperCtrl.enable(enable); + } + if (NVM->SystemParams.errorPinMode == ERROR_PIN_MODE_ACTIVE_LOW_ENABLE) + { + static int enable; + //read our enable pin + enable = !digitalRead(PIN_ENABLE); + if (enable != enableState) + { + WARNING("Enable now %d",enable); + } + enableState=enable; + //stepperCtrl.enable(enable); + } +#else + if (NVM->SystemParams.errorPinMode == ERROR_PIN_MODE_ENABLE) + { + static int enable; + //read our enable pin + enable = digitalRead(PIN_ERROR); + enableState=enable; + //stepperCtrl.enable(enable); + } + if (NVM->SystemParams.errorPinMode == ERROR_PIN_MODE_ACTIVE_LOW_ENABLE) + { + static int enable; + //read our enable pin + enable = !digitalRead(PIN_ERROR); + enableState=enable; + //stepperCtrl.enable(enable); + } +#endif + +#ifdef USE_STEP_DIR_SERIAL + + static uint8_t pinCFG[2]; + static uint8_t pinMux[2]; + if (enableState == false && lastState==true) + { + // turn the step/dir to serial port + + //save pin config for restoring + pinCFG[0]=getPinCfg(PIN_STEP_INPUT); + pinCFG[1]=getPinCfg(PIN_DIR_INPUT); + pinMux[0]=getPinMux(PIN_STEP_INPUT); + pinMux[1]=getPinMux(PIN_DIR_INPUT); + + //lets see if the step pin has interrupt enabled + if (pinMux[0] == PORT_PMUX_PMUXE_A_Val) + { + EExt_Interrupts in = g_APinDescription[PIN_STEP_INPUT].ulExtInt; + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT(1 << in); //disable the interrupt + //we need to disable the interrupt + } + + //now we need to set the pins to serial port peripheral (sercom0) + setPinMux(PIN_STEP_INPUT,PORT_PMUX_PMUXE_C_Val); + setPinMux(PIN_DIR_INPUT,PORT_PMUX_PMUXE_C_Val); + + //make sure that step pin is input with mux to peripheral + setPinCfg(PIN_STEP_INPUT, PORT_PINCFG_PMUXEN | PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); + + //make sure that dir pin is an output with mux to peripheral + setPinCfg(PIN_DIR_INPUT, PORT_PINCFG_PMUXEN ); + + Serial1.begin(STEP_DIR_BAUD); + + } + if (enableState == true && lastState==false) + { + Serial1.end(); + setPinMux(PIN_STEP_INPUT,pinMux[0]); + setPinMux(PIN_DIR_INPUT,pinMux[1]); + setPinCfg(PIN_STEP_INPUT,pinCFG[0]); + setPinCfg(PIN_DIR_INPUT,pinCFG[1]); + //turn step/dir pins back to GPIO + if (PORT_PMUX_PMUXE_A_Val == pinMux[0]) + { + //if interrupt was enabled for step pin renable it. + EExt_Interrupts in = g_APinDescription[PIN_STEP_INPUT].ulExtInt; + EIC->INTENSET.reg = EIC_INTENCLR_EXTINT(1 << in); //enable the interrupt + } + + } + +#endif //USE_STEP_DIR_SERIAL + lastState=enableState; +} + + + + + +void TC5_Handler() +{ +// static bool led=false; +// YELLOW_LED(led); +// led=!led; + interrupts(); //allow other interrupts + if (TC5->COUNT16.INTFLAG.bit.OVF == 1) + { + int error=0; + + + error=(stepperCtrl.processFeedback()); //handle the control loop + YELLOW_LED(error); +#ifdef PIN_ENABLE + GPIO_OUTPUT(PIN_ERROR); + bool level; + level = !NVM->SystemParams.errorLogic; + if (error) + { //assume high is inactive and low is active on error pin + digitalWrite(PIN_ERROR,level); + }else + { + digitalWrite(PIN_ERROR,!level); + } +#else + + if (NVM->SystemParams.errorPinMode == ERROR_PIN_MODE_ERROR) + { + GPIO_OUTPUT(PIN_ERROR); + if (error) + { //assume high is inactive and low is active on error pin + digitalWrite(PIN_ERROR,LOW); + }else + { + digitalWrite(PIN_ERROR,HIGH); + } + } +#endif + TC5->COUNT16.INTFLAG.bit.OVF = 1; // writing a one clears the flag ovf flag + } + +} + +//check the NVM and set to defaults if there is any +void validateAndInitNVMParams(void) +{ + + if (false == NVM->sPID.parametersVaild) + { + nvmWrite_sPID(0.9,0.0001, 0.01); + } + + if (false == NVM->pPID.parametersVaild) + { + nvmWrite_pPID(1.0, 0, 0); + } + + if (false == NVM->vPID.parametersVaild) + { + nvmWrite_vPID(2.0, 1.0, 1.0); + } + + if (false == NVM->SystemParams.parametersVaild) + { + SystemParams_t params; + params.microsteps=16; + #if defined(CTRL_POS_PID_AS_DEFAULT) + params.controllerMode=CTRL_POS_PID; + #else + params.controllerMode=CTRL_SIMPLE; + #endif + + params.dirPinRotation=CW_ROTATION; //default to clockwise rotation when dir is high + params.errorLimit=(int32_t)ANGLE_FROM_DEGREES(1.8); + params.errorPinMode=ERROR_PIN_MODE_ENABLE; //default to enable pin + params.homePin=-1; + params.errorLogic=false; + params.homeAngleDelay=ANGLE_FROM_DEGREES(10); + nvmWriteSystemParms(params); + } + + //the motor parameters are check in the stepper_controller code + // as that there we can auto set much of them. + + +} + + + +void SYSCTRL_Handler(void) +{ + if (SYSCTRL->INTFLAG.reg & SYSCTRL_INTFLAG_BOD33DET) + { + eepromFlush(); //flush the eeprom + SYSCTRL->INTFLAG.reg |= SYSCTRL_INTFLAG_BOD33DET; + } +} + +// Wait for synchronization of registers between the clock domains +static __inline__ void syncBOD33(void) __attribute__((always_inline, unused)); +static void syncBOD33(void) { + //int32_t t0=1000; + while (SYSCTRL->PCLKSR.bit.BOD33RDY==1) + { + // t0--; + // if (t0==0) + // { + // break; + // } + } +} +static void configure_bod(void) +{ + //syncBOD33(); + //SYSCTRL->BOD33.reg=0; //disable BOD33 before starting + //syncBOD33(); + SYSCTRL->BOD33.reg=SYSCTRL_BOD33_ACTION_INTERRUPT | //generate interrupt when BOD is triggered + SYSCTRL_BOD33_LEVEL(48) | //about 3.2V + //SYSCTRL_BOD33_HYST | //enable hysteresis + SYSCTRL_BOD33_ENABLE; //turn module on + + LOG("BOD33 %02X", SYSCTRL->BOD33.reg ); + SYSCTRL->INTENSET.reg |= SYSCTRL_INTENSET_BOD33DET; + + NVIC_SetPriority(SYSCTRL_IRQn, 1); //make highest priority as we need to save eeprom + // Enable InterruptVector + NVIC_EnableIRQ(SYSCTRL_IRQn); +} + + +void NZS::begin(void) +{ + int to=20; + stepCtrlError_t stepCtrlError; + + //set up the pins correctly on the board. + boardSetupPins(); + + //start up the USB serial interface + //TODO check for power on USB before doing this... +#ifndef MECHADUINO_HARDWARE + SerialUSB.begin(SERIAL_BAUD); +#endif + + //setup the serial port for syslog + Serial5.begin(SERIAL_BAUD); + + +#ifndef CMD_SERIAL_PORT + SysLogInit(&Serial5,LOG_DEBUG); + pinPeripheral(PIN_TXD, PIO_SERCOM_ALT); + pinPeripheral(PIN_RXD, PIO_SERCOM_ALT); +#else + SysLogInit(NULL, LOG_WARNING); +#endif + + LOG("Power up!"); + pinMode(PIN_USB_PWR, INPUT); + +#ifndef MECHADUINO_HARDWARE + if (digitalRead(PIN_USB_PWR)) + { + //wait for USB serial port to come alive + while (!SerialUSB) + { + to--; + if (to == 0) + { + break; + } + delay(500); + }; //wait for serial + } else + { + WARNING("USB Not connected"); + } +#endif + + validateAndInitNVMParams(); + + LOG("EEPROM INIT"); + if (EEPROM_OK == eepromInit()) //init the EEPROM + { + eepromRead((uint8_t *)&PowerupEEPROM, sizeof(PowerupEEPROM)); + } + configure_bod(); //configure the BOD +#ifndef DISABLE_LCD + LOG("Testing LCD"); + Lcd.begin(&stepperCtrl); + +#ifdef A5995_DRIVER + Lcd.lcdShow("MisfitTech","NEMA 23", VERSION); +#else + Lcd.lcdShow("MisfitTech","NEMA 17", VERSION); +#endif + +#endif + + LOG("command init!"); + commandsInit(); //setup command handler system + + + stepCtrlError=STEPCTRL_NO_CAL; + + + while (STEPCTRL_NO_ERROR != stepCtrlError) + { + LOG("init the stepper controller"); + stepCtrlError=stepperCtrl.begin(); //start controller before accepting step inputs + + //todo we need to handle error on LCD and through command line + if (STEPCTRL_NO_POWER == stepCtrlError) + { +#ifndef MECHADUINO_HARDWARE + SerialUSB.println("Appears that there is no Motor Power"); + SerialUSB.println("Connect motor power!"); +#else + Serial5.println("Appears that there is no Motor Power"); + Serial5.println("Connect motor power!"); +#endif +#ifndef DISABLE_LCD + Lcd.lcdShow("Waiting", "MOTOR", "POWER"); +#endif + while (STEPCTRL_NO_POWER == stepCtrlError) + { + stepCtrlError=stepperCtrl.begin(); //start controller before accepting step inputs + } + + } + + if (STEPCTRL_NO_CAL == stepCtrlError) + { +#ifndef MECHADUINO_HARDWARE + SerialUSB.println("You need to Calibrate"); +#else + Serial5.println("You need to Calibrate"); +#endif +#ifndef DISABLE_LCD + Lcd.lcdShow(" NOT ", "Calibrated", " "); + delay(1000); + Lcd.setMenu(MenuCal); + Lcd.forceMenuActive(); +#endif + + //TODO add code here for LCD and command line loop + while(false == stepperCtrl.calibrationValid()) + { + commandsProcess(); //handle commands + +#ifndef DISABLE_LCD + Lcd.process(); +#endif + + } + +#ifndef DISABLE_LCD + Lcd.setMenu(NULL); +#endif + } + + if (STEPCTRL_NO_ENCODER == stepCtrlError) + { +#ifndef MECHADUINO_HARDWARE + SerialUSB.println("AS5047D not working"); + SerialUSB.println(" try disconnecting power from board for 15+mins"); + SerialUSB.println(" you might have to short out power pins to ground"); +#else + Serial5.println("AS5047D not working"); + Serial5.println(" try disconnecting power from board for 15+mins"); + Serial5.println(" you might have to short out power pins to ground"); +#endif +#ifndef DISABLE_LCD + Lcd.lcdShow("Encoder", " Error!", " REBOOT"); +#endif + while(1) + { + + } + } + + } +#ifndef DISABLE_LCD + Lcd.setMenu(MenuMain); +#endif + + stepPinSetup(); //setup the step pin + +#ifdef PIN_ENABLE + //attachInterrupt(digitalPinToInterrupt(PIN_ENABLE), enableInput, CHANGE); + NVIC_SetPriority(EIC_IRQn, 0); //set port A interrupt as highest priority +#else + attachInterrupt(digitalPinToInterrupt(PIN_ERROR), enableInput, CHANGE); +#endif + + SmartPlanner.begin(&stepperCtrl); + RED_LED(false); + LOG("SETUP DONE!"); +} + + +void printLocation(void) +{ + char buf[128]={0}; + Location_t loc; + int32_t n, i, len; + int32_t pktSize; + + if (dataEnabled==0) + { + //RED_LED(false); + return; + } + + //the packet length for binary print is 12bytes + // assuming rate of 6Khz this would be 72,000 baud + i=0; + n=stepperCtrl.getLocation(&loc); + if (n==-1) + { + //RED_LED(false); + return; + } + + len=0; + pktSize=sizeof(Location_t)+1; //packet lenght is size location plus sync byte + + // //binary write + + while(n>=0 && (len)<=(128-pktSize)) + { + memcpy(&buf[len],&loc,sizeof(Location_t)); + len+=sizeof(Location_t); + buf[len]=0XAA; //sync + len++; + buf[len]=sizeof(Location_t); //data len + len++; + + n=stepperCtrl.getLocation(&loc); + i++; + } +#ifndef MECHADUINO_HARDWARE + SerialUSB.write(buf,len); +#endif + + //hex write + // hex write is 29 bytes per tick, @ 6khz this 174000 baud + // while(n>=0 && (i*29)<(200-29)) + // { + // sprintf(buf,"%s%08X\t%08X\t%08X\n\r",buf,loc.microSecs,loc.desiredLoc,loc.actualLoc); + // n=stepperCtrl.getLocation(&loc); + // i++; + // } + // SerialUSB.write(buf,strlen(buf)); + +// if (n<=0) +// { +// RED_LED(false); +// }else +// { +// RED_LED(true); +// } + + return; +} + +void NZS::loop(void) +{ + eepromData_t eepromData; + + + // if (dataEnabled==0) + // { + // LOG("loop time is %dus",stepperCtrl.getLoopTime()); + // } + + //read the enable pin and update + // this is also done as an edge interrupt but does not always see + // to trigger the ISR. + enableInput(); + + if (enableState != stepperCtrl.getEnable()) + { + stepperCtrl.enable(enableState); + } + + //handle EEPROM + eepromData.angle=stepperCtrl.getCurrentAngle(); + eepromData.encoderAngle=stepperCtrl.getEncoderAngle(); + eepromData.valid=1; + eepromWriteCache((uint8_t *)&eepromData,sizeof(eepromData)); + + commandsProcess(); //handle commands +#ifndef DISABLE_LCD + Lcd.process(); +#endif + //stepperCtrl.PrintData(); //prints steps and angle to serial USB. + + + printLocation(); //print out the current location + + return; +} + +#pragma GCC pop_options diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.h b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.h new file mode 100644 index 0000000..a21904d --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs.h @@ -0,0 +1,53 @@ +/* + * nzs.h + * + * Created on: Dec 8, 2016 + * Author: trampas + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef NZS_H_ +#define NZS_H_ + +#include "board.h" +#include "nzs_lcd.h" +#include "stepper_controller.h" +#include "planner.h" + +typedef struct +{ + int64_t angle; + uint16_t encoderAngle; + uint8_t valid; +}eepromData_t; + +class NZS //nano Zero Stepper +{ + + public: + void begin(void); + void loop(void); + +}; + + +#endif /* NZS_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.cpp new file mode 100644 index 0000000..b29051c --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.cpp @@ -0,0 +1,600 @@ +/* + * nzs_lcd.cpp + * + * Created on: Dec 8, 2016 + * Author: trampas + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#include "nzs_lcd.h" +#include +#include +#include + + +#ifndef DISABLE_LCD +void LCD::begin(StepperCtrl *ptrsCtrl) +{ +#ifndef MECHADUINO_HARDWARE + pinMode(PIN_SW1, INPUT_PULLUP); + pinMode(PIN_SW3, INPUT_PULLUP); + pinMode(PIN_SW4, INPUT_PULLUP); +#endif + buttonState=0; + + //we need access to the stepper controller + ptrStepperCtrl=ptrsCtrl; //save a pointer to the stepper controller + + + ptrMenu=NULL; + menuIndex=0; + menuActive=false; + optionIndex=0; + ptrOptions=NULL; + displayEnabled=true; + + //check that the SCL and SDA are pulled high + pinMode(PIN_SDA, INPUT); + pinMode(PIN_SCL, INPUT); + if (digitalRead(PIN_SDA)==0) + { + //pin is not pulled up + displayEnabled=false; + } + if (digitalRead(PIN_SCL)==0) + { + //pin is not pulled up + displayEnabled=false; + } + + if (displayEnabled) + { + displayEnabled=display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + }else + { + WARNING("SCL/SDA not pulled up"); + } + if (false == displayEnabled) + { + WARNING("NO display found, LCD will not be used"); + } + Wire.setClock(800000); + + //showSplash(); + +} + + +void __attribute__ ((optimize("Ofast"))) LCD::lcdShow(const char *line1, const char *line2,const char *line3) +{ + + if (false == displayEnabled) + { + return; + } + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println(line1); + display.setCursor(0,20); + display.println(line2); + display.setCursor(0,40); + display.println(line3); + display.display(); + +} + +void LCD::showSplash(void) +{ + if (false == displayEnabled) + { + return; + } +#ifdef A5995_DRIVER + lcdShow("MisfitTech","NEMA 23", VERSION); +#else + lcdShow("MisfitTech","NEMA 17", VERSION); +#endif +} + + +void LCD::setMenu(menuItem_t *pMenu) +{ + if (false == displayEnabled) + { + return; + } + ptrMenu=pMenu; + menuIndex=0; +} + + +void LCD::showOptions(void) +{ + int32_t i,j; + char str[3][26]={0}; + if (false == displayEnabled) + { + return; + } + + i=optionIndex; + j=0; + while(strlen(ptrOptions[i].str)>0 && j<3) + { + if (i == optionIndex) + { + sprintf(str[j],"*%s",ptrOptions[i].str); + }else + { + sprintf(str[j]," %s",ptrOptions[i].str); + } + j++; + i++; + } + + lcdShow(str[0], str[1], str[2]); + + return; +} + + +void __attribute__ ((optimize("Ofast"))) LCD::showMenu(void) +{ + int32_t i,j; + char str[3][26]={0}; + if (false == displayEnabled) + { + return; + } + + i=menuIndex; + j=0; + while(ptrMenu[i].func!=NULL && j<3) + { + if (i == menuIndex) + { + sprintf(str[j],"*%s",ptrMenu[i].str); + }else + { + sprintf(str[j]," %s",ptrMenu[i].str); + } + j++; + i++; + } + + //show exit if there is room + if (j<3) + { + if (j==0) + { + sprintf(str[j],"*Exit"); + }else + { + sprintf(str[j]," Exit"); + } + } + + lcdShow(str[0], str[1], str[2]); + + + return; +} + + +void __attribute__ ((optimize("Ofast"))) LCD::updateMenu(void) +{ + if (false == displayEnabled) + { + return; + } + + if (ptrOptions != NULL) + { + showOptions(); + }else + { + showMenu(); + } + + //handle push buttons + if (digitalRead(PIN_SW3)==0 && (buttonState & 0x02)==0) + { + buttonState |= 0x02; + + LOG("SW3 pressed"); + if (ptrMenu[menuIndex].func == NULL) + { + //exit pressed + menuIndex=0; //reset menu index + menuActive=false; + return; + } + + if (ptrMenu[menuIndex].func != NULL) + { + LOG("Calling function for %s",ptrMenu[menuIndex].str); + if (ptrOptions != NULL) + { + char *ptrArgV[1]; + char str[25]={0}; + ptrArgV[0]=str; + sprintf(str,"%d",optionIndex); + LOG("Calling function for %s %s",ptrMenu[menuIndex].str,str); + ptrMenu[menuIndex].func(1,ptrArgV); + ptrOptions=NULL; + optionIndex=0; + }else + { + int i; + i=ptrMenu[menuIndex].func(0,NULL); + if (ptrMenu[menuIndex].ptrOptions != NULL) + { + LOG("displaying options for %s %d",ptrMenu[menuIndex].str,i); + ptrOptions=ptrMenu[menuIndex].ptrOptions; + optionIndex=i; + } + } + + return; + } + + } + if (digitalRead(PIN_SW1)==0 && (buttonState & 0x01)==0) + { + buttonState |= 0x01; + LOG("SW1 pressed"); + if (ptrOptions != NULL) + { + optionIndex++; + if (strlen(ptrOptions[optionIndex].str) == 0) + { + optionIndex=0; + } + } else + { + if (ptrMenu[menuIndex].func != NULL) + { + menuIndex++; + } else + { + menuIndex=0; + } + } + + } + + if (digitalRead(PIN_SW1)) + { + buttonState &= ~0x01; + } + + if (digitalRead(PIN_SW3)) + { + buttonState &= ~0x02; + } +} + +void LCD::forceMenuActive(void) +{ + + menuActive=true; +} + +void __attribute__((optimize("Ofast")))LCD::process(void) +{ + if (false == displayEnabled) + { + return; + } + + if (false == menuActive || ptrMenu==NULL) + { + updateLCD(); + }else + { + updateMenu(); + } + + if (digitalRead(PIN_SW4)==0 && (buttonState & 0x04)==0) + { + buttonState |= 0x04; + menuActive=!menuActive; + } + + if (digitalRead(PIN_SW4)) + { + buttonState &= ~0x04; + } +} +#endif +/* +//does the LCD menu system +void StepperCtrl::menu(void) +{ + + bool done=false; + int menuItem=0; + char str[100]; + int sw1State=0; + int sw3State=0; + + pinMode(PIN_SW1, INPUT_PULLUP); + pinMode(PIN_SW3, INPUT_PULLUP); + pinMode(PIN_SW4, INPUT_PULLUP); + + + while (!done) + { + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + + if (menuItem==0) + { + sprintf(str,"*Run Cal"); + display.setCursor(0,0); + display.println(str); + }else + { + sprintf(str," Run Cal"); + display.setCursor(0,0); + display.println(str); + } + + if (menuItem==1) + { + sprintf(str,"*Check Cal"); + display.setCursor(0,20); + display.println(str); + }else + { + sprintf(str," Check Cal"); + display.setCursor(0,20); + display.println(str); + } + + if (menuItem==2) + { + sprintf(str,"*Exit"); + display.setCursor(0,40); + display.println(str); + }else + { + sprintf(str," Exit"); + display.setCursor(0,40); + display.println(str); + } + + display.display(); + + if (sw1State==1) + { + while (digitalRead(PIN_SW1)==0); + sw1State=0; + } + + if (digitalRead(PIN_SW1)==0) + { + sw1State=1; + menuItem=(menuItem+1)%3; + } + + if (sw3State==1) + { + while (digitalRead(PIN_SW3)==0); + sw3State=0; + } + + if (digitalRead(PIN_SW3)==0) + { + sw3State=1; + switch(menuItem) + { + case 0: + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println("Running"); + display.setCursor(0,20); + display.println("Cal"); + display.display(); + calibrateEncoder(); + break; + case 1: + { + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println("Testing"); + display.setCursor(0,20); + display.println("Cal"); + display.display(); + int32_t error,x,y,m; + error=maxCalibrationError(); + x=(error*100 *360)/ANGLE_STEPS; + m=x/100; + y=abs(x-(m*100)); + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(WHITE); + display.setCursor(0,0); + display.println("Error"); + + sprintf(str, "%02d.%02d deg",m,y); + display.setCursor(0,20); + display.println(str); + display.display(); + while (digitalRead(PIN_SW3)); + break; + } + case 2: + return; + break; + + } + + } + + } + +} + + */ + +void LCD::updateLCD(void) +{ + if (false == displayEnabled) + { + return; + } + char str[3][25]; + static int highRPM=0; + int32_t y,z,err; + + static int64_t lastAngle,deg; + static int32_t RPM=0; + static int32_t lasttime=0; + + bool state; + static int32_t dt=40; + static uint32_t t0=0; + + static bool rpmDone=false; + + if ((millis()-t0)>500) + { + + int32_t x,d; + + //do first half of RPM measurement + if (!rpmDone) + { + //LOG("loop time is %dus",ptrStepperCtrl->getLoopTime()); + lastAngle=ptrStepperCtrl->getCurrentAngle(); + lasttime=millis(); + rpmDone=true; + return; + } + + //do the second half of rpm measurement and update LCD. + if (rpmDone && (millis()-lasttime)>(dt)) + { + rpmDone=false; + deg=ptrStepperCtrl->getCurrentAngle(); + y=millis()-lasttime; + err=ptrStepperCtrl->getLoopError(); + + t0=millis(); + d=(int64_t)(lastAngle-deg); + + d=abs(d); + + x=0; + if (d>0) + { + x=((int64_t)d*(60*1000UL))/((int64_t)y * ANGLE_STEPS); + } + + lastAngle=deg; + RPM=(int32_t)x; //(7*RPM+x)/8; //average RPMs + if (RPM>500) + { + dt=10; + } + if (RPM<100) + { + dt=100; + } + str[0][0]='\0'; + //LOG("RPMs is %d, %d, %d",(int32_t)x,(int32_t)d,(int32_t)y); + switch(ptrStepperCtrl->getControlMode()) + { + case CTRL_SIMPLE: + sprintf(str[0], "%dRPM simp",RPM); + break; + case CTRL_TORQUE: + sprintf(str[0], "%dRPM torque",RPM); + break; + case CTRL_POS_PID: + sprintf(str[0], "%dRPM pPID",RPM); + break; + case CTRL_POS_VELOCITY_PID: + sprintf(str[0], "%dRPM vPID",RPM); + break; + case CTRL_OPEN: + sprintf(str[0], "%dRPM open",RPM); + break; + case CTRL_OFF: + sprintf(str[0], "%dRPM off",RPM); + break; + default: + sprintf(str[0], "error %u",ptrStepperCtrl->getControlMode()); + break; + + } + + + err=(err*360*100)/(int32_t)ANGLE_STEPS; + //LOG("error is %d %d %d",err,(int32_t)ptrStepperCtrl->getCurrentLocation(),(int32_t)ptrStepperCtrl->getDesiredLocation()); + z=(err)/100; + y=abs(err-(z*100)); + + sprintf(str[1],"%01d.%02d err", z,y); + + + deg=ptrStepperCtrl->getDesiredAngle(); + +#ifndef NZS_LCD_ABSOULTE_ANGLE + deg=deg & ANGLE_MAX; //limit to 360 degrees +#endif + + deg=(deg*360*10)/(int32_t)ANGLE_STEPS; + int K=0; + if (abs(deg)>9999) + { + K=1; + deg=deg/1000; + } + + x=(deg)/10; + y=abs(deg-(x*10)); + + if (K==1) + { + sprintf(str[2],"%03d.%01uKdeg", x,y); + }else + { + sprintf(str[2],"%03d.%01udeg", x,y); + } + str[0][10]='\0'; + str[1][10]='\0'; + str[2][10]='\0'; + lcdShow(str[0],str[1],str[2]); + } + } +} + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.h b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.h new file mode 100644 index 0000000..c3c4bac --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/nzs_lcd.h @@ -0,0 +1,90 @@ +/* + * nzs_lcd.h + * + * Created on: Dec 8, 2016 + * Author: trampas + * + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef NZS_LCD_H_ +#define NZS_LCD_H_ + +#include "Arduino.h" +#include "syslog.h" +#include "board.h" +#include "stepper_controller.h" + +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" +#include "gfxfont.h" + + +typedef struct { + char str[15]; +} options_t; + +typedef struct { + char str[15]; + + //only one of the following should be not null + int (*func)(int argc, char *argv[]); + options_t *ptrOptions; + +} menuItem_t; + + + + + +class LCD +{ + private: + bool displayEnabled; + Adafruit_SSD1306 display; + StepperCtrl *ptrStepperCtrl; + menuItem_t *ptrMenu; + int32_t menuIndex; + bool menuActive; + + options_t *ptrOptions; + int32_t optionIndex; + + int32_t buttonState; + + void updateLCD(void); + void showMenu(void); + void updateMenu(void); + void showOptions(void); + public: + void forceMenuActive(void); + void setMenu(menuItem_t *pMenu); + void begin(StepperCtrl *ptrStepperCtrl); //sets up the LCD + void process(void); //processes the LCD and updates as needed + void showSplash(void); + void lcdShow(const char *line1, const char *line2,const char *line3); + + +}; + + +#endif /* NZS_LCD_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/planner.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/planner.cpp new file mode 100644 index 0000000..ec37836 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/planner.cpp @@ -0,0 +1,207 @@ +/********************************************************************** + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "planner.h" + +#include "board.h" +#include "wiring_private.h" +#include "syslog.h" +#include "angle.h" +#include "Arduino.h" + +#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY); + +//define the planner class as being global +Planner SmartPlanner; + +static bool enterTC3CriticalSection() +{ + bool state=NVIC_IS_IRQ_ENABLED(TC3_IRQn); + NVIC_DisableIRQ(TC3_IRQn); + return state; +} + +static void exitTC3CriticalSection(bool prevState) +{ + if (prevState) + { + NVIC_EnableIRQ(TC3_IRQn); + } //else do nothing +} + + + + +void TC3_Init(void) +{ + // Enable GCLK for TC3 + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )) ; + while (GCLK->STATUS.bit.SYNCBUSY); + + TC3->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; // Disable TCx + WAIT_TC16_REGS_SYNC(TC3) // wait for sync + + TC3->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits + WAIT_TC16_REGS_SYNC(TC3) + + TC3->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; // Set TC as normal Normal Frq + WAIT_TC16_REGS_SYNC(TC3) + + TC3->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV2; // Set perscaler + WAIT_TC16_REGS_SYNC(TC3) + + + TC3->COUNT16.CC[0].reg = F_CPU/PLANNER_UPDATE_RATE_HZ/2; //divide by two because of prescaler + + WAIT_TC16_REGS_SYNC(TC3) + + + TC3->COUNT16.INTENSET.reg = 0; // disable all interrupts + TC3->COUNT16.INTENSET.bit.OVF = 1; // enable overfollow + + + + NVIC_SetPriority(TC3_IRQn, 3); + + + // Enable InterruptVector + NVIC_EnableIRQ(TC3_IRQn); + + + // Enable TC + TC3->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; + WAIT_TC16_REGS_SYNC(TC3); +} + + +void TC3_Handler(void) +{ + interrupts(); //allow other interrupts + //do the planner tick + SmartPlanner.tick(); + //SerialUSB.println('x'); + TC3->COUNT16.INTFLAG.bit.OVF = 1; //clear interrupt by writing 1 to flag +} + +void Planner::begin(StepperCtrl *ptrStepper) +{ + + ptrStepperCtrl=ptrStepper; + currentMode=PLANNER_NONE; + //setup the timer and interrupt as the last thing + TC3_Init(); +} + +void Planner::tick(void) +{ + if (currentMode == PLANNER_NONE) + { + return; //do nothing + } + + if (PLANNER_CV == currentMode) + { +// SerialUSB.println(currentSetAngle); +// SerialUSB.println(endAngle); +// SerialUSB.println(tickIncrement); +// SerialUSB.println(fabs(currentSetAngle-endAngle)); +// SerialUSB.println(fabs(tickIncrement*2)); +// SerialUSB.println(); + int32_t x; + if (fabs(currentSetAngle-endAngle) >= fabs(tickIncrement)) + { + currentSetAngle+=tickIncrement; + x=ANGLE_FROM_DEGREES(currentSetAngle); + ptrStepperCtrl->moveToAbsAngle(x); + }else + { + //we are done, make sure we end at the right point + //SerialUSB.println("done"); + x=ANGLE_FROM_DEGREES(endAngle); + ptrStepperCtrl->moveToAbsAngle(x); + currentMode=PLANNER_NONE; + } + } + + +} + +void Planner::stop(void) +{ + bool state; + state = enterTC3CriticalSection(); + currentMode=PLANNER_NONE; + exitTC3CriticalSection(state); +} + +bool Planner::moveConstantVelocity(float finalAngle, float rpm) +{ + bool state; + state = enterTC3CriticalSection(); + + //first determine if operation is in progress + if (PLANNER_NONE != currentMode) + { +#ifndef MECHADUINO_HARDWARE + //we are in operation return false + SerialUSB.println("planner operational"); +#else + Serial5.println("planner operational"); +#endif + exitTC3CriticalSection(state); + return false; + } + + //get current posistion + startAngle = ANGLE_T0_DEGREES(ptrStepperCtrl->getCurrentAngle()); + + //deterime the tick increment + tickIncrement=360.0*fabs(rpm)/60/PLANNER_UPDATE_RATE_HZ; + + + + //set the desired end angle + endAngle=finalAngle; + + + //set the current angle + currentSetAngle=startAngle; + + if (startAngle>endAngle) + { +#ifndef MECHADUINO_HARDWARE + SerialUSB.println("reverse"); +#endif + tickIncrement=-tickIncrement; + } + +// SerialUSB.println(currentSetAngle); +// SerialUSB.println(endAngle); +// SerialUSB.println(tickIncrement); +// SerialUSB.println(); + + currentMode=PLANNER_CV; + + exitTC3CriticalSection(state); + return true; +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/planner.h b/firmware_smartstepper_trikarus/stepper_nano_zero/planner.h new file mode 100644 index 0000000..e80b8b1 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/planner.h @@ -0,0 +1,68 @@ +/********************************************************************** + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +/* + * This file implements a trajectory planner for use with serial + * interface. It allows the smart stepper to move at constant velocity. + * Additionally you can move to some location at constant velocity or + * with a trajectory curve + */ + +#ifndef PLANNER_H_ +#define PLANNER_H_ +#include "board.h" +#include "stepper_controller.h" + +#define PLANNER_UPDATE_RATE_HZ (3000UL) //how often planner updates PID + +typedef enum { + PLANNER_NONE =0, + PLANNER_CV =1, //constant velocity + //PLANNER_CA =2, //constant accleration + //PLANNER_S_CURVE =3, //s-curve move +} PlannerMode; +class Planner +{ + private: + StepperCtrl *ptrStepperCtrl; + volatile PlannerMode currentMode=PLANNER_NONE; + //todo we should not use floating point, rather use "Angle" + volatile float endAngle; + volatile float startAngle; + volatile float currentSetAngle; + volatile float tickIncrement; + + public: + void begin(StepperCtrl *ptrStepper); + bool moveConstantVelocity(float finalAngle, float rpm); //moves to the final location at a constant RPM + void tick(void); //this is called on regular tick interval + void stop(void); + bool done(void) {return currentMode==PLANNER_NONE;} +}; + + +extern Planner SmartPlanner; + + +#endif /* PLANNER_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/sine.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/sine.cpp new file mode 100644 index 0000000..8c2e22c --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/sine.cpp @@ -0,0 +1,198 @@ +/* + * since.cpp + * + * Created on: Dec 24, 2016 + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#include "sine.h" + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +#ifdef NZS_FAST_SINE +static const int16_t sineTable[1280]={ +0,201,402,603,804,1005,1206,1407,1608,1808,2009,2210,2410,2611,2811,3011, +3212,3412,3611,3811,4011,4210,4410,4609,4808,5007,5205,5404,5602,5800,5998,6195, +6392,6589,6786,6983,7179,7375,7571,7766,7962,8156,8351,8545,8739,8933,9126,9319, +9512,9704,9896,10087,10278,10469,10659,10849,11039,11228,11417,11605,11793,11980,12167,12353, +12539,12725,12910,13094,13278,13462,13645,13828,14010,14191,14372,14553,14732,14912,15090,15269, +15446,15623,15800,15976,16151,16325,16499,16673,16846,17018,17189,17360,17530,17700,17869,18037, +18204,18371,18537,18703,18868,19032,19195,19357,19519,19680,19841,20000,20159,20317,20475,20631, +20787,20942,21097,21250,21403,21554,21705,21856,22005,22154,22301,22448,22594,22739,22884,23027, +23170,23312,23452,23592,23732,23870,24007,24143,24279,24413,24547,24680,24812,24942,25072,25201, +25329,25456,25583,25708,25832,25955,26077,26199,26319,26438,26556,26674,26790,26905,27019,27133, +27245,27356,27466,27575,27683,27791,27897,28001,28105,28208,28310,28411,28510,28609,28706,28803, +28898,28992,29085,29178,29268,29358,29447,29535,29621,29707,29791,29874,29956,30037,30117,30195, +30273,30349,30425,30499,30572,30643,30714,30783,30852,30919,30985,31050,31113,31176,31237,31297, +31356,31414,31471,31526,31580,31633,31685,31736,31785,31834,31881,31926,31971,32015,32057,32098, +32138,32176,32214,32250,32285,32319,32351,32382,32413,32441,32469,32496,32521,32545,32568,32589, +32609,32629,32646,32663,32678,32693,32706,32717,32728,32737,32745,32752,32757,32762,32765,32767, +32767,32767,32765,32762,32757,32752,32745,32737,32728,32717,32706,32693,32678,32663,32646,32629, +32609,32589,32568,32545,32521,32496,32469,32441,32413,32382,32351,32319,32285,32250,32214,32176, +32138,32098,32057,32015,31971,31926,31881,31834,31785,31736,31685,31633,31580,31526,31471,31414, +31356,31297,31237,31176,31113,31050,30985,30919,30852,30783,30714,30643,30572,30499,30425,30349, +30273,30195,30117,30037,29956,29874,29791,29707,29621,29535,29447,29358,29268,29178,29085,28992, +28898,28803,28706,28609,28510,28411,28310,28208,28105,28001,27897,27791,27683,27575,27466,27356, +27245,27133,27019,26905,26790,26674,26556,26438,26319,26199,26077,25955,25832,25708,25583,25456, +25329,25201,25072,24942,24812,24680,24547,24413,24279,24143,24007,23870,23732,23592,23452,23312, +23170,23027,22884,22739,22594,22448,22301,22154,22005,21856,21705,21554,21403,21250,21097,20942, +20787,20631,20475,20317,20159,20000,19841,19680,19519,19357,19195,19032,18868,18703,18537,18371, +18204,18037,17869,17700,17530,17360,17189,17018,16846,16673,16499,16325,16151,15976,15800,15623, +15446,15269,15090,14912,14732,14553,14372,14191,14010,13828,13645,13462,13278,13094,12910,12725, +12539,12353,12167,11980,11793,11605,11417,11228,11039,10849,10659,10469,10278,10087,9896,9704, +9512,9319,9126,8933,8739,8545,8351,8156,7962,7766,7571,7375,7179,6983,6786,6589, +6392,6195,5998,5800,5602,5404,5205,5007,4808,4609,4410,4210,4011,3811,3611,3412, +3212,3011,2811,2611,2410,2210,2009,1808,1608,1407,1206,1005,804,603,402,201, +0,-201,-402,-603,-804,-1005,-1206,-1407,-1608,-1809,-2010,-2210,-2411,-2611,-2812,-3012, +-3212,-3412,-3612,-3812,-4011,-4211,-4410,-4609,-4808,-5007,-5206,-5404,-5602,-5800,-5998,-6196, +-6393,-6590,-6787,-6983,-7180,-7376,-7571,-7767,-7962,-8157,-8352,-8546,-8740,-8933,-9127,-9320, +-9512,-9704,-9896,-10088,-10279,-10470,-10660,-10850,-11039,-11228,-11417,-11605,-11793,-11980,-12167,-12354, +-12540,-12725,-12910,-13095,-13279,-13463,-13646,-13828,-14010,-14192,-14373,-14553,-14733,-14912,-15091,-15269, +-15447,-15624,-15800,-15976,-16151,-16326,-16500,-16673,-16846,-17018,-17190,-17361,-17531,-17700,-17869,-18037, +-18205,-18372,-18538,-18703,-18868,-19032,-19195,-19358,-19520,-19681,-19841,-20001,-20160,-20318,-20475,-20632, +-20788,-20943,-21097,-21250,-21403,-21555,-21706,-21856,-22006,-22154,-22302,-22449,-22595,-22740,-22884,-23028, +-23170,-23312,-23453,-23593,-23732,-23870,-24007,-24144,-24279,-24414,-24548,-24680,-24812,-24943,-25073,-25202, +-25330,-25457,-25583,-25708,-25832,-25956,-26078,-26199,-26319,-26439,-26557,-26674,-26790,-26906,-27020,-27133, +-27245,-27357,-27467,-27576,-27684,-27791,-27897,-28002,-28106,-28209,-28310,-28411,-28511,-28609,-28707,-28803, +-28899,-28993,-29086,-29178,-29269,-29359,-29448,-29535,-29622,-29707,-29791,-29875,-29957,-30038,-30117,-30196, +-30273,-30350,-30425,-30499,-30572,-30644,-30715,-30784,-30852,-30919,-30985,-31050,-31114,-31176,-31238,-31298, +-31357,-31415,-31471,-31527,-31581,-31634,-31686,-31736,-31786,-31834,-31881,-31927,-31972,-32015,-32057,-32098, +-32138,-32177,-32214,-32250,-32285,-32319,-32352,-32383,-32413,-32442,-32470,-32496,-32521,-32545,-32568,-32590, +-32610,-32629,-32647,-32664,-32679,-32693,-32706,-32718,-32728,-32738,-32746,-32752,-32758,-32762,-32765,-32767, +-32768,-32767,-32765,-32762,-32758,-32752,-32746,-32738,-32728,-32718,-32706,-32693,-32679,-32664,-32647,-32629, +-32610,-32590,-32568,-32545,-32521,-32496,-32470,-32442,-32413,-32383,-32352,-32319,-32285,-32250,-32214,-32177, +-32138,-32098,-32057,-32015,-31972,-31927,-31881,-31834,-31786,-31736,-31686,-31634,-31581,-31527,-31471,-31415, +-31357,-31298,-31238,-31176,-31114,-31050,-30985,-30919,-30852,-30784,-30715,-30644,-30572,-30499,-30425,-30350, +-30273,-30196,-30117,-30038,-29957,-29875,-29791,-29707,-29622,-29535,-29448,-29359,-29269,-29178,-29086,-28993, +-28899,-28803,-28707,-28609,-28511,-28411,-28310,-28209,-28106,-28002,-27897,-27791,-27684,-27576,-27467,-27357, +-27245,-27133,-27020,-26906,-26790,-26674,-26557,-26439,-26319,-26199,-26078,-25956,-25832,-25708,-25583,-25457, +-25330,-25202,-25073,-24943,-24812,-24680,-24548,-24414,-24279,-24144,-24007,-23870,-23732,-23593,-23453,-23312, +-23170,-23028,-22884,-22740,-22595,-22449,-22302,-22154,-22006,-21856,-21706,-21555,-21403,-21250,-21097,-20943, +-20788,-20632,-20475,-20318,-20160,-20001,-19841,-19681,-19520,-19358,-19195,-19032,-18868,-18703,-18538,-18372, +-18205,-18037,-17869,-17700,-17531,-17361,-17190,-17018,-16846,-16673,-16500,-16326,-16151,-15976,-15800,-15624, +-15447,-15269,-15091,-14912,-14733,-14553,-14373,-14192,-14010,-13828,-13646,-13463,-13279,-13095,-12910,-12725, +-12540,-12354,-12167,-11980,-11793,-11605,-11417,-11228,-11039,-10850,-10660,-10470,-10279,-10088,-9896,-9704, +-9512,-9320,-9127,-8933,-8740,-8546,-8352,-8157,-7962,-7767,-7571,-7376,-7180,-6983,-6787,-6590, +-6393,-6196,-5998,-5800,-5602,-5404,-5206,-5007,-4808,-4609,-4410,-4211,-4011,-3812,-3612,-3412, +-3212,-3012,-2812,-2611,-2411,-2210,-2010,-1809,-1608,-1407,-1206,-1005,-804,-603,-402,-201, +0,201,402,603,804,1005,1206,1407,1608,1808,2009,2210,2410,2611,2811,3011, +3212,3412,3611,3811,4011,4210,4410,4609,4808,5007,5205,5404,5602,5800,5998,6195, +6392,6589,6786,6983,7179,7375,7571,7766,7962,8156,8351,8545,8739,8933,9126,9319, +9512,9704,9896,10087,10278,10469,10659,10849,11039,11228,11417,11605,11793,11980,12167,12353, +12539,12725,12910,13094,13278,13462,13645,13828,14010,14191,14372,14553,14732,14912,15090,15269, +15446,15623,15800,15976,16151,16325,16499,16673,16846,17018,17189,17360,17530,17700,17869,18037, +18204,18371,18537,18703,18868,19032,19195,19357,19519,19680,19841,20000,20159,20317,20475,20631, +20787,20942,21097,21250,21403,21554,21705,21856,22005,22154,22301,22448,22594,22739,22884,23027, +23170,23312,23452,23592,23732,23870,24007,24143,24279,24413,24547,24680,24812,24942,25072,25201, +25329,25456,25583,25708,25832,25955,26077,26199,26319,26438,26556,26674,26790,26905,27019,27133, +27245,27356,27466,27575,27683,27791,27897,28001,28105,28208,28310,28411,28510,28609,28706,28803, +28898,28992,29085,29178,29268,29358,29447,29535,29621,29707,29791,29874,29956,30037,30117,30195, +30273,30349,30425,30499,30572,30643,30714,30783,30852,30919,30985,31050,31113,31176,31237,31297, +31356,31414,31471,31526,31580,31633,31685,31736,31785,31834,31881,31926,31971,32015,32057,32098, +32138,32176,32214,32250,32285,32319,32351,32382,32413,32441,32469,32496,32521,32545,32568,32589, +32609,32629,32646,32663,32678,32693,32706,32717,32728,32737,32745,32752,32757,32762,32765,32767 +}; +#else +static const uint16_t sineTable[257]={ + 0,402,804,1206,1608,2010,2412,2814,3216,3617,4019,4420,4821,5222,5623,6023, + 6424,6824,7223,7623,8022,8421,8820,9218,9616,10014,10411,10808,11204,11600,11996,12391, + 12785,13179,13573,13966,14359,14751,15142,15533,15924,16313,16703,17091,17479,17866,18253,18639, + 19024,19408,19792,20175,20557,20939,21319,21699,22078,22456,22834,23210,23586,23960,24334,24707, + 25079,25450,25820,26189,26557,26925,27291,27656,28020,28383,28745,29106,29465,29824,30181,30538, + 30893,31247,31600,31952,32302,32651,32999,33346,33692,34036,34379,34721,35061,35400,35738,36074, + 36409,36743,37075,37406,37736,38064,38390,38715,39039,39361,39682,40001,40319,40635,40950,41263, + 41575,41885,42194,42500,42806,43109,43411,43712,44011,44308,44603,44897,45189,45479,45768,46055, + 46340,46624,46905,47185,47464,47740,48014,48287,48558,48827,49095,49360,49624,49885,50145,50403, + 50659,50913,51166,51416,51664,51911,52155,52398,52638,52877,53113,53348,53580,53811,54039,54266, + 54490,54713,54933,55151,55367,55582,55794,56003,56211,56417,56620,56822,57021,57218,57413,57606, + 57797,57985,58171,58356,58537,58717,58895,59070,59243,59414,59582,59749,59913,60075,60234,60391, + 60546,60699,60850,60998,61144,61287,61429,61567,61704,61838,61970,62100,62227,62352,62475,62595, + 62713,62829,62942,63053,63161,63267,63371,63472,63571,63668,63762,63853,63943,64030,64114,64196, + 64276,64353,64428,64500,64570,64638,64703,64765,64826,64883,64939,64992,65042,65090,65136,65179, + 65219,65258,65293,65327,65357,65386,65412,65435,65456,65475,65491,65504,65515,65524,65530,65534, + 65535, +}; +#endif + + + + +int16_t sine(uint16_t angle) +{ +#ifdef NZS_FAST_SINE + return sineTable[angle]; +#else + int sign=1; + int16_t ret; + //our sine table has 1024 points per rotation so convert angle to closest step + + if (angle>=(SINE_STEPS/2)) + { + sign=-1; + } + + angle=angle % (SINE_STEPS/2); //limit to 0-180 as sign takes care of 180-360 + + if (angle>(SINE_STEPS/4-1)) //if we are greater than 90 we need to look up table backwards + { + angle=(SINE_STEPS/2)-angle; + } + + ret=(int16_t)(sineTable[angle]/2)*sign; + return ret; +#endif +} + +int16_t cosine(uint16_t angle) +{ +#ifdef NZS_FAST_SINE + angle=angle+(SINE_STEPS/4); + return sineTable[angle]; +#else + + int sign=1; + int16_t ret; + //our sine table has 1024 points per rotation so convert angle to closest step + + if (angle>=(SINE_STEPS/4) and angle<(3*(SINE_STEPS/4))) + { + sign=-1; + } + + angle=angle % (SINE_STEPS/2); //limit to 0-180 as sign takes care of 180-360 + + if (angle>(SINE_STEPS/4-1)) //if we are greater than 90 we need to look up table backwards + { + angle=(SINE_STEPS/2)-angle; + } + + //for cosine we need 90 degree phase shift + angle=(SINE_STEPS/4)-angle; + + ret=(int16_t)(sineTable[angle]/2)*sign; + return ret; +#endif +} + +#pragma GCC pop_options diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/sine.h b/firmware_smartstepper_trikarus/stepper_nano_zero/sine.h new file mode 100644 index 0000000..8a039e4 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/sine.h @@ -0,0 +1,43 @@ +/********************************************************************** + * sine.h + * + * Created on: Dec 24, 2016 + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + + +#ifndef SINE_H_ +#define SINE_H_ + +#include "board.h" + +#define SINE_STEPS (1024L) + +#define SINE_MAX ((int32_t)(32768L)) + + +int16_t sine(uint16_t angle); +int16_t cosine(uint16_t angle); + + +#endif /* SINE_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_controller.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_controller.cpp new file mode 100644 index 0000000..a88774f --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_controller.cpp @@ -0,0 +1,1951 @@ +/********************************************************************** + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "stepper_controller.h" + +#include "nonvolatile.h" //for programmable parameters +#include +#include +#include "steppin.h" + +#pragma GCC push_options +#pragma GCC optimize ("-Ofast") + +#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY); + +volatile bool TC5_ISR_Enabled=false; + +void setupTCInterrupts() { + + // Enable GCLK for TC4 and TC5 (timer counter input clock) + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)); + while (GCLK->STATUS.bit.SYNCBUSY); + + TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE; // Disable TCx + WAIT_TC16_REGS_SYNC(TC5) // wait for sync + + TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16; // Set Timer counter Mode to 16 bits + WAIT_TC16_REGS_SYNC(TC5) + + TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; // Set TC as normal Normal Frq + WAIT_TC16_REGS_SYNC(TC5) + + TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1; // Set perscaler + WAIT_TC16_REGS_SYNC(TC5) + + + TC5->COUNT16.CC[0].reg = F_CPU/NZS_CONTROL_LOOP_HZ; + WAIT_TC16_REGS_SYNC(TC5) + + + TC5->COUNT16.INTENSET.reg = 0; // disable all interrupts + TC5->COUNT16.INTENSET.bit.OVF = 1; // enable overfollow + // TC5->COUNT16.INTENSET.bit.MC0 = 1; // enable compare match to CC0 + + + NVIC_SetPriority(TC5_IRQn, 2); + + + // Enable InterruptVector + NVIC_EnableIRQ(TC5_IRQn); + + + // Enable TC + TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; + WAIT_TC16_REGS_SYNC(TC5) + +} + +static void enableTCInterrupts() { + + TC5_ISR_Enabled=true; + NVIC_EnableIRQ(TC5_IRQn); + TC5->COUNT16.INTENSET.bit.OVF = 1; + // TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; //Enable TC5 + // WAIT_TC16_REGS_SYNC(TC5) //wait for sync +} + +static void disableTCInterrupts() { + + TC5_ISR_Enabled=false; + //NVIC_DisableIRQ(TC5_IRQn); + TC5->COUNT16.INTENCLR.bit.OVF = 1; +} + +static bool enterCriticalSection() +{ + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + return state; +} + +static void exitCriticalSection(bool prevState) +{ + if (prevState) + { + enableTCInterrupts(); + } //else do nothing +} + + +void StepperCtrl::updateParamsFromNVM(void) +{ + bool state=enterCriticalSection(); + + pPID.Kd=NVM->pPID.Kd*CTRL_PID_SCALING; + pPID.Ki=NVM->pPID.Ki*CTRL_PID_SCALING; + pPID.Kp=NVM->pPID.Kp*CTRL_PID_SCALING; + + vPID.Kd=NVM->vPID.Kd*CTRL_PID_SCALING; + vPID.Ki=NVM->vPID.Ki*CTRL_PID_SCALING; + vPID.Kp=NVM->vPID.Kp*CTRL_PID_SCALING; + + sPID.Kd=NVM->sPID.Kd*CTRL_PID_SCALING; + sPID.Ki=NVM->sPID.Ki*CTRL_PID_SCALING; + sPID.Kp=NVM->sPID.Kp*CTRL_PID_SCALING; + + if (NVM->SystemParams.parametersVaild) + { + memcpy((void *)&systemParams, (void *)&NVM->SystemParams, sizeof(systemParams)); + LOG("Home pin %d",systemParams.homePin); + + }else + { + ERROR("This should never happen but just in case"); + systemParams.microsteps=16; + #if defined(CTRL_POS_PID_AS_DEFAULT) + systemParams.controllerMode=CTRL_POS_PID; + #else + systemParams.controllerMode=CTRL_SIMPLE; + #endif + systemParams.dirPinRotation=CW_ROTATION; //default to clockwise rotation when dir is high + systemParams.errorLimit=(int32_t)ANGLE_FROM_DEGREES(1.8); + systemParams.errorPinMode=ERROR_PIN_MODE_ENABLE; //default to enable pin + systemParams.errorLogic=false; + systemParams.homeAngleDelay=ANGLE_FROM_DEGREES(10); + systemParams.homePin=-1; //no homing pin configured + } + + //default the error pin to input, if it is an error pin the + // handler for this will change the pin to be an output. + // for bidirection error it has to handle input/output it's self as well. + // This is not the cleanest way to handle this... + // TODO implement this cleaner? + pinMode(PIN_ERROR, INPUT_PULLUP); //we have input pin + + if (NVM->motorParams.parametersVaild) + { + memcpy((void *)&motorParams, (void *)&NVM->motorParams, sizeof(motorParams)); + } else + { + //MotorParams_t Params; + motorParams.fullStepsPerRotation=200; + motorParams.currentHoldMa=500; + motorParams.currentMa=800; + motorParams.homeHoldMa=200; + motorParams.homeMa=800; + motorParams.motorWiring=true; + //memcpy((void *)&Params, (void *)&motorParams, sizeof(motorParams)); + //nvmWriteMotorParms(Params); + } + + stepperDriver.setRotationDirection(motorParams.motorWiring); + + exitCriticalSection(state); +} + + +void StepperCtrl::motorReset(void) +{ + //when we reset the motor we want to also sync the motor + // phase. Therefore we move forward a few full steps then back + // to sync motor phasing, leaving the motor at "phase 0" + bool state=enterCriticalSection(); + + // stepperDriver.move(0,motorParams.currentMa); + // delay(100); + // stepperDriver.move(A4954_NUM_MICROSTEPS,motorParams.currentMa); + // delay(100); + // stepperDriver.move(A4954_NUM_MICROSTEPS*2,motorParams.currentMa); + // delay(100); + // stepperDriver.move(A4954_NUM_MICROSTEPS*3,motorParams.currentMa); + // delay(100); + // stepperDriver.move(A4954_NUM_MICROSTEPS*2,motorParams.currentMa); + // delay(100); + // stepperDriver.move(A4954_NUM_MICROSTEPS,motorParams.currentMa); + // delay(100); + stepperDriver.move(0,motorParams.currentMa); + delay(1000); + + setLocationFromEncoder(); //measure new starting point + exitCriticalSection(state); +} + +void StepperCtrl::setLocationFromEncoder(void) +{ + numSteps=0; + currentLocation=0; + + if (calTable.calValid()) + { + int32_t n,x; + int32_t calIndex; + Angle a; + + //set our angles based on previous cal data + + x=sampleMeanEncoder(200); + a=calTable.fastReverseLookup(x); + + //our cal table starts at angle zero, so lets set starting based on this and stepsize + LOG("start angle %d, encoder %d", (uint16_t)a,x); + + // we were rounding to nearest full step, but this should not be needed TBS 10/12/2017 + // //TODO we need to handle 0.9 degree motor + // if (CALIBRATION_TABLE_SIZE == motorParams.fullStepsPerRotation) + // { + // n=(int32_t)ANGLE_STEPS/CALIBRATION_TABLE_SIZE; + // + // calIndex=((int32_t)((uint16_t)a+n/2)*CALIBRATION_TABLE_SIZE)/ANGLE_STEPS; //find calibration index + // if (calIndex>CALIBRATION_TABLE_SIZE) + // { + // calIndex-=CALIBRATION_TABLE_SIZE; + // } + // a=(uint16_t)((calIndex*ANGLE_STEPS)/CALIBRATION_TABLE_SIZE); + // } + + + x=(int32_t)((((float)(uint16_t)a)*360.0/(float)ANGLE_STEPS)*1000); + LOG("start angle after rounding %d %d.%03d", (uint16_t)a,x/1000,x%1000); + + //we need to set our numSteps + numSteps=DIVIDE_WITH_ROUND( ((int32_t)a *motorParams.fullStepsPerRotation*systemParams.microsteps),ANGLE_STEPS); + currentLocation=(uint16_t)a; + } + zeroAngleOffset=getCurrentLocation(); //zero the angle shown on LCD +} + +void StepperCtrl::acceptPositionAndStealthSwitchMode(feedbackCtrl_t m) +{ + bool state=enterCriticalSection(); + currentLocationIsDesiredLocation(); + systemParams.controllerMode=m; + exitCriticalSection(state); +} + +void StepperCtrl::stealthSwitchMode(feedbackCtrl_t m) +{ + bool state=enterCriticalSection(); + systemParams.controllerMode=m; + exitCriticalSection(state); +} + +int64_t StepperCtrl::getZeroAngleOffset(void) +{ + int64_t x; + bool state=enterCriticalSection(); + + x=zeroAngleOffset; + + exitCriticalSection(state); + return x; +} + +void StepperCtrl::setAngle(int64_t angle) +{ + bool state=enterCriticalSection(); + + zeroAngleOffset=getCurrentLocation()-angle; + + exitCriticalSection(state); +} + +void StepperCtrl::setZero(void) +{ + //we want to set the starting angle to zero. + bool state=enterCriticalSection(); + + zeroAngleOffset=getCurrentLocation(); + + exitCriticalSection(state); +} + +void StepperCtrl::encoderDiagnostics(char *ptrStr) +{ + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + + encoder.diagnostics(ptrStr); + + if (state) enableTCInterrupts(); +} + + +//TODO This function does two things, set rotation direction +// and measures step size, it should be two functions. +//return is anlge in degreesx100 ie 360.0 is returned as 36000 +float StepperCtrl::measureStepSize(void) +{ + int32_t angle1,angle2,x,i; + bool feedback=enableFeedback; + int32_t microsteps=systemParams.microsteps; + + systemParams.microsteps=1; + enableFeedback=false; + motorParams.motorWiring=true; //assume we are forward wiring to start with + stepperDriver.setRotationDirection(motorParams.motorWiring); + ///////////////////////////////////////// + //// Measure the full step size ///// + /// Note we assume machine can take one step without issue/// + + LOG("reset motor"); + motorReset(); //this puts stepper motor at stepAngle of zero + + LOG("sample encoder"); + + angle1=sampleMeanEncoder(200); + + LOG("move"); + stepperDriver.move(A4954_NUM_MICROSTEPS/2,motorParams.currentMa); //move one half step 'forward' + delay(100); + stepperDriver.move(A4954_NUM_MICROSTEPS,motorParams.currentMa); //move one half step 'forward' + delay(500); + LOG("sample encoder"); + angle2=sampleMeanEncoder(200); + + LOG("Angles %d %d",angle1,angle2); + if ((abs(angle2-angle1))>(ANGLE_STEPS/2)) + { + //we crossed the wrap around + if (angle1>angle2) + { + angle1=angle1+(int32_t)ANGLE_STEPS; + }else + { + angle2=angle2+(int32_t)ANGLE_STEPS; + } + } + LOG("Angles %d %d",angle1,angle2); + + //when we are increase the steps in the stepperDriver.move() command + // we want the encoder increasing. This ensures motor is moving clock wise + // when encoder is increasing. + // if (angle2>angle1) + // { + // motorParams.motorWiring=true; + // stepperDriver.setRotationDirection(true); + // LOG("Forward rotating"); + // }else + // { + // //the motor is wired backwards so correct in stepperDriver + // motorParams.motorWiring=false; + // stepperDriver.setRotationDirection(false); + // LOG("Reverse rotating"); + // } + x=((int64_t)(angle2-angle1)*36000)/(int32_t)ANGLE_STEPS; + // if x is ~180 we have a 1.8 degree step motor, if it is ~90 we have 0.9 degree step + LOG("%angle delta %d %d (%d %d)",x,abs(angle2-angle1),angle1,angle2 ); + + //move back + stepperDriver.move(-A4954_NUM_MICROSTEPS/2,motorParams.currentMa); //move one half step 'forward' + delay(100); + stepperDriver.move(-A4954_NUM_MICROSTEPS,motorParams.currentMa); //move one half step 'forward' + + systemParams.microsteps=microsteps; + enableFeedback=feedback; + + return ((float)x)/100.0; +} + + +int32_t StepperCtrl::measureError(void) +{ + //LOG("current %d desired %d %d",(int32_t) currentLocation, (int32_t)getDesiredLocation(), numSteps); + + return ((int32_t)currentLocation-(int32_t)getDesiredLocation()); +} + +/* +bool StepperCtrl::changeMicrostep(uint16_t microSteps) +{ + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + systemParams.microsteps=microSteps; + motorReset(); + if (state) enableTCInterrupts(); + return true; +} + */ +Angle StepperCtrl::maxCalibrationError(void) +{ + //Angle startingAngle; + bool done=false; + int32_t mean; + int32_t maxError=0, j; + int16_t dist; + uint16_t angle=0; + bool feedback=enableFeedback; + uint16_t microSteps=systemParams.microsteps; + int32_t steps; + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + + + if (false == calTable.calValid()) + { + return ANGLE_MAX; + } + + enableFeedback=false; + j=0; + LOG("Running calibration test"); + + systemParams.microsteps=1; + motorReset(); + steps=0; + + while(!done) + { + Angle cal; + Angle act, desiredAngle; + + //todo we should measure mean and wait until stable. + delay(200); + mean=sampleMeanEncoder(200); + desiredAngle=(uint16_t)(getDesiredLocation() & 0x0FFFFLL); + + cal=calTable.getCal(desiredAngle); + dist=Angle(mean)-cal; + act=calTable.fastReverseLookup(cal); + + LOG("actual %d, cal %d",mean,(uint16_t)cal); + LOG("desired %d",(uint16_t)desiredAngle); + LOG("numSteps %d", numSteps); + + LOG("cal error for step %d is %d",j,dist); + LOG("mean %d, cal %d",mean, (uint16_t)cal); + + updateStep(0,1); + + // move one half step at a time, a full step move could cause a move backwards depending on how current ramps down + steps+=A4954_NUM_MICROSTEPS/2; + stepperDriver.move(steps,motorParams.currentMa); + + delay(50); + steps+=A4954_NUM_MICROSTEPS/2; + stepperDriver.move(steps,motorParams.currentMa); + + + if (400==motorParams.fullStepsPerRotation) + { + delay(100); + updateStep(0,1); + // move one half step at a time, a full step move could cause a move backwards depending on how current ramps down + steps+=A4954_NUM_MICROSTEPS/2; + stepperDriver.move(steps,motorParams.currentMa); + + delay(100); + steps+=A4954_NUM_MICROSTEPS/2; + stepperDriver.move(steps,motorParams.currentMa); + } + //delay(400); + + if (abs(dist)>maxError) + { + maxError=abs(dist); + } + + j++; + if (j>=(1*CALIBRATION_TABLE_SIZE+3)) + { + done=true; + } + + + } + systemParams.microsteps=microSteps; + motorReset(); + enableFeedback=feedback; + if (state) enableTCInterrupts(); + LOG("max error is %d cnts", maxError); + return Angle((uint16_t)maxError); +} + + +//The encoder needs to be calibrated to the motor. +// we will assume full step detents are correct, +// ex 1.8 degree motor will have 200 steps for 360 degrees. +// We also need to calibrate the phasing of the motor +// to the A4954. This requires that the A4954 "step angle" of +// zero is the first entry in the calibration table. +bool StepperCtrl::calibrateEncoder(void) +{ + int32_t x,i,j; + uint32_t angle=0; + int32_t steps; + bool done=false; + + int32_t mean; + uint16_t microSteps=systemParams.microsteps; + bool feedback=enableFeedback; + bool state=TC5_ISR_Enabled; + + disableTCInterrupts(); + + enableFeedback=false; + systemParams.microsteps=1; + LOG("reset motor"); + motorReset(); + LOG("Starting calibration"); + delay(200); + steps=0; + j=0; + while(!done) + { + int ii,N; + Angle cal,desiredAngle; + desiredAngle=(uint16_t)(getDesiredLocation() & 0x0FFFFLL); + cal=calTable.getCal(desiredAngle); + delay(200); + mean=sampleMeanEncoder(200); + + LOG("Previous cal distance %d, %d, mean %d, cal %d",j, cal-Angle((uint16_t)mean), mean, (uint16_t)cal); + + calTable.updateTableValue(j,mean); + + updateStep(0,1); + + N=2; + // move one half step at a time, a full step move could cause a move backwards depending on how current ramps down + for (ii=0; ii=CALIBRATION_TABLE_SIZE) + { + done=true; + } + + + } + //calTable.printCalTable(); + //calTable.smoothTable(); + //calTable.printCalTable(); + calTable.saveToFlash(); //saves the calibration to flash + calTable.printCalTable(); + + systemParams.microsteps=microSteps; + motorReset(); + enableFeedback=feedback; + if (state) enableTCInterrupts(); + return done; +} + + + + + +stepCtrlError_t StepperCtrl::begin(void) +{ + int i; + float x; + + + enableFeedback=false; + velocity=0; + currentLocation=0; + numSteps=0; + + //we have to update from NVM before moving motor + updateParamsFromNVM(); //update the local cache from the NVM + + LOG("start up encoder"); + if (false == encoder.begin(PIN_AS5047D_CS)) + { + return STEPCTRL_NO_ENCODER; + } + + LOG("cal table init"); + calTable.init(); + + startUpEncoder=(uint16_t)getEncoderAngle(); + WARNING("start up encoder %d",startUpEncoder); + + LOG("start stepper driver"); + stepperDriver.begin(); + +#ifdef NEMA17_SMART_STEPPER_3_21_2017 + if (NVM->motorParams.parametersVaild) + { + //lets read the motor voltage + if (GetMotorVoltage()<5) + { + //if we have less than 5 volts the motor is not powered + uint32_t x; + x=(uint32_t)(GetMotorVoltage()*1000.0); + ERROR("Motor voltage is %" PRId32 "mV",x); //default printf does not support floating point numbers + ERROR("Motor may not have power"); + return STEPCTRL_NO_POWER; + } + bool state=enterCriticalSection(); + setLocationFromEncoder(); //measure new starting point + exitCriticalSection(state); + + }else + { + LOG("measuring step size"); + x=measureStepSize(); + if (abs(x)<0.5) + { + ERROR("Motor may not have power"); + return STEPCTRL_NO_POWER; + } + } + +#else + LOG("measuring step size"); + x=measureStepSize(); + if (abs(x)<0.5) + { + ERROR("Motor may not have power"); + return STEPCTRL_NO_POWER; + } +#endif + + + LOG("Checking the motor parameters"); + //todo we might want to move this up a level to the NZS + // especially since it has default values + if (false == NVM->motorParams.parametersVaild) + { + MotorParams_t params; + WARNING("NVM motor parameters are not set, we will update"); + + //power could have just been applied and step size read wrong + // if we are more than 200 steps/rotation which is most common + // lets read again just to be sure. + if (abs(x)<1.5) + { + //run step test a second time to be sure + x=measureStepSize(); + } + + if (x>0) + { + motorParams.motorWiring=true; + } else + { + motorParams.motorWiring=false; + } + if (abs(x)<=1.2) + { + motorParams.fullStepsPerRotation=400; + }else + { + motorParams.fullStepsPerRotation=200; + } + + memcpy((void *)¶ms, (void *)&motorParams,sizeof(motorParams)); + nvmWriteMotorParms(params); + } + + LOG("Motor params are now good"); + LOG("fullSteps %d", motorParams.fullStepsPerRotation); + LOG("motorWiring %d", motorParams.motorWiring); + LOG("currentMa %d", motorParams.currentMa); + LOG("holdCurrentMa %d", motorParams.currentHoldMa); + LOG("homeMa %d", motorParams.homeMa); + LOG("homeHoldMa %d", motorParams.homeHoldMa); + + + updateParamsFromNVM(); //update the local cache from the NVM + + + if (false == calTable.calValid()) + { + return STEPCTRL_NO_CAL; + } + + + enableFeedback=true; + setupTCInterrupts(); + enableTCInterrupts(); + return STEPCTRL_NO_ERROR; + +} + +Angle StepperCtrl::sampleAngle(void) +{ + uint16_t angle; + int32_t x,y; + +#ifdef NZS_AS5047_PIPELINE + //read encoder twice such that we get the latest sample as the pipeline is always once sample behind + + + y=encoder.readEncoderAnglePipeLineRead(); //convert the 14 bit encoder value to a 16 bit number + x=encoder.readEncoderAnglePipeLineRead(); + + + angle=((uint32_t)(x)*4); //convert the 14 bit encoder value to a 16 bit number +#else + angle=((uint32_t)encoder.readEncoderAngle())<<2; //convert the 14 bit encoder value to a 16 bit number +#endif + return Angle(angle); +} + +//when sampling the mean of encoder if we are on roll over +// edge we can have an issue so we have this function +// to do the mean correctly +Angle StepperCtrl::sampleMeanEncoder(int32_t numSamples) +{ + + int32_t i,last,x=0; + int64_t mean=0; + int32_t min,max; + + mean=0; + for (i=0; i<(numSamples); i++) + { + int32_t d; + last=x; + x=(((int32_t)encoder.readEncoderAngle())*4); + if (encoder.getError()) + { +#ifndef MECHADUINO_HARDWARE + SerialUSB.println("AS5047 Error"); +#else + Serial5.print("AS5047 Error"); +#endif + delay(1000); + return 0; + } + if(i==0) + { + last=x; + min=x; + max=x; + } + //LOG("i %d,min %d, max %d, last %d, x %d", i, min, max, last, x); + if (abs(last-x)>65536/2) + { + if (last>x) + { + x=x+65536; + } else + { + x=x-65536; + } + } + + + if (x>max) + { + max=x; + } + if (xn) + { + ret-=n; + } + while(ret<-n) + { + ret+=n; + } + n=(int32_t)(ret); + LOG("s is %d %d",n,steps); + stepperDriver.move(n,motorParams.currentMa); + } + + +} + + + +int64_t StepperCtrl::getDesiredLocation(void) +{ + int64_t ret; + int32_t n; + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + n=motorParams.fullStepsPerRotation * systemParams.microsteps; + ret=((int64_t)numSteps * (int64_t)ANGLE_STEPS+(n/2))/n ; + if (state) enableTCInterrupts(); + return ret; +} + + +//int32_t StepperCtrl::getSteps(void) +//{ +// int32_t ret; +// bool state=enterCriticalSection(); +// ret=numSteps; +// exitCriticalSection(state); +// return ret; +//} + +void StepperCtrl::moveToAbsAngle(int32_t a) +{ + + int64_t ret; + int32_t n; + + + n=motorParams.fullStepsPerRotation * systemParams.microsteps; + + ret=(((int64_t)a+zeroAngleOffset)*n+ANGLE_STEPS/2)/(int32_t)ANGLE_STEPS; + bool state=enterCriticalSection(); + numSteps=ret; + exitCriticalSection(state); +} + +void StepperCtrl::moveToAngle(int32_t a, uint32_t ma) +{ + //we need to convert 'Angle' to A4954 steps + a=a % ANGLE_STEPS; //we only interested in the current angle + + + a=DIVIDE_WITH_ROUND( (a*motorParams.fullStepsPerRotation*A4954_NUM_MICROSTEPS), ANGLE_STEPS); + + //LOG("move %d %d",a,ma); + stepperDriver.move(a,ma); + +} + +Angle StepperCtrl::getEncoderAngle(void) +{ + Angle a; + bool state=enterCriticalSection(); + a=calTable.fastReverseLookup(sampleAngle()); + exitCriticalSection(state); + return a; +} + +int64_t StepperCtrl::getCurrentLocation(void) +{ + Angle a; + int32_t x; + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + a=calTable.fastReverseLookup(sampleAngle()); + x=(int32_t)a - (int32_t)((currentLocation) & ANGLE_MAX); + + if (x>((int32_t)ANGLE_STEPS/2)) + { + currentLocation -= ANGLE_STEPS; + } + if (x<-((int32_t)ANGLE_STEPS/2)) + { + currentLocation += ANGLE_STEPS; + } + currentLocation=(currentLocation & 0xFFFFFFFFFFFF0000UL) | (uint16_t)a; + if (state) enableTCInterrupts(); + return currentLocation; + +} + + + +int64_t StepperCtrl::getCurrentAngle(void) +{ + int64_t x; + x=getCurrentLocation()-zeroAngleOffset; + return x; +} + + +int64_t StepperCtrl::getDesiredAngle(void) +{ + int64_t x; + x=getDesiredLocation()-zeroAngleOffset; + return x; +} + +void StepperCtrl::setVelocity(int64_t vel) +{ + bool state=enterCriticalSection(); + + velocity=vel; + exitCriticalSection(state); +} + +void StepperCtrl::setTorque(int8_t tor) +{ + bool state=enterCriticalSection(); + + torque=tor; + exitCriticalSection(state); +} + +int8_t StepperCtrl::getTorque(void) +{ + int8_t tor; + bool state=enterCriticalSection(); + + tor=torque; + exitCriticalSection(state); + return tor; +} + +int64_t StepperCtrl::getVelocity(void) +{ + int64_t vel; + bool state=enterCriticalSection(); + + vel=velocity; + exitCriticalSection(state); + return vel; +} + +bool StepperCtrl::torqueLoop(int64_t currentLoc, Control_t *ptrCtrl) +{ + int32_t U, ma; + int64_t u, y; + + int32_t fullStep=ANGLE_STEPS/motorParams.fullStepsPerRotation; + + y=currentLoc; + ma=motorParams.currentMa; + u=torque*ma/128; // Make ma the maximum torque at 128 + // If dir pin changes meaning then torque also changes direction + if (CW_ROTATION == systemParams.dirPinRotation) + { + u=-u; + } + U=abs(u); + if (U>ma) + U=ma; + if (u>0) + y=y+fullStep; + else + y=y-fullStep; + ptrCtrl->ma=U; + ptrCtrl->angle=(int32_t)y; + moveToAngle(y,U); +} + +void StepperCtrl::PrintData(void) +{ + char s[128]; + bool state=enterCriticalSection(); + sprintf(s, "%u,%u,%u", (uint32_t)numSteps,(uint32_t)getDesiredAngle(),(uint32_t)getCurrentAngle()); +#ifndef MECHADUINO_HARDWARE + SerialUSB.println(s); +#endif + exitCriticalSection(state); +} +//this is the velocity PID feedback loop +bool StepperCtrl::vpidFeedback(int64_t desiredLoc, int64_t currentLoc, Control_t *ptrCtrl) +{ + int32_t fullStep=ANGLE_STEPS/motorParams.fullStepsPerRotation; + static int64_t lastY=getCurrentLocation(); + static int32_t lastError=0; + static int64_t Iterm=0; + int64_t y,z; + int64_t v,dy; + int64_t u; + + //get the current location + y =currentLoc; + + v=y-lastY; + + //add in phase prediction + y=y+calculatePhasePrediction(currentLoc); + z=y; + + lastY=y; + + v=v*NZS_CONTROL_LOOP_HZ; + + + if (enableFeedback) //if ((micros()-lastCall)>(updateRate/10)) + { + int64_t error,U; + error = velocity-v; + + Iterm += (vPID.Ki * error); + if (Iterm>(16*4096*CTRL_PID_SCALING *(int64_t)motorParams.currentMa)) + { + Iterm=(16*4096*CTRL_PID_SCALING *(int64_t)motorParams.currentMa); + } + if (Iterm<-(16*4096*CTRL_PID_SCALING *(int64_t)motorParams.currentMa)) + { + Iterm=-(16*4096*CTRL_PID_SCALING*(int64_t)motorParams.currentMa); + } + + u=((vPID.Kp * error) + Iterm - (vPID.Kd *(lastError-error))); + U=abs(u)/CTRL_PID_SCALING/1024; //scale the error to make PID params close to 1.0;//scale the error to make PID params close to 1.0 by dividing by 1024 + + if (U>motorParams.currentMa) + { + U=motorParams.currentMa; + } + + //when error is positive we need to move reverse direction + if (u>0) + { + z=z+(fullStep); + }else + { + z=z-(fullStep); + + } + + ptrCtrl->ma=U; + ptrCtrl->angle=(int32_t)z; + moveToAngle(z,U); + loopError=error; + lastError=error; + } else + { + lastError=0; + Iterm=0; + } + + if (abs(lastError)>(systemParams.errorLimit)) + { + return 1; + } + return 0; +} + + +//Since we are doing fixed point math our +// threshold needs to be large. +// We need a large threshold when we have fast update +// rate as well. But for most part it is random +bool StepperCtrl::pidFeedback(int64_t desiredLoc, int64_t currentLoc, Control_t *ptrCtrl) +{ + static int count=0; + + static int32_t maxError=0; + static int32_t lastError=0; + static int32_t Iterm=0; + int32_t ma; + int64_t y; + + int32_t fullStep=ANGLE_STEPS/motorParams.fullStepsPerRotation; + int32_t dy; + + y=currentLoc; + + //add in phase prediction + y=y+calculatePhasePrediction(currentLoc); + + if (enableFeedback) //if ((micros()-lastCall)>(updateRate/10)) + { + int64_t error,u; + int32_t U,x; + + //error is in units of degrees when 360 degrees == 65536 + error=(desiredLoc-y); //error is currentPos-desiredPos + + Iterm+=(pPID.Ki * error); + + if (systemParams.homePin>0 && digitalRead(systemParams.homePin)==0) + { + ma=motorParams.homeMa; + } else + { + ma=motorParams.currentMa; + } + + //Over the long term we do not want error + // to be much more than our threshold + if (Iterm> (ma*CTRL_PID_SCALING) ) + { + Iterm=(ma*CTRL_PID_SCALING) ; + } + if (Iterm<-(ma*CTRL_PID_SCALING) ) + { + Iterm=-(ma*CTRL_PID_SCALING) ; + } + + //u=((pPID.Kp * error) + Iterm - (pPID.Kd *(lastError-error))); + if(abs(error) > 90304) // 540 degrees + { + u=(int64_t)((float)ma*(float)CTRL_PID_SCALING*90304.0/(float)error); + } + else + { + u=((pPID.Kp * error) + Iterm - (pPID.Kd *(lastError-error))); + } + + U=abs(u)/CTRL_PID_SCALING; + if (U>ma) + { + U=ma; + } + + + //when error is positive we need to move reverse direction + if (u>0) + { + y=y+fullStep; + }else + { + y=y-fullStep; + + } + + ptrCtrl->ma=U; + ptrCtrl->angle=(int32_t)y; + moveToAngle(y,U); + loopError=error; + lastError=error; + + }else + { + lastError=0; + Iterm=0; + } + + if (abs(lastError)>(systemParams.errorLimit)) + { + return 1; + } + return 0; +} + + + +// the phase prediction tries to predict error from sensor based +// on current location and previous location. +// TODO our error can help in the phase prediction. +// if the error +int64_t StepperCtrl::calculatePhasePrediction(int64_t currentLoc) +{ + static int64_t lastLoc=0; + static int32_t mean=0; + int32_t dx,x; + +#ifndef ENABLE_PHASE_PREDICTION + return 0; +#endif + + //what was our change in the location + dx=currentLoc-lastLoc; //max value is typically less than 327(1.8 degrees) or 163(0.9 degree) + + //if the motor direction changes, zero phase prediction + if (SIGN(dx) != SIGN(mean)) + { + //last thing we want is phase prediction during direction change. + mean=0; + } else + { + if (abs(dx)>abs(mean)) + { + //increase mean really slowly, 2048 ~ 1/3 second with 6khz processing loop + // in fixed point since the dx is so small we need to scale it up to average + // dx has be be greater than 8 to change the mean... + // this limits the acceleration of motor above max processing speed (6k*1.8)=1800RPM + // however I doubt the motor can accelerate that fast with any load... + // The average helps prevent external impulse error from causing prediction to cause issues. + mean=DIVIDE_WITH_ROUND(2047*mean + dx*128, 2048); + }else + { + //decrease fast + //do not add more phase prediction than the difference in last two samples. + mean=dx*128; + } + } + lastLoc=currentLoc; + + x= mean/128; //scale back to normal + return x; +} + + +bool StepperCtrl::determineError(int64_t currentLoc,int64_t error) +{ + static int64_t lastLocation=0; + static int64_t lastError=0; + static int64_t lastVelocity=0; + + int64_t velocity; + + //since this is called on periodic timer the velocity + // is propotional to the change in location + // one rotation per second is velocity of 10, assumming 6khz update rate + // one rotation per minute is 10/60 velocity units + // since this is less than 1 we will scale the velo + velocity=(currentLoc-lastLocation); + + if (velocity>0 && lastVelocity>0) + { + + } + + + lastVelocity=velocity; + lastError=error; + lastLocation=currentLoc; +} + +//this was written to do the PID loop not modeling a DC servo +// but rather using features of stepper motor. +bool StepperCtrl::simpleFeedback(int64_t desiredLoc, int64_t currentLoc, Control_t *ptrCtrl) +{ + static uint32_t t0=0; + static uint32_t calls=0; + bool ret=false; + + static int32_t maxError=0; + static int32_t lastError=0; + static int32_t i=0; + static int32_t iTerm=0; + //static int64_t lastY=getCurrentLocation(); + static int32_t velocity=0; + static int32_t errorCount=0; + + static bool lastProbeState=false; + static int64_t probeStartAngle=0; + static int32_t maxMa=0; + + + static int64_t filteredError=0; + static int32_t probeCount=0; + + int32_t fullStep=ANGLE_STEPS/motorParams.fullStepsPerRotation; + + int32_t ma=0; + + int64_t y; + + + + //estimate our current location based on the encoder + y=currentLoc; + + //add in phase prediction + y=y+calculatePhasePrediction(currentLoc); + + + //we can limit the velocity by controlling the amount we move per call to this function + // this only works for velocity greater than 100rpm + /* if (velocity!=0) + { + fullStep=velocity/NZS_CONTROL_LOOP_HZ; + } + if (fullStep==0) + { + fullStep=1; //this RPM of (1*NZS_CONTROL_LOOP_HZ)/60 ie at 6Khz it is 100RPM + } + */ + if (enableFeedback) + { + int64_t error; + int32_t u; + + int32_t x; + int32_t kp; + + //error is in units of degrees when 360 degrees == 65536 + error=(desiredLoc-y);//measureError(); //error is currentPos-desiredPos + + + //data[i]=(int16_t)error; + //i++; + if (i>=N_DATA) + { + i=0; + } + + kp=sPID.Kp; + if (1)//(abs(error)<(fullStep)) + { + iTerm+=(sPID.Ki*error); + x=iTerm/CTRL_PID_SCALING; + }else + { + kp=(CTRL_PID_SCALING*9)/10; + x=0; + iTerm=0; + } + + if (x>fullStep) + { + x=fullStep; + iTerm=fullStep; + } + if (x<-fullStep) + { + x=-fullStep; + iTerm=-fullStep; + } + + + //u=(kp * error)/CTRL_PID_SCALING+x+(sPID.Kd *(error-lastError))/CTRL_PID_SCALING; + + // Lower effort if we're very far off + if(abs(error) > 90304) // 540 degrees + { + u=(int64_t)((float)fullStep*90304.0/(float)error); + } + else + { + u=(kp * error)/CTRL_PID_SCALING+x+(sPID.Kd *(error-lastError))/CTRL_PID_SCALING; + } + + //limit error to full step + if (u>fullStep) + { + u=fullStep; + } + if (u<-fullStep) + { + u=-fullStep; + } + + ma=(abs(u)*(motorParams.currentMa-motorParams.currentHoldMa))/ fullStep + motorParams.currentHoldMa; + if (ma>motorParams.currentMa) + { + ma=motorParams.currentMa; + } + //maxMa=motorParams.currentMa; + + if (systemParams.homePin>=0) + { + + if (digitalRead(systemParams.homePin)==0) + { + if (lastProbeState==false) + { + //record our current angle for homing + probeStartAngle=desiredLoc; + probeCount=0; + maxMa=0; + } + lastProbeState=true; + probeCount++; + //we will lower current after whe have moved some amount + + if (probeCount > NZS_CONTROL_LOOP_HZ && probeCount <(2* NZS_CONTROL_LOOP_HZ)) + { + maxMa+=ma; + if (abs(error)>maxError) + { + maxError=abs(error); + } + + } + if (probeCount>(2*NZS_CONTROL_LOOP_HZ)) + { + // ma=(abs(u)*(maxMa))/ fullStep;// + motorParams.homeHoldMa; + // if (ma>motorParams.homeMa) + // { + // ma=motorParams.homeMa; + // } + + //if (ma>maxMa/NZS_CONTROL_LOOP_HZ) + { + ma=((maxMa/NZS_CONTROL_LOOP_HZ)*9)/10; + } + + } + + } else + { + lastProbeState=false; + } + }else + { + maxError=0; + probeCount=0; + //maxMa=0; + } + + + y=y+u; + ptrCtrl->ma=ma; + ptrCtrl->angle=(int32_t)y; + moveToAngle(y,ma); //35us + + lastError=error; + loopError=error; + //stepperDriver.limitCurrent(99); + } + + //filteredError=(filteredError*15+lastError)/16; + + if (probeCount>(2*NZS_CONTROL_LOOP_HZ)) + { + if (abs(lastError) > maxError ) + { + + errorCount++; + if (errorCount>(10)) + { + return 1; + } + return 0; + } + + } + else + { + if (abs(lastError) > systemParams.errorLimit) + { + + errorCount++; + if (errorCount>(NZS_CONTROL_LOOP_HZ/128)) // error needs to exist for some time period + { + return 1; + } + return 0; + } + } + + if (errorCount>0) + { + errorCount--; + } + + //errorCount=0; + stepperDriver.limitCurrent(99); //reduce noise on low error + return 0; + +} + +void StepperCtrl::currentLocationIsDesiredLocation(){ + bool state=enterCriticalSection(); + moveToAbsAngle(getCurrentAngle()); + exitCriticalSection(state); +} + +void StepperCtrl::enable(bool enable) +{ + bool state=TC5_ISR_Enabled; + disableTCInterrupts(); + bool feedback=enableFeedback; + + stepperDriver.enable(enable); //enable or disable the stepper driver as needed + + + if (enabled==true && enable==false) + { + feedback = false; + } + if (enabled==false && enable==true) //if we are enabling previous disabled motor + { + feedback = true; + setLocationFromEncoder(); + } + + enabled=enable; + enableFeedback=feedback; + if (state) enableTCInterrupts(); +} + +/* +void StepperCtrl::testRinging(void) +{ + uint16_t c; + int32_t steps; + int32_t microSteps=systemParams.microsteps; + bool feedback=enableFeedback; + + enableFeedback=false; + systemParams.microsteps=1; + motorReset(); + for (c=2000; c>10; c=c-10) + { + SerialUSB.print("Current "); + SerialUSB.println(c); + steps+=A4954_NUM_MICROSTEPS; + stepperDriver.move(steps,NVM->SystemParams.currentMa); + currentLimit=false; + measure(); + } + systemParams.microsteps=microSteps; + motorReset(); + enableFeedback=feedback; +} + */ + +//returns -1 if no data, else returns number of data points remaining. +int32_t StepperCtrl::getLocation(Location_t *ptrLoc) +{ + bool state=enterCriticalSection(); + int32_t n; + //check for empty + if (locReadIndx==locWriteIndx) + { + //empty data + exitCriticalSection(state); + return -1; + } + + //else read data + memcpy(ptrLoc,(void *)&locs[locReadIndx], sizeof(Location_t)); + + //update the read index + locReadIndx=(locReadIndx+1)%MAX_NUM_LOCATIONS; + + //calculate number of locations left + n=((locWriteIndx+MAX_NUM_LOCATIONS)-locReadIndx)%MAX_NUM_LOCATIONS; + + + exitCriticalSection(state); + return n; +} + +void StepperCtrl::updateLocTable(int64_t desiredLoc, int64_t currentLoc, Control_t *ptrCtrl) +{ + bool state=enterCriticalSection(); + int32_t next; + + // set the next write location + next=(locWriteIndx+1)%MAX_NUM_LOCATIONS; + + if (next==locReadIndx) + { + //we are full, exit + exitCriticalSection(state); + //RED_LED(true); //turn Red LED on to indciate buffer full + return; + } + + //use ticks for the moment so we can tell if we miss data on the print. + locs[locWriteIndx].microSecs=(int32_t)micros(); + locs[locWriteIndx].desiredLoc=(int32_t)(desiredLoc-zeroAngleOffset); + locs[locWriteIndx].actualLoc=(int32_t)(currentLoc-zeroAngleOffset); + locs[locWriteIndx].angle=(ptrCtrl->angle-zeroAngleOffset); + locs[locWriteIndx].ma=ptrCtrl->ma; + locWriteIndx=next; + + + exitCriticalSection(state); +} + + +bool StepperCtrl::processFeedback(void) +{ + bool ret; + int32_t us,j; + Control_t ctrl; + int64_t desiredLoc; + int64_t currentLoc; + int32_t steps; + static int64_t mean=0;; + + us=micros(); + +#ifdef USE_TC_STEP + static int64_t lastSteps; + int64_t x; + x=getSteps()-lastSteps; + updateSteps(x); + lastSteps+=x; +#endif + +// steps=getSteps(); +// if (steps>0) +// { +// requestStep(1, (uint16_t)steps); +// }else +// { +// requestStep(0, (uint16_t)(-steps)); +// } + + desiredLoc=getDesiredLocation(); + + currentLoc=getCurrentLocation(); + mean=(31*mean+currentLoc+16)/32; + +#ifdef A5995_DRIVER //the A5995 is has more driver noise + if (abs(currentLoc-mean)PIDparams.Kp; + // pKi=NVM->PIDparams.Ki; + // pKd=NVM->PIDparams.Kd; + // threshold=NVM->PIDparams.Threshold; + + //enableTCInterrupts(); + moveToAngle(angle,motorParams.currentMa); + + + //moveToAngle(angle,NVM->SystemParams.currentMa); + /* + //next lets measure our noise on the encoder + noiseMin=(int32_t)ANGLE_MAX; + noiseMax=-(int32_t)ANGLE_MAX; + mean=0; + j=1000000UL/NZS_CONTROL_LOOP_HZ; + prevAngle=sampleAngle(); + for (i=0; i<(NZS_CONTROL_LOOP_HZ/2); i++) + { + Angle a; + a=sampleAngle(); + error=(int32_t)(prevAngle-a); + + if (errornoiseMax) + { + noiseMax=error; + } + mean=mean+(int32_t)a; + delayMicroseconds(j); + + } + mean=mean/i; + while (mean>ANGLE_MAX) + { + mean=mean-ANGLE_STEPS; + } + while (mean<0) + { + mean=mean+ANGLE_STEPS; + } + //mean is the average of the encoder. + */ + + + + stepperDriver.move(0,motorParams.currentMa); + delay(1000); + + //now we need to do the relay control + for (i=0; i<10; i++) + { + startAngle=getCurrentLocation(); + LOG("Start %d", (int32_t)startAngle); + } + thres=startAngle + (int32_t)((ANGLE_STEPS/motorParams.fullStepsPerRotation)*10/9); + LOG("Thres %d, start %d",(int32_t)thres,(int32_t)startAngle); + eMin=(int32_t)ANGLE_MAX; + eMax=-(int32_t)ANGLE_MAX; + int32_t reset=0; + int32_t force=(motorParams.currentMa); + + for (i=0; i<100; i++) + { + int32_t error; + if (reset) + { + motorReset(); + stepperDriver.move(0,motorParams.currentMa); + delay(1000); + startAngle=getCurrentLocation(); + LOG("Start %d", (int32_t)startAngle); + force=force-100; + + eMin=(int32_t)ANGLE_MAX; + eMax=-(int32_t)ANGLE_MAX; + + if (force<100) + { + i=100; + break; + } + LOG("force set to %d",force); + i=0; + } + reset=0; + + stepperDriver.move(A4954_NUM_MICROSTEPS,force); + //moveToAngle(startAngle+(ANGLE_STEPS/motorParams.fullStepsPerRotation),force); + //stepperDriver.move(A4954_NUM_MICROSTEPS,NVM->SystemParams.currentMa); + t0=micros(); + + error=0; + while(error<=((ANGLE_STEPS/motorParams.fullStepsPerRotation)/2+40)) + { + int32_t y; + y=getCurrentLocation(); + error=y-startAngle; + //LOG("Error1 %d",error); + if (erroreMax) + { + eMax=error; + } + if (abs(error)>ANGLE_STEPS/motorParams.fullStepsPerRotation*2) + { + LOG("large Error1 %d, %d, %d",error, y, startAngle); + + reset=1; + break; + } + + } + + stepperDriver.move(0,force); + + //stepperDriver.move(0,NVM->SystemParams.currentMa); + t1=micros(); + + error=(ANGLE_STEPS/motorParams.fullStepsPerRotation); + while(error>=((ANGLE_STEPS/motorParams.fullStepsPerRotation)/2-40)) + { + error=getCurrentLocation()-startAngle; + //LOG("Error2 %d",error); + if (erroreMax) + { + eMax=error; + } + if (abs(error)>ANGLE_STEPS/motorParams.fullStepsPerRotation*2) + { + LOG("large Error2 %d",error); + reset=1; + break; + } + } + + times[i]=t1-t0; + + } + for (i=0; i<100; i++) + { + LOG("Time %d %d",i,times[i]); + } + LOG("errorMin=%d",eMin); + LOG("errorMax=%d",eMax); + + motorReset(); + systemParams.controllerMode=prevCtrl; + systemParams.microsteps=microSteps; + enableFeedback=feedback; + if (state) enableTCInterrupts(); + +} + +//void StepperCtrl::printData(void) +//{ +// bool state=TC5_ISR_Enabled; +// disableTCInterrupts(); +// int32_t i; +// for(i=0; i. + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#ifndef __STEPPER_CONTROLLER_H__ +#define __STEPPER_CONTROLLER_H__ + +#include "syslog.h" +#include "board.h" +#include "as5047d.h" +#include "A1333.h" +#include "calibration.h" +#include "A4954.h" +#include "A5995.h" +#include "nonvolatile.h" +#include "fet_driver.h" //for the NEMA23 10A + + +#define N_DATA (1024) + + +typedef enum { + STEPCTRL_NO_ERROR=0, + STEPCTRL_NO_POWER=1, //no power to motor + STEPCTRL_NO_CAL=2, //calibration not set + STEPCTRL_NO_ENCODER=3, //encoder not working +} stepCtrlError_t; + + +typedef struct { + int32_t Kp; + int32_t Ki; + int32_t Kd; +} PID_t; + + + typedef __attribute__((aligned(4))) struct { + int32_t microSecs; + int32_t desiredLoc; + int32_t actualLoc; + int32_t angle; + int32_t ma; +} Location_t; + + +typedef struct { + int32_t angle; + int32_t ma; +}Control_t; + +#define MAX_NUM_LOCATIONS (64) //maximum number of locations to buffer + + +//this scales the PID parameters from Flash to floating point +// to fixed point int32_t values +#define CTRL_PID_SCALING (1024) + +// Uncommenting this will make motor go into ctrl_pos_pid mode +// at startup and when exiting ctrl_torque mode by setting torque=0 +//#define CTRL_POS_PID_AS_DEFAULT + +class StepperCtrl +{ + private: + volatile bool enableFeedback; //true if we are using PID control algorithm + +#ifdef A1333_ENCODER + A1333 encoder; +#else + AS5047D encoder; +#endif + +#ifdef NEMA_23_10A_HW + FetDriver stepperDriver; +#else +#ifdef A5995_DRIVER + A5995 stepperDriver; +#else + A4954 stepperDriver; +#endif +#endif + uint16_t startUpEncoder; + volatile int32_t ticks=0; + volatile Location_t locs[MAX_NUM_LOCATIONS]; + volatile int32_t locReadIndx=0; + volatile int32_t locWriteIndx=0; + + volatile MotorParams_t motorParams; + volatile SystemParams_t systemParams; + volatile bool enabled; + + + + volatile int32_t loopTimeus; //time to run loop in microseconds + + volatile PID_t sPID; //simple control loop PID parameters + volatile PID_t pPID; //positional current based PID control parameters + volatile PID_t vPID; //velocity PID control parameters + + volatile int64_t numSteps; //this is the number of steps we have taken from our start angle + + volatile int32_t loopError; + + volatile int64_t currentLocation; //estimate of the current location from encoder feedback + // the current location lower 16 bits is angle (0-360 degrees in 65536 steps) while upper + // bits is the number of full rotations. + + //this is used for the velocity PID feedback + // units are in Angles/sec where 1 Angle=360deg/65536 + volatile int64_t velocity; + volatile int8_t torque=0; + + int64_t zeroAngleOffset=0; + + + //volatile int16_t data[N_DATA]; + + //does linear interpolation of the encoder calibration table + int32_t getAngleCalibration(int32_t encoderAngle); + + //updates the currentMeasuredAngle with our best guess where we are + Angle sampleAngle(void); + Angle sampleMeanEncoder(int32_t numSamples); + + float measureStepSize(void); //steps motor and estimates step size + uint32_t measureMaxCalibrationError(void); + void setLocationFromEncoder(void); + + void motorReset(void); + void updateStep(int dir, uint16_t steps); + + bool torqueLoop(int64_t currentLoc, Control_t *ptrCtrl); + bool pidFeedback(int64_t desiredLoc, int64_t currentLoc, Control_t *ptrCtrl); + bool simpleFeedback(int64_t desiredLoc, int64_t currentLoc,Control_t *ptrCtrl); + bool vpidFeedback(int64_t desiredLoc, int64_t currentLoc,Control_t *ptrCtrl); + int64_t getCurrentLocation(void); + int64_t getDesiredLocation(void); + void updateLocTable(int64_t desiredLoc, int64_t currentLoc,Control_t *ptrCtrl); + + int64_t calculatePhasePrediction(int64_t currentLoc); + bool determineError(int64_t currentLoc, int64_t error); + + public: + uint16_t getStartupEncoder(void) {return startUpEncoder;} + int32_t getLocation(Location_t *ptrLoc); + + //int32_t getSteps(void); + Angle getEncoderAngle(void); + + void setAngle(int64_t loc); + + int64_t getZeroAngleOffset(void); + void PrintData(void); + void setTorque(int8_t tor); //set torqu for torque mode + int8_t getTorque(void); + void setVelocity(int64_t vel); //set velocity for vPID mode + int64_t getVelocity(void); + int32_t getLoopError(void) {return loopError;}; //assume atomic read + + bool calibrationValid(void) { return calTable.calValid();} //returns true if calbiration is good + + void updateParamsFromNVM(void); //updates the parameters from NVM + CalibrationTable calTable; + //void printData(void); + + bool calibrateEncoder(void); //do manual calibration of the encoder + Angle maxCalibrationError(void); //measures the maximum calibration error as an angle + + void moveToAbsAngle(int32_t a); + void moveToAngle(int32_t a, uint32_t ma); + + stepCtrlError_t begin(void); //returns false if we can not use motor + + bool processFeedback(void); // does the feedback loop + + feedbackCtrl_t getControlMode(void) { return systemParams.controllerMode;}; + + void updateSteps(int64_t steps); + void requestStep(int dir, uint16_t steps); //requests a step, if feedback controller is off motor does not move + + void feedback(bool enable); + bool getFeedback(void) {return enableFeedback;} + + void encoderDiagnostics(char *ptrStr); + int32_t measureError(void); + + //these two functions are compenstated by the zero offset + int64_t getCurrentAngle(void); + int64_t getDesiredAngle(void); + + void move(int dir, uint16_t steps); //forces motor to move even if feedback controller is turned off. + void currentLocationIsDesiredLocation(); + void stealthSwitchMode(feedbackCtrl_t m); + void acceptPositionAndStealthSwitchMode(feedbackCtrl_t m); + void enable(bool enable); + bool getEnable(void) {return enabled;} + + int32_t getLoopTime(void) { return loopTimeus;} + + void PID_Autotune(void); + void setZero(void); +}; + +#endif //__STEPPER_CONTROLLER_H__ + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.ino b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.ino new file mode 100644 index 0000000..62794ae --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.ino @@ -0,0 +1,13 @@ +#include "nzs.h" + +NZS nzs; + + +void setup() { + nzs.begin(); +} + + +void loop() { + nzs.loop(); +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.bin b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.bin new file mode 100644 index 0000000..65bfa29 Binary files /dev/null and b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.bin differ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.elf b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.elf new file mode 100644 index 0000000..ff5095d Binary files /dev/null and b/firmware_smartstepper_trikarus/stepper_nano_zero/stepper_nano_zero.misfittech.samd.nano_zero.elf differ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.cpp new file mode 100644 index 0000000..8eb5659 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.cpp @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + */ +#include "steppin.h" +#include "stepper_controller.h" +#include "wiring_private.h" +#include "Arduino.h" + +extern StepperCtrl stepperCtrl; + +volatile int32_t stepsChanged=0; +volatile int64_t steps=0; + + +#if (PIN_STEP_INPUT != 0) +#error "this code only works with step pin being D0 (PA11, EXTINT11)" +#endif + + +#define WAIT_TCC2_SYNC() while(TCC2->SYNCBUSY.reg) + +void checkDir(void) +{ + int dir=1; + static int lastDir=-1; + + + if (CW_ROTATION == NVM->SystemParams.dirPinRotation) + { + dir=0; //reverse the rotation + } + + if (lastDir != dir) + { + if (dir) + { + EIC->CONFIG[1].reg &= ~EIC_CONFIG_SENSE2_Msk; + EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH; + + } else + { + EIC->CONFIG[1].reg &= ~EIC_CONFIG_SENSE2_Msk; + EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_LOW; + } + lastDir=dir; + } + +} + +//this function can not be called in interrupt context as the overflow interrupt for tC4 needs to run. +int64_t getSteps(void) +{ + +//#ifndef USE_NEW_STEP +// return 0; +//#endif + int64_t x; +#ifdef USE_TC_STEP + uint16_t y; + static uint16_t lasty=0; + + TCC2->CTRLBSET.reg=TCC_CTRLBSET_CMD_READSYNC; + WAIT_TCC2_SYNC(); + + + y=(uint16_t)(TCC2->COUNT.reg & 0x0FFFFul); //use only lowest 16bits + //LOG("count is %d",y); + steps += (int16_t)(y-lasty); + lasty=y; + + checkDir(); + return steps; + +#else + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT11; + x=stepsChanged; + stepsChanged=0; + EIC->INTENSET.reg = EIC_INTENSET_EXTINT11; + return x; +#endif +} + + + + +//this function is called on the rising edge of a step from external device +static void stepInput(void) +{ + static int dir; + + //read our direction pin + dir = digitalRead(PIN_DIR_INPUT); + + if (CW_ROTATION == NVM->SystemParams.dirPinRotation) + { + dir=!dir; //reverse the rotation + } + +#ifndef USE_NEW_STEP + stepperCtrl.requestStep(dir,1); +#else + if (dir) + { + stepsChanged++; + }else + { + stepsChanged--; + } +#endif +} + +void enableEIC(void) +{ + PM->APBAMASK.reg |= PM_APBAMASK_EIC; + if (EIC->CTRL.bit.ENABLE == 0) + { + // Enable GCLK for IEC (External Interrupt Controller) + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC)); + + // Enable EIC + EIC->CTRL.bit.ENABLE = 1; + while (EIC->STATUS.bit.SYNCBUSY == 1) { } + } +} + + + + + +void setupStepEvent(void) +{ + //we will set up the EIC to generate an even on rising edge of step pin + //make sure EIC is setup + enableEIC(); + + + // Assign step pin to EIC + // Step pin is PA11, EXTINT11 + pinPeripheral(PIN_STEP_INPUT, PIO_EXTINT); + + //set up the direction pin PA10 to trigger external interrupt + pinPeripheral(PIN_DIR_INPUT, PIO_EXTINT); //EXTINT10 + + + //***** setup EIC ****** + EIC->EVCTRL.bit.EXTINTEO11=1; //enable event for EXTINT11 + EIC->EVCTRL.bit.EXTINTEO10=1; //enable event for EXTINT10 + //setup up external interurpt 11 to be rising edge triggered + //setup up external interurpt 10 to be both edge triggered + EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE3_RISE | EIC_CONFIG_SENSE2_HIGH; + + checkDir(); + + //disable actually generating an interrupt, we only want event triggered + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT11; + EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10; + + //**** setup the event system *** + // Enable GCLK for EVSYS channel 0 + PM->APBCMASK.reg |= PM_APBCMASK_EVSYS; + + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EVSYS_CHANNEL_0)); + while (GCLK->STATUS.bit.SYNCBUSY); + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EVSYS_CHANNEL_1)); + while (GCLK->STATUS.bit.SYNCBUSY); + + //setup the step pin to trigger event 0 on the TCC2 (step) + EVSYS->CHANNEL.reg=EVSYS_CHANNEL_CHANNEL(0) + | EVSYS_CHANNEL_EDGSEL_RISING_EDGE + | EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_11) + | EVSYS_CHANNEL_PATH_ASYNCHRONOUS; + + EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) + | EVSYS_USER_USER(EVSYS_ID_USER_TCC2_EV_0); + + //setup the dir pin to trigger event 2 on the TCC2 (dir change) + EVSYS->CHANNEL.reg=EVSYS_CHANNEL_CHANNEL(1) + | EVSYS_CHANNEL_EDGSEL_BOTH_EDGES + | EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) + | EVSYS_CHANNEL_PATH_ASYNCHRONOUS; + + EVSYS->USER.reg = EVSYS_USER_CHANNEL(2) + | EVSYS_USER_USER(EVSYS_ID_USER_TCC2_EV_1); + + //**** setup the Timer counter ****** + PM->APBCMASK.reg |= PM_APBCMASK_TCC2; + + // Enable GCLK for TCC2 (timer counter input clock) + GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TCC2_TC3)); + while (GCLK->STATUS.bit.SYNCBUSY); + + + + TCC2->CTRLA.reg &= ~TCC_CTRLA_ENABLE; + WAIT_TCC2_SYNC(); + + TCC2->CTRLA.reg= TCC_CTRLA_SWRST; //reset TCC2 + WAIT_TCC2_SYNC(); + while(TCC2->CTRLA.bit.SWRST ==1); + + + //TCC2->WAVE.reg = TCC_WAVE_WAVEGEN_NFRQ; + //WAIT_TCC2_SYNC(); + + TCC2->EVCTRL.reg=TCC_EVCTRL_EVACT0_COUNTEV | TCC_EVCTRL_TCEI0 + | TCC_EVCTRL_EVACT1_DIR | TCC_EVCTRL_TCEI1; + WAIT_TCC2_SYNC(); + + + TCC2->COUNT.reg=0; + WAIT_TCC2_SYNC(); + + //TCC2->CTRLBSET.bit.CMD=TCC_CTRLBSET_CMD_RETRIGGER; + //checkDirPin(); + TCC2->CTRLBSET.bit.DIR=1; + + WAIT_TCC2_SYNC(); + TCC2->CTRLA.reg |=TCC_CTRLA_ENABLE; + WAIT_TCC2_SYNC(); + + + //checkDirPin(); + +// +// TC4->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 // Set Timer counter Mode to 16 bits +// | TC_CTRLA_WAVEGEN_NFRQ //normal counting mode (not using waveforms) +// | TC_CTRLA_PRESCALER_DIV1; //count each pulse +// WAIT_TC32_REGS_SYNC(TC4) +// +// TC4->COUNT16.CTRLBCLR.reg=0xFF; //clear all values. +// WAIT_TC32_REGS_SYNC(TC4) +// +// TC4->COUNT16.EVCTRL.reg=TC_EVCTRL_TCEI | TC_EVCTRL_EVACT_COUNT; //enable event input and count +// WAIT_TC32_REGS_SYNC(TC4) +// +// TC4->COUNT16.COUNT.reg=0; +// WAIT_TC32_REGS_SYNC(TC4) +// +// TC4->COUNT16.INTENSET.bit.OVF = 1; //enable over/under flow interrupt +// //setup the TC overflow/underflow interrupt +// NVIC_SetPriority(TC4_IRQn, 0); +// // Enable InterruptVector +// NVIC_EnableIRQ(TC4_IRQn); +// +// +// // Enable TC +// TC4->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; +// WAIT_TC32_REGS_SYNC(TC4) +} + +//static void dirChanged_ISR(void) +//{ +// int dir=0; +// //read our direction pin +// //dir = digitalRead(PIN_DIR_INPUT); +// if ( (PORT->Group[g_APinDescription[PIN_DIR_INPUT].ulPort].IN.reg & (1ul << g_APinDescription[PIN_DIR_INPUT].ulPin)) != 0 ) +// { +// dir=1; +// } +// +// +// if (CW_ROTATION == NVM->SystemParams.dirPinRotation) +// { +// dir=!dir; //reverse the rotation +// } +// if (dir) +// { +// TC4->COUNT16.CTRLBSET.bit.DIR=1; +// } else +// { +// TC4->COUNT16.CTRLBCLR.bit.DIR=1; +// } +//} + + +void stepPinSetup(void) +{ + + +#ifdef USE_TC_STEP + +// //setup the direction pin +// dirChanged_ISR(); +// +// //attachInterrupt configures the EIC as highest priority interrupts. +// attachInterrupt(digitalPinToInterrupt(PIN_DIR_INPUT), dirChanged_ISR, CHANGE); + setupStepEvent(); +// NVIC_SetPriority(EIC_IRQn, 1); //set port A interrupt as highest priority + + +#else + attachInterrupt(digitalPinToInterrupt(PIN_STEP_INPUT), stepInput, RISING); + NVIC_SetPriority(EIC_IRQn, 0); //set port A interrupt as highest priority +#endif + +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.h b/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.h new file mode 100644 index 0000000..62b13dd --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/steppin.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + */ +#ifndef __STEPPIN_H___ +#define __STEPPIN_H___ +#include "board.h" + +void stepPinSetup(void); //setup step pin + +int64_t getSteps(void); //returns the number of steps changed since last call + + +#endif // __STEPPIN_H___ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.cpp new file mode 100644 index 0000000..aaf270d --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.cpp @@ -0,0 +1,243 @@ +/* + * syslog.c + * + * Created on: Sep 14, 2011 + * Author: trampas.stern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ +#include "syslog.h" +#include +#include "board.h" + + +#define ANSI_WHITE "\033[37m" +#define ANSI_NORMAL "\033[0m" +#define ANSI_BLINK "\033[5m" +#define ANSI_BLUE "\033[34m" +#define ANSI_MAGENTA "\033[35m" +#define ANSI_CYAN "\033[36m" +#define ANSI_WHITE "\033[37m" +#define ANSI_RED "\033[31m" +#define ANSI_GREEN "\033[32m" +#define ANSI_PINK "\033[35m\033[1m" +#define ANSI_BROWN "\033[33m" +#define ANSI_YELLOW "\033[33m\033[1m" +#define ANSI_BLACK "\033[30m" +#define ANSI_BELL_AND_RED "\a\033[31m" + +#define NEW_LINE "\n\r" + +Stream *ptrSerial=NULL; +eLogLevel SyslogLevelToWrite; + +bool DebugUART=false; +static char buffer[SYSLOG_BUFFER_SIZE]; +static unsigned int BufIndex=0; + +static int SysLog_Enabled=1; + +int SysLogDisable(void) +{ + SysLog_Enabled=0; + return 0; +} + +int SysLogEnable(void) +{ + SysLog_Enabled=1; + return 0; +} + +int SysLogIsEnabled(void) +{ + return SysLog_Enabled; +} +void SysLogDebug(bool x) +{ + DebugUART=x; +} + +void SysLogPuts(const char *ptrStr) +{ + if (!SysLog_Enabled) + return; + + if (NULL == ptrSerial) + { + while(*ptrStr) + { + + SYSLOG_PUTC(*ptrStr); + ptrStr++; + } + } else + { + ptrSerial->write(ptrStr); + } +#ifndef MECHADUINO_HARDWARE + if (DebugUART) + { + SerialUSB.write(ptrStr); + } +#endif +} + +int SysLogInitDone=0; +void SysLogInit(Stream *ptrSerialObj, eLogLevel LevelToWrite) +{ + ptrSerial=ptrSerialObj; + SyslogLevelToWrite=LevelToWrite; + + SysLogInitDone=1; + BufIndex=0; + memset(buffer,0,SYSLOG_BUFFER_SIZE); +} + + +int SysLogProcessing=0; // this is used such that syslog can be reentrent +int SysLogMissed=0; + + +void SysLog(eLogLevel priorty, const char *fmt, ...) +{ + //UINT32 ret; + int previousState=SysLog_Enabled; + char vastr[MAX_SYSLOG_STRING]={0}; + //char outstr[MAX_SYSLOG_STRING]={0}; + + + va_list ap; + + if (SysLogProcessing) + { + //we have a syslog from a syslog call thus return as not much we can do... + //memset(buffer,0,SYSLOG_BUFFER_SIZE); + va_start(ap,fmt); + vsnprintf(&buffer[BufIndex],SYSLOG_BUFFER_SIZE-BufIndex,(char *)fmt,ap); + BufIndex=strlen(buffer); + snprintf(&buffer[BufIndex],SYSLOG_BUFFER_SIZE-BufIndex,NEW_LINE); + BufIndex=strlen(buffer); + SysLogMissed++; //set flag that we missed a call + return; + } + + SysLogProcessing=1; + + //stop the watch dog will doing a SysLog print + Sys_WDogHoldOn(); + + if(!SysLogInitDone) + { + SysLogInit(NULL, LOG_WARNING); //not sure who is reseting serial port but before we print set it up + WARNING("You should init SysLog"); + //SysLogInitDone=0; + } + + //Send out a * that we missed a SysLog Message before this current message + if (SysLogMissed) + { + //SysLogPuts(ANSI_RED); + SysLogPuts("*** Reentrant Log call possible loss of message(s):"); + SysLogPuts(NEW_LINE); + if (BufIndex>0) + { + SysLogPuts(buffer); + memset(buffer,0,SYSLOG_BUFFER_SIZE); + BufIndex=0; + } + //SysLogPuts(ANSI_RED); + SysLogPuts("***********"); + SysLogPuts(NEW_LINE); + SysLogMissed=0; + } + memset(vastr,0,MAX_SYSLOG_STRING); + va_start(ap,fmt); +//#ifndef PGM_P +#if 1 + vsnprintf(vastr,MAX_SYSLOG_STRING,(char *)fmt,ap); +#else + vsprintf_P(vastr,(const char *)fmt,ap); +#endif + //get time and store in datetimestr if desired + //sprintf(outstr, "[%s] %s\r\n", datetimestr, vastr); + + + + if (priorty<=LOG_ERROR) + { + SysLog_Enabled=1; + SysLogPuts(ANSI_RED); + + }else if (priorty==LOG_DEBUG) + { + SysLogPuts(ANSI_WHITE); + }else if (priorty==LOG_WARNING) + { + SysLogPuts(ANSI_BLUE); + } + +#ifdef RTC_H_ +#ifdef TIME_H_ + { + struct tm tp; + RTC_Time_s tm; + time_t secs; + char datetimestr[MAX_SYSLOG_STRING]={0}; + + RTC_ReadTime(&tm); + secs=tm.seconds; + convertFlexNetTime((time_t *)&secs, &tp); + time_str(datetimestr,&tp); + SysLogPuts(datetimestr); + + if (priorty<=SyslogLevelToWrite && SysLogWriteFunc!=NULL) + { + SysLogWriteFunc(datetimestr,strlen(datetimestr)); + } + } +#endif +#endif + + SysLogPuts(vastr); +// +// if (priorty<=SyslogLevelToWrite && SysLogWriteFunc!=NULL) +// { +// SysLogWriteFunc(vastr,strlen(vastr)); +// SysLogWriteFunc(NEW_LINE,strlen(NEW_LINE)); +// } + + + SysLogPuts(ANSI_NORMAL); + SysLogPuts(NEW_LINE); + + + + if (priorty == LOG_EMERG) { + //you can reboot processor here + } + + //start the watch dog where left off.. + Sys_WDogHoldOff(); + SysLogProcessing=0; + SysLog_Enabled=previousState; + return; +} diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.h b/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.h new file mode 100644 index 0000000..acd7b2e --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/syslog.h @@ -0,0 +1,210 @@ +/* + * syslog.h + * + * Created on: Sep 14, 2011 + * Author: trampas.stern + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#ifndef SYSLOG_H_ +#define SYSLOG_H_ + +#include +#include +#include +#include "Arduino.h" +#include "variant.h" + +#ifdef __cplusplus +extern "C" +{ +#endif // __cplusplus + +#define SYSLOG_BUFFER_SIZE (250) + +#define MAX_SYSLOG_STRING (250) +#define __FILENAME1__ (__builtin_strrchr(__FILE__, '\\') ? __builtin_strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (__builtin_strrchr(__FILENAME1__, '/') ? __builtin_strrchr(__FILENAME1__, '/') + 1 : __FILENAME1__) + +#define SYSLOG_WRITE(buffer,nBytes) + +#ifdef CMD_SERIAL_PORT +#define SYSLOG_PUTC(x) +#else +#define SYSLOG_PUTC(x) //SerialUSB.write(x) +#endif + +#define Sys_WDogHoldOn() +#define Sys_WDogHoldOff() +/* + * priorities/facilities are encoded into a single 32-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ + +typedef enum _eLogLevel { + LOG_EMERG = 0, // system is unusable + LOG_ALERT = 1, // action must be taken immediately + LOG_CRIT = 2, // critical conditions + LOG_ERROR = 3, // error conditions + LOG_WARNING = 4, // warning conditions + LOG_NOTICE = 5, // normal but significant condition + LOG_INFO = 6, // informational + LOG_DEBUG = 7, // debug-level messages + LOG_DISABLED = 8 // disabled messages +} eLogLevel; + +#if 0 +#define CONCAT(x, y) CONCAT_(x, y) +#define CONCAT_(x, y) x##y + +#define ID(...) __VA_ARGS__ + +#define IFMULTIARG(if,then,else) \ +CONCAT(IFMULTIARG_, IFMULTIARG_(if, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +1, 1, 0, ))(then,else) +#define IFMULTIARG_(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, \ +_10, _11, _12, _13, _14, _15, _16, _17, _18, _19, \ +_20, _21, _22, _23, _24, _25, _26, _27, _28, _29, \ +_30, _31, _32, _33, _34, _35, _36, _37, _38, _39, \ +_40, _41, _42, _43, _44, _45, _46, _47, _48, _49, \ +_50, _51, _52, _53, _54, _55, _56, _57, _58, _59, \ +_60, _61, _62, _63, ...) _63 +#define IFMULTIARG_0(then, else) else +#define IFMULTIARG_1(then, else) then + +#define PROVIDE_SECOND_ARGUMENT(x, ...) CONCAT( IFMULTIARG(ID(__VA_ARGS__), INSERT_, ADD_), SECOND_ARGUMENT ) (x, __VA_ARGS__) +#define PROVIDE_SECOND_ARGUMENT2(x, y, ...) CONCAT( IFMULTIARG(ID(__VA_ARGS__), INSERT_, ADD_), SECOND_ARGUMENT2 ) (x, y, __VA_ARGS__) + +#define ADD_SECOND_ARGUMENT(x, y) y, x +#define INSERT_SECOND_ARGUMENT(x, y, ...) y, x, __VA_ARGS__ + +#define ADD_SECOND_ARGUMENT2(x, z, y) y, x, z +#define INSERT_SECOND_ARGUMENT2(x, z, y, ...) y, x, z, __VA_ARGS__ + +#endif +//#define DEBUG1(...) printf( "DEBUG %s %s: " +//PROVIDE_SECOND_ARGUMENT2(__FILE__, __LINE__, __VA_ARGS__)) + + +//TXT(x) macro is used for system which can store strings in flash, like AVR processors +#ifndef TXT + #define TXT(x) x +#endif + +void SysLog(eLogLevel priorty, const char *fmt, ...); + + + +static inline const char * __file__( const char *filename ) { + char const *p = strrchr( filename, '/' ); + if ( p ) + return p+1; + else + return filename; +} // __file__ + + +//These macros abstract the logging and append the file and line number to errors. +#ifndef SYSLOG_DISABLE +//#ifndef PGM_P +#if 1 +//EMERG means system is unstable thus will force a reboot! +#define EMERG(fmt, ...) SysLog( LOG_EMERG, "EMERG: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define ALERT(fmt, ...) SysLog( LOG_ALERT, "ALERT: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define CRITICAL(fmt, ...) SysLog( LOG_CRIT, "CRITICAL: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define ERROR(fmt, ...) SysLog( LOG_ERROR, "ERROR: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define WARNING(fmt, ...) SysLog( LOG_WARNING, "WARNING: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define NOTICE(fmt, ...) SysLog( LOG_NOTICE, "NOTICE: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define INFO(fmt, ...) SysLog( LOG_INFO, "INFO: %s %4d: " fmt, __FILENAME__, __LINE__, ## __VA_ARGS__ ) +#define LOG(fmt, ...) SysLog( LOG_DEBUG, "%s %4d: " fmt, __FILENAME__ , __LINE__, ## __VA_ARGS__ ) +// +//#define EMERG(...) SysLog( LOG_EMERG, "EMERG: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define ALERT(...) SysLog( LOG_ALERT, "ALERT: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define CRITICAL(...) SysLog( LOG_CRIT, "CRITICAL: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define ERROR(...) SysLog( LOG_ERROR, "ERROR: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define WARNING(...) SysLog( LOG_WARNING, "WARNING: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define NOTICE(...) SysLog( LOG_NOTICE, "NOTICE: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define INFO(...) SysLog( LOG_INFO, "INFO: %15s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +//#define LOG(...) SysLog( LOG_DEBUG, "%s %4d: " PROVIDE_SECOND_ARGUMENT2(BASE_FILE_NAME, __LINE__,__VA_ARGS__ ) ) +#else +//EMERG means system is unstable thus will force a reboot! +#define EMERG(fmt, ...) SysLog( LOG_EMERG, PSTR("EMERG: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define ALERT(fmt, ...) SysLog( LOG_ALERT, PSTR("ALERT: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define CRITICAL(fmt, ...) SysLog( LOG_CRIT, PSTR("CRITICAL: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define ERROR(fmt, ...) SysLog( LOG_ERROR, PSTR("ERROR: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define WARNING(fmt, ...) SysLog( LOG_WARNING, PSTR("WARNING: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define NOTICE(fmt, ...) SysLog( LOG_NOTICE, PSTR("NOTICE: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define INFO(fmt, ...) SysLog( LOG_INFO, PSTR("INFO: %15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) +#define LOG(fmt, ...) SysLog( LOG_DEBUG, PSTR("%15s %4d: " fmt), __file__(__FILE__), __LINE__, ## __VA_ARGS__ ) + +#endif +#else +#define EMERG(fmt, ...) +#define ALERT(fmt, ...) +#define CRITICAL(fmt, ...) +#define ERROR(fmt, ...) +#define WARNING(fmt, ...) +#define NOTICE(fmt, ...) +#define INFO(fmt, ...) +#define LOG(fmt, ...) + +#endif //SYSLOG_DIABLE + +//Note that if you are running debug code with JTAG the assert will stop +// However you might want to run release code with syslog enabled for testing +// where you want error logging, but asserts are not enabled. +// Thus this macro does error logging and an assert. +//This macro assumed to take a constant string as argument + + +//this can be enabled to log asserts to the history file, if you have code space to do it. +#ifdef ASSERT_HISTORY +#define ASSERT(x) {if(!(x)){ERROR(#x); HISTORY_ASSERT();} assert(x);} +#define ASSERT_ERROR(x) {HISTORY_ASSERT(); ERROR(x); ASSERT_FAIL(x);} +#else +#define ASSERT(x) {if(!(x)){ERROR(#x);} assert(x);} +#define ASSERT_ERROR(x) {ERROR(x); ASSERT_FAIL(x);} +#endif + + +void SysLogInit(Stream *ptrSerialObj, eLogLevel LevelToWrite); +int SysLogDisable(void); +int SysLogEnable(void); +int SysLogIsEnabled(void); + +void SysLogDebug(bool x); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* SYSLOG_H_ */ diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/utils.cpp b/firmware_smartstepper_trikarus/stepper_nano_zero/utils.cpp new file mode 100644 index 0000000..144ec2e --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/utils.cpp @@ -0,0 +1,45 @@ +/********************************************************************** + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +#include "utils.h" +#include "syslog.h" + +double CubicInterpolate( + double y0,double y1, + double y2,double y3, + double mu) +{ + double a0,a1,a2,a3,mu2; + + mu2 = mu*mu; + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; + + return(a0*mu*mu2+a1*mu2+a2*mu+a3); +} + + + diff --git a/firmware_smartstepper_trikarus/stepper_nano_zero/utils.h b/firmware_smartstepper_trikarus/stepper_nano_zero/utils.h new file mode 100644 index 0000000..b8f1a11 --- /dev/null +++ b/firmware_smartstepper_trikarus/stepper_nano_zero/utils.h @@ -0,0 +1,39 @@ +/********************************************************************** + * Author: tstern + * + Copyright (C) 2018 MisfitTech, All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + Written by Trampas Stern for MisfitTech. + + Misfit Tech invests time and resources providing this open source code, + please support MisfitTech and open-source hardware by purchasing + products from MisfitTech, www.misifittech.net! + *********************************************************************/ + +/* this file contains generic utilities and functions */ + +#ifndef UTILS_H_ +#define UTILS_H_ + + +double CubicInterpolate( + double y0,double y1, + double y2,double y3, + double mu); + + + + +#endif /* UTILS_H_ */ diff --git a/grafana/collectd_InfluxDB Metrics.json b/grafana/collectd_InfluxDB Metrics.json new file mode 100644 index 0000000..5bac6bc --- /dev/null +++ b/grafana/collectd_InfluxDB Metrics.json @@ -0,0 +1,14085 @@ +{ + "__inputs": [ + { + "name": "DS_INFLUXDB_| COLLECTD", + "label": "InfluxDB | collectd", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + }, + { + "name": "DS_INFLUXDB_| TRIKARUS", + "label": "InfluxDB | trikarus", + "description": "", + "type": "datasource", + "pluginId": "influxdb", + "pluginName": "InfluxDB" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.0.6" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "datasource", + "id": "influxdb", + "name": "InfluxDB", + "version": "1.0.0" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "text", + "name": "Text", + "version": "" + } + ], + "annotations": { + "list": [ + { + "$$hashKey": "object:353", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "This dashboard provides various performance metrics for Linux systems, with templating to select the influxdb datasource and host.", + "editable": true, + "gnetId": 6642, + "graphTooltip": 1, + "id": null, + "links": [], + "panels": [ + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 122, + "panels": [ + { + "cacheTimeout": null, + "content": "
\n\n
", + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 23, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 39, + "links": [], + "mode": "html", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "1m" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "measurement": "interface_tx", + "orderByTime": "ASC", + "policy": "default", + "query": "", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "/60" + ], + "type": "math" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$hostname$/" + }, + { + "condition": "AND", + "key": "instance", + "operator": "=~", + "value": "/^$ifname$/" + }, + { + "condition": "AND", + "key": "type", + "operator": "=", + "value": "if_octets" + } + ] + } + ], + "title": "Webcam", + "type": "text" + } + ], + "title": "Webcam Logitech C920", + "type": "row" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 1 + }, + "id": 31, + "panels": [], + "title": "Last One Hour Realtime Statistics", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "$$hashKey": "object:154", + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + }, + { + "$$hashKey": "object:155", + "id": 1, + "op": "=", + "text": "(I) Idle", + "type": 1, + "value": "0" + }, + { + "$$hashKey": "object:156", + "id": 2, + "op": "=", + "text": "(P) Printing from SD Card", + "type": 1, + "value": "1" + }, + { + "$$hashKey": "object:157", + "id": 3, + "op": "=", + "text": "(S) Stopped", + "type": 1, + "value": "2" + }, + { + "$$hashKey": "object:158", + "id": 4, + "op": "=", + "text": "(C) Running config file", + "type": 1, + "value": "3" + }, + { + "$$hashKey": "object:159", + "id": 5, + "op": "=", + "text": "(A) Paused", + "type": 1, + "value": "4" + }, + { + "$$hashKey": "object:160", + "id": 6, + "op": "=", + "text": "(D) Pausing", + "type": 1, + "value": "5" + }, + { + "$$hashKey": "object:161", + "id": 7, + "op": "=", + "text": "(R) Resuming from pause", + "type": 1, + "value": "6" + }, + { + "$$hashKey": "object:162", + "id": 8, + "op": "=", + "text": "(B) Busy", + "type": 1, + "value": "7" + }, + { + "$$hashKey": "object:163", + "id": 9, + "op": "=", + "text": "(F) Firmware Update", + "type": 1, + "value": "8" + }, + { + "$$hashKey": "object:164", + "id": 10, + "op": "=", + "text": "(O) Offline / no PSU voltage", + "type": 1, + "value": "-1" + }, + { + "$$hashKey": "object:176", + "id": 11, + "op": "=", + "text": "No network", + "type": 1, + "value": "-2" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "#d44a3a", + "value": null + }, + { + "color": "#F2495C", + "value": -1 + }, + { + "color": "#299c46", + "value": 0 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 2 + }, + "id": 70, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(status) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Controller Status", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "On", + "type": 1, + "value": "0" + }, + { + "id": 1, + "op": "=", + "text": "Off", + "type": 1, + "value": "1" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "purple", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 2 + }, + "id": 83, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(value) from \"relay_states_value\" WHERE \"type_instance\" = 'pin_psu' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de'", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "PSU Status", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "description": "", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "Off", + "type": 1, + "value": "0" + }, + { + "id": 1, + "op": "=", + "text": "On", + "type": 1, + "value": "1" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "#EAB839", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 2 + }, + "id": 82, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "background", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(value) from \"relay_states_value\" WHERE \"type_instance\" = 'pin_ledspot' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de'", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "LED Status", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "description": "0.0 V cannot be displayed because the controller just would be offline\n0.1 V to 5.0 V is USB only voltage\n22.0 V is shutdown voltage\n23.0 V is resume voltage\n24.0 V to 24.3 V is regular voltage from power supply", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "$$hashKey": "object:224", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "#EAB839", + "value": 5 + }, + { + "color": "red", + "value": 22 + }, + { + "color": "red", + "value": 23 + }, + { + "color": "green", + "value": 24 + }, + { + "color": "green", + "value": 24.3 + }, + { + "color": "red", + "value": 24.4 + } + ] + }, + "unit": "volt" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 15, + "y": 2 + }, + "id": 84, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(vin) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "PSU Voltage @ Duet", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgb(0, 0, 0)", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 2 + }, + "hideTimeOverride": true, + "id": 1, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "expr": "", + "groupBy": [], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"value\") FROM \"uptime_value\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de'", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "uptime" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": "1h", + "title": "RPi Uptime", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 102400000 + }, + { + "color": "rgba(50, 172, 45, 0.97)", + "value": 204800000 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 0, + "y": 6 + }, + "hideTimeOverride": true, + "id": 4, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "mean" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "10s" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"memory_value\" WHERE \"type_instance\" = 'free' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(10s) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "available_percent" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": "1h", + "title": "Free Memory", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 5, + "y": 6 + }, + "hideTimeOverride": true, + "id": 21, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"memory_value\" WHERE \"type_instance\" = 'cached' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(10s) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": "1h", + "title": "Memory Cached", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 10, + "y": 6 + }, + "hideTimeOverride": true, + "id": 3, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "expr": "", + "groupBy": [], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"memory_value\" WHERE \"type_instance\" = 'used' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(10s) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": "1h", + "title": "Memory Used", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 5, + "x": 15, + "y": 6 + }, + "hideTimeOverride": true, + "id": 20, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"memory_value\" WHERE \"type_instance\" = 'buffered' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(10s) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": "1h", + "title": "Memory Buffered", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgba(50, 172, 45, 0.97)", + "value": null + }, + { + "color": "rgba(237, 129, 40, 0.89)", + "value": 10 + }, + { + "color": "rgba(245, 54, 54, 0.9)", + "value": 5 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 4, + "x": 20, + "y": 6 + }, + "hideTimeOverride": true, + "id": 2, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "expr": "", + "groupBy": [], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"load_midterm\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(10s) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "n_cpus" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": "1h", + "title": "5min Load", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 3, + "mappings": [ + { + "$$hashKey": "object:368", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgb(0, 0, 0)", + "value": null + } + ] + }, + "unit": "lengthmm" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 0, + "y": 10 + }, + "id": 86, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(z_coord) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Z Coord", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 3, + "mappings": [ + { + "$$hashKey": "object:416", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "rgb(0, 0, 0)", + "value": null + } + ] + }, + "unit": "lengthmm" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 3, + "y": 10 + }, + "id": 77, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(babystep) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Z Baby Step", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "$$hashKey": "object:464", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 6, + "y": 10 + }, + "id": 76, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(mcu_temp) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Duet MCU Temperature", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "$$hashKey": "object:512", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "green", + "value": 170 + }, + { + "color": "green", + "value": 240 + }, + { + "color": "#EAB839", + "value": 250 + }, + { + "color": "dark-yellow", + "value": 260 + }, + { + "color": "red", + "value": 275 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 9, + "y": 10 + }, + "id": 78, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(hotend_temp) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "SuperVolcano Hotend Temperature", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 80 + }, + { + "color": "red", + "value": 85 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 12, + "y": 10 + }, + "hideTimeOverride": true, + "id": 45, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "expr": "", + "groupBy": [], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(\"value\") FROM \"cpu_temp_value\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de'", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "uptime" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "timeFrom": "1h", + "title": "RPi CPU Temperature", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "$$hashKey": "object:272", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 25 + }, + { + "color": "green", + "value": 100 + }, + { + "color": "red", + "value": 125 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 15, + "y": 10 + }, + "id": 79, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(extrfactor) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Extrusion Factor", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 1, + "mappings": [ + { + "$$hashKey": "object:320", + "id": 0, + "op": "=", + "text": "n.a.", + "type": 1, + "value": "99999" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 200 + }, + { + "color": "red", + "value": 300 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 18, + "y": 10 + }, + "id": 80, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "sum" + ] + }, + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "alias": "", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(speedfactor) FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "table", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Speed Factor", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [ + { + "id": 0, + "op": "=", + "text": "N/A", + "type": 1, + "value": "null" + } + ], + "nullValueMode": "connected", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "purple", + "value": 1 + }, + { + "color": "red", + "value": 2 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 3, + "x": 21, + "y": 10 + }, + "hideTimeOverride": true, + "id": 22, + "interval": null, + "links": [], + "maxDataPoints": 100, + "options": { + "colorMode": "value", + "fieldOptions": { + "calcs": [ + "lastNotNull" + ] + }, + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + } + }, + "pluginVersion": "7.0.6", + "targets": [ + { + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"users_value\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "timeFrom": "1h", + "title": "RPi Users/Sessions", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 58, + "panels": [], + "title": "All-over Network", + "type": "row" + }, + { + "aliasColors": {}, + "bars": true, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 15 + }, + "hiddenSeries": false, + "id": 43, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": false, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "received", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "1h" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "interface_rx", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT non_negative_derivative(mean(\"value\"), 1h) FROM \"interface_rx\" WHERE (\"host\" = 'hangprinter-pi.fablabchemnitz.de' AND \"type\" = 'if_octets') AND $timeFilter GROUP BY time(1h) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "1h" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "type", + "operator": "=", + "value": "if_octets" + } + ] + }, + { + "alias": "sent", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "1h" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "interface_tx", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT non_negative_derivative(mean(\"value\"), 1h) FROM \"interface_tx\" WHERE (\"host\" = 'hangprinter-pi.fablabchemnitz.de' AND \"type\" = 'if_octets') AND $timeFilter GROUP BY time(1h) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "1h" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + }, + { + "condition": "AND", + "key": "type", + "operator": "=", + "value": "if_octets" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Utilization (Hourly)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 15 + }, + "hiddenSeries": false, + "id": 23, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_instance Errors In", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT derivative(mean(value), 1s) FROM \"interface_rx\" WHERE \"type\"='if_errors' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), instance fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "$tag_instance Errors Out", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT derivative(mean(value), 1s) FROM \"interface_tx\" WHERE \"type\"='if_errors' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), instance fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_sent" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Errors", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 15 + }, + "hiddenSeries": false, + "id": 14, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_instance Data In", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT derivative(mean(value), 1s)*8 FROM \"interface_rx\" WHERE \"type\"='if_octets' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), instance fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "$tag_instance Data Out", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT derivative(mean(value), 1s)*8 FROM \"interface_tx\" WHERE \"type\"='if_octets' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), instance fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_sent" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Network Traffic", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bps", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "E", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "0", + "frequency": "10s", + "handler": 1, + "message": "Duet could not be pinged. Maybe controller was reset by M112, M999 or reconfigured by M552", + "name": "Duet 2 pings @ local alert", + "noDataState": "keep_state", + "notifications": [ + { + "uid": "ye2notZgk" + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 2, + "description": "drop rate of 1.0 means there is no connection at all! The information is helpful to see if device was rebooted for example.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 22 + }, + "hiddenSeries": false, + "id": 62, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "latency (ms)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = 'yourduet' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "standard devation (ms)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping_stddev' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = 'yourduet' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "drop rate", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping_droprate' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = 'yourduet' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.9 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Duet 2 pings @ local (data from hangprinter-pi)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:730", + "decimals": 2, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": 0, + "show": true + }, + { + "$$hashKey": "object:731", + "decimals": 2, + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "E", + "1m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "0m", + "frequency": "10s", + "handler": 1, + "name": "c-MaschinenBoom-FLC pings @ local alert", + "noDataState": "keep_state", + "notifications": [ + { + "uid": "ye2notZgk" + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 2, + "description": "drop rate of 1.0 means there is no connection at all! The information is helpful to see if device was rebooted for example.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 28 + }, + "hiddenSeries": false, + "id": 63, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideEmpty": false, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "sideWidth": null, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "latency (ms)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = '2001:bc8:3f13:ffc2:ee08:6bff:feb8:1778' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "standard devation (ms)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping_stddev' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = '2001:bc8:3f13:ffc2:ee08:6bff:feb8:1778' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "drop rate", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "net", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"ping_value\" WHERE type = 'ping_droprate' AND host = 'hangprinter-pi.fablabchemnitz.de' AND type_instance = '2001:bc8:3f13:ffc2:ee08:6bff:feb8:1778' AND $timeFilter GROUP BY type_instance , time($__interval) fill(null)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "bytes_recv" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.9 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "c-MaschinenBoom-FLC pings @ local (data from hangprinter-pi)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:682", + "decimals": 2, + "format": "none", + "label": null, + "logBase": 1, + "max": "150", + "min": 0, + "show": true + }, + { + "$$hashKey": "object:683", + "decimals": 2, + "format": "ms", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 124, + "panels": [], + "title": "Duet 2 Ethernet v1.04", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 1, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 35 + }, + "hiddenSeries": false, + "id": 125, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Temperature", + "color": "#F2495C" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Temperature", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"hotend_temp\") FROM \"duet_ethernet\" WHERE $timeFilter GROUP BY time(60s)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "SuperVolcano Hotend Temperatures", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "celsius", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 1, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 35 + }, + "hiddenSeries": false, + "id": 126, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:230", + "alias": "Temperature", + "color": "#FF9830" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Temperature", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"mcu_temp\") FROM \"duet_ethernet\" WHERE $timeFilter GROUP BY time(60s)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "MCU Temperature", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:243", + "decimals": 1, + "format": "celsius", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:244", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 24 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "last" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "0m", + "frequency": "3s", + "handler": 1, + "message": "Duet VIN Power dropped below 24.0 V", + "name": "Duet 2 Voltage (VIN) alert", + "noDataState": "keep_state", + "notifications": [ + { + "uid": "ye2notZgk" + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 1, + "description": "This normally should be 24.0 to 24.3 V. If it is 5 V or below it points to \n- powering the Duet by Raspberry Pi now (which gets the power from UPS)\n- 230 V supply was shut down completely (emergency button was hit or regular shut down of main power cord)\n- possible problem with wiring.\n\nTo check against please also have a look at Smart Stepper monitoring. They can only be online if they are powered by USB 5 V and/or 24 V main power.\n\nThe voltage cannot be 0 V because Duet would be just offline and could not deliver those measurement values", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 35 + }, + "hiddenSeries": false, + "id": 85, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Voltage", + "color": "#FF9830" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Voltage", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"vin\") FROM \"duet_ethernet\" WHERE $timeFilter GROUP BY time(60s)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 24 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Voltage (VIN)", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 1, + "format": "volt", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 43 + }, + "hiddenSeries": false, + "id": 128, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Extrusion Factor", + "color": "#5794F2" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Extrusion Factor", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"extrfactor\" FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Extrusion Factor History", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 43 + }, + "hiddenSeries": false, + "id": 129, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Print Speed Factor", + "color": "#B877D9" + } + ], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Print Speed Factor", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"speedfactor\" FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Print Speed Factor History", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "percent", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 1, + "description": "-2 = No network connection\n-1 = O = Offline / no PSU voltage\n 0 = I = idle\n 1 = P = printing from SD card (processing)\n 2 = S = paused (i.e. needs a reset)\n 3 = C = running config file (i.e starting up)\n 4 = A = paused\n 5 = D = pausing\n 6 = R = resuming from a pause\n 7 = B = busy (e.g. running a macro)\n 8 = F = performing firmware update\n 9 = T = changing tool\n 10 = S = simulating\n 11 = H = halted", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 43 + }, + "hiddenSeries": false, + "id": 81, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Status", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"status\" FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Controller Status Transition History", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:468", + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": "8", + "min": "-1", + "show": true + }, + { + "$$hashKey": "object:469", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 3, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 10, + "gridPos": { + "h": 8, + "w": 16, + "x": 0, + "y": 51 + }, + "hiddenSeries": false, + "id": 87, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Z Coord", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"z_coord\" FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Z Coord History", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:963", + "decimals": 3, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": "2500", + "min": "-10", + "show": true + }, + { + "$$hashKey": "object:964", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 51 + }, + "hiddenSeries": false, + "id": 72, + "legend": { + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Baby Step", + "groupBy": [ + { + "params": [ + "$__interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT \"babystep\" FROM \"duet_ethernet\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Baby Steps History", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 59 + }, + "id": 66, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The average speed is calculated in 5 second interval by script. Have a look at rotaryEncoder.py file", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 60 + }, + "hiddenSeries": false, + "id": 64, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Current speed (mm/s)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mm_per_s FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Onrush (mm/s)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT gust FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Average speed (mm/s)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT avg FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "G", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Velocities", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1920", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:1921", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The travel distance is a kind of absolute sum which is added/subtracted by rough value 3.01 mm. This comes from constant values which are 11.5 mm rubber wheel diameter and 12 ticks per full rotation. So 1/12 of the wheel circumference are 3.01 mm.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 67 + }, + "hiddenSeries": false, + "id": 54, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Rounds per minute (rpm)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT rpm FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Absolute travel distance (mm)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT dist_meas_mm FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Absolute pulse count", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT pulse FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Distances", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:2058", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:2059", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The travel distance is a kind of absolute sum which is added/subtracted by rough value 3.01 mm. This comes from constant values which are 11.5 mm rubber wheel diameter and 12 ticks per full rotation. So 1/12 of the wheel circumference are 3.01 mm.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 74 + }, + "hiddenSeries": false, + "id": 118, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Time between two pulses (ms)", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT elapse FROM \"rotary_encoder\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Time between two pulses (ms)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:221", + "decimals": null, + "format": "none", + "label": null, + "logBase": 32, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:222", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "Filament Feed Sensor (Rotary Encoder Keyes KY040)", + "type": "row" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 60 + }, + "id": 117, + "panels": [], + "title": "MisfitTech Smart Stepper - Control Modes", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 61 + }, + "hiddenSeries": false, + "id": 97, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:323", + "alias": "torque", + "color": "#F2CC0C" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "torque", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT torque FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - torque()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": "127", + "min": "-128", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 61 + }, + "hiddenSeries": false, + "id": 101, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:323", + "alias": "torque", + "color": "#F2CC0C" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "torque", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT torque FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - torque()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": "127", + "min": "-128", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 61 + }, + "hiddenSeries": false, + "id": 104, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:323", + "alias": "torque", + "color": "#F2CC0C" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "torque", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT torque FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - torque()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": "127", + "min": "-128", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 61 + }, + "hiddenSeries": false, + "id": 107, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:323", + "alias": "torque", + "color": "#F2CC0C" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "torque", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT torque FROM \"SmartStepperD\" WHERE $timeFilter", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - torque()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": "127", + "min": "-128", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 68 + }, + "id": 120, + "panels": [], + "title": "MisfitTech Smart Stepper - Positions", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 69 + }, + "hiddenSeries": false, + "id": 90, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#3274D9" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT readpos FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - readpos()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 69 + }, + "hiddenSeries": false, + "id": 99, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#3274D9" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT readpos FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - readpos()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 69 + }, + "hiddenSeries": false, + "id": 102, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#3274D9" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT readpos FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - readpos()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 69 + }, + "hiddenSeries": false, + "id": 108, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#3274D9" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT readpos FROM \"SmartStepperD\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - readpos()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 3, + "description": "position = ((200 * Microstepping) / StepsPerUnit) * angleFromSmartStepper / 360.0", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 76 + }, + "hiddenSeries": false, + "id": 105, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#7C2EA3" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT ((200 * 16) / 200) * readpos / 360.0 FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - position in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 3, + "description": "position = ((200 * Microstepping) / StepsPerUnit) * angleFromSmartStepper / 360.0", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 76 + }, + "hiddenSeries": false, + "id": 111, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#7C2EA3" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT ((200 * 16) / 200) * readpos / 360.0 FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - position in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 3, + "description": "position = ((200 * Microstepping) / StepsPerUnit) * angleFromSmartStepper / 360.0", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 76 + }, + "hiddenSeries": false, + "id": 110, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#7C2EA3" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT ((200 * 16) / 200) * readpos / 360.0 FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - position in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 3, + "description": "position = ((200 * Microstepping) / StepsPerUnit) * angleFromSmartStepper / 360.0", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 76 + }, + "hiddenSeries": false, + "id": 109, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:301", + "alias": "readpos", + "color": "#7C2EA3" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "readpos", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT ((200 * 16) / 200) * readpos / 360.0 FROM \"SmartStepperD\" WHERE $timeFilter", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - position in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 83 + }, + "id": 95, + "panels": [], + "title": "MisfitTech Smart Stepper - Errors", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 84 + }, + "hiddenSeries": false, + "id": 134, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT serialError FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - serial errors", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 84 + }, + "hiddenSeries": false, + "id": 135, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT serialError FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - serial errors", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 84 + }, + "hiddenSeries": false, + "id": 136, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT serialError FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - serial errors", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 84 + }, + "hiddenSeries": false, + "id": 137, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null as zero", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT serialError FROM \"SmartStepperD\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - serial errors", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 91 + }, + "hiddenSeries": false, + "id": 98, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - geterror()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 91 + }, + "hiddenSeries": false, + "id": 100, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - geterror()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 91 + }, + "hiddenSeries": false, + "id": 103, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - geterror()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "The error can get really high (360 degrees and more. But they are not displayed in the graph to flatten the view)", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 91 + }, + "hiddenSeries": false, + "id": 112, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror FROM \"SmartStepperD\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' and $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - geterror()", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "arclength", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 98 + }, + "hiddenSeries": false, + "id": 106, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror / 180.0 * 3.1415926535 * 65.0 FROM \"SmartStepperA\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "A Drive - error in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "arclength", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 98 + }, + "hiddenSeries": false, + "id": 114, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror / 180.0 * 3.1415926535 * 65.0 FROM \"SmartStepperB\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "B Drive - error in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "arclength", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 98 + }, + "hiddenSeries": false, + "id": 115, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror / 180.0 * 3.1415926535 * 65.0 FROM \"SmartStepperC\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "C Drive - error in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "description": "arclength", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 98 + }, + "hiddenSeries": false, + "id": 113, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:236", + "alias": "geterror", + "color": "#E02F44" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "geterror", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT geterror / 180.0 * 3.1415926535 * 65.0 FROM \"SmartStepperD\" WHERE $timeFilter", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "D Drive - error in mm", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:515", + "decimals": null, + "format": "lengthmm", + "label": null, + "logBase": 1, + "max": "5", + "min": "-5", + "show": true + }, + { + "$$hashKey": "object:516", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": true, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 105 + }, + "id": 56, + "panels": [ + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": null, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 21 + }, + "hiddenSeries": false, + "id": 96, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "X", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_x' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Y", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_y' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Z", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_z' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ceiling module - gyro - raw values", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": null, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 28 + }, + "hiddenSeries": false, + "id": 50, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "X deg/s", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_x_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Y deg/s", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_y_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Z deg/s", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'gyro_z_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ceiling module - gyro - scaled values", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": null, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 35 + }, + "hiddenSeries": false, + "id": 51, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "X", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_x' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Y", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_y' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Z", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_z' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ceiling module - accelerometer - raw values", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": null, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 42 + }, + "hiddenSeries": false, + "id": 52, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "X m/s²", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_x_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Y m/s²", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_y_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Z m/s²", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'accel_z_scaled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ceiling module - accelerometer - scaled values", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": null, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 49 + }, + "hiddenSeries": false, + "id": 53, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "°C", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"mpu6050_value\" WHERE \"type_instance\" = 'temp' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Ceiling module - temperature sensor", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "decimals": null, + "format": "none", + "label": "", + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "title": "GY-512 MPU-6050 InvenSense", + "type": "row" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 106 + }, + "id": 92, + "panels": [], + "title": "GY-250 MPU-9250 InvenSense", + "type": "row" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 107 + }, + "id": 32, + "panels": [], + "title": "Raspberry Pi 3 Model B Rev 1.2", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 10, + "w": 12, + "x": 0, + "y": 108 + }, + "hiddenSeries": false, + "id": 6, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Short", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"load_shortterm\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "load1" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Medium", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"load_midterm\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "load5" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Long", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "system", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"load_longterm\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "load15" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Load Average", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1778", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:1779", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 10, + "w": 12, + "x": 12, + "y": 108 + }, + "hiddenSeries": false, + "id": 5, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "hideZero": true, + "max": true, + "min": true, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "CPU $tag_instance $tag_type_instance", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "cpu", + "orderByTime": "ASC", + "policy": "default", + "query": "select derivative(mean(value),1s) AS idle from \"cpu_value\" WHERE \"type\" = 'cpu' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), instance, type_instance fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "usage_guest" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "CPU Usage", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1812", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:1813", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 118 + }, + "hiddenSeries": false, + "id": 10, + "isNew": true, + "legend": { + "alignAsTable": false, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "forks", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "kernel", + "orderByTime": "ASC", + "policy": "default", + "query": "select derivative(mean(value), 1s) from \"processes_value\" WHERE \"type\" = 'fork_rate' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "processes_forked" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Forks", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1730", + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1731", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 118 + }, + "hiddenSeries": false, + "id": 8, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "used", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'used' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "used" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "free", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'free' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "free" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "buffered", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'buffered' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "buffered" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "cached", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "mem", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'cached' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "cached" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "slab_recl", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'slab_recl' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "slab_unrecl", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT mean(\"value\") FROM \"memory_value\" WHERE \"type_instance\" = 'slab_unrecl' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "(Stacked) Memory Distribution", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1696", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1697", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 1, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 125 + }, + "hiddenSeries": false, + "id": 15, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Used Swap", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"swap_value\" WHERE \"type\" = 'swap' AND \"type_instance\" = 'used' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Cached Swap", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"swap_value\" WHERE \"type\" = 'swap' AND \"type_instance\" = 'cached' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "free" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Free Swap", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"swap_value\" WHERE \"type\" = 'swap' AND \"type_instance\" = 'free' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "(Stacked) Swap Space", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1627", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1628", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 125 + }, + "hiddenSeries": false, + "id": 9, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "running", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "processes", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'running' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "running" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "blocked", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "processes", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'blocked' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "blocked" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "sleeping", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'sleeping' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "stopped", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'stopped' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "paging", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'paging' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + }, + { + "alias": "zombies", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(value) from \"processes_value\" WHERE \"type_instance\" = 'zombies' AND \"type\" = 'ps_state' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "(Stacked) Processes", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1579", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1580", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 1, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 132 + }, + "hiddenSeries": false, + "id": 12, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_type_instance interrupts", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "kernel", + "orderByTime": "ASC", + "policy": "default", + "query": "select derivative(mean(value),1s) from \"irq_value\" WHERE \"type\" = 'irq' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), \"type_instance\" fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "interrupts" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Interrupts", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1510", + "format": "ops", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1511", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 132 + }, + "hiddenSeries": false, + "id": 25, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_instance Free", + "dsType": "influxdb", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(value) FROM \"df_value\" WHERE \"type_instance\" = 'free' AND \"type\" = 'df_complex' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval), \"instance\" fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "mean" + } + ] + ], + "tags": [] + } + ], + "thresholds": [], + "timeFrom": "2w", + "timeRegions": [], + "timeShift": null, + "title": "Disk Free Space", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 80 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "avg" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "0m", + "frequency": "10s", + "handler": 1, + "name": "hangprinter-pi CPU Temperature alert", + "noDataState": "keep_state", + "notifications": [ + { + "uid": "42PfNEiRz" + }, + { + "uid": "ye2notZgk" + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 1, + "description": "The official operating temperature limit of the SoC is 85°C. it will throttle performance around 80°C.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 3, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 11, + "x": 0, + "y": 140 + }, + "hiddenSeries": false, + "id": 47, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": true, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "$$hashKey": "object:304", + "alias": "Raspberry Pi CPU Temperature", + "color": "#8F3BB8" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Raspberry Pi CPU Temperature", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select mean(*) from \"cpu_temp_value\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time(60s)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 80 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Raspberry Pi CPU Temperature", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:317", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "$$hashKey": "object:318", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 13, + "x": 11, + "y": 140 + }, + "hiddenSeries": false, + "id": 16, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": false, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Swap Page In", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select derivative(mean(value),1s) from \"swap_value\" WHERE \"type\" = 'swap_io' AND \"type_instance\" = 'in' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Swap Page Out", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select derivative(mean(value),1s) from \"swap_value\" WHERE \"type\" = 'swap_io' AND \"type_instance\" = 'out' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval) fill(null)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "out" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Swap I/O", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1476", + "format": "bytes", + "label": null, + "logBase": 1, + "max": null, + "min": 0, + "show": true + }, + { + "$$hashKey": "object:1477", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 2, + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 147 + }, + "hiddenSeries": false, + "id": 93, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": true, + "current": true, + "max": true, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "%user", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_user) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "%nice", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_nice) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "%system", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_system) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "%iowait", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_iowait) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "%steal", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_steal) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "%idle", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(val_idle) FROM \"iostat\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "in" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + }, + { + "params": [ + "10s" + ], + "type": "non_negative_derivative" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "iostat", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:312", + "decimals": 0, + "format": "percent", + "label": null, + "logBase": 1, + "max": "100", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:313", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0.9 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "D", + "10s", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "0m", + "frequency": "10s", + "handler": 1, + "name": "Power States (vcgencmd) alert", + "noDataState": "keep_state", + "notifications": [ + { + "uid": "42PfNEiRz" + }, + { + "uid": "ye2notZgk" + } + ] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 1, + "description": "Undervoltage events, combined with throttling may happen while rebooting the device. So a possible device reboot can be seen by those peaks. However, please have a look at the uptime value for exactness.", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 3, + "fillGradient": 9, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 154 + }, + "hiddenSeries": false, + "id": 48, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "throttled", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(*) from \"pwr_states_value\" WHERE \"type_instance\" = 'throttled' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "armfreq_capped", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(*) from \"pwr_states_value\" WHERE \"type_instance\" = 'armfreq_capped' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "undervoltage", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(*) from \"pwr_states_value\" WHERE \"type_instance\" = 'undervoltage' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "soft_temp_limit", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(*) from \"pwr_states_value\" WHERE \"type_instance\" = 'soft_temp_limit' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0.9 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Power States (vcgencmd)", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1283", + "decimals": null, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1284", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| COLLECTD}", + "decimals": 1, + "description": "- PSU is active off by default\n- LED is active on by default\n\nThe graph shows 0 not if the device is switched on or off. It only shows the boolean state of the relay!", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 0, + "fillGradient": 0, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 161 + }, + "hiddenSeries": false, + "id": 46, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "Led Spots on/off", + "color": "#FADE2A" + }, + { + "alias": "Power Supply Unit (PSU) on/off", + "color": "#F2495C" + } + ], + "spaceLength": 10, + "stack": true, + "steppedLine": false, + "targets": [ + { + "alias": "Led Spots on/off", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(value) from \"relay_states_value\" WHERE \"type_instance\" = 'pin_ledspot' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Power Supply Unit (PSU) on/off", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "select last(value) from \"relay_states_value\" WHERE \"type_instance\" = 'pin_psu' AND \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Relay States", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:1228", + "decimals": 0, + "format": "none", + "label": null, + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:1229", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 168 + }, + "id": 89, + "panels": [], + "title": "USB Devices", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "${DS_INFLUXDB_| TRIKARUS}", + "decimals": 0, + "description": "0 = offline, 1 = online\nIf one or all motors are offline 230 V source power might have been disconnected or some other problem occured. Please also have a look at Duet Controller voltage. Please not that this does not monitor any UART bugs in communication between Raspberry PI and USB interfaces!", + "editable": true, + "error": false, + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 1, + "grid": {}, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 169 + }, + "hiddenSeries": false, + "id": 49, + "isNew": true, + "legend": { + "alignAsTable": true, + "avg": false, + "current": true, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": false, + "values": true + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "connected", + "options": { + "dataLinks": [] + }, + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "Smart Stepper - A Drive", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(a_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Smart Stepper - B Drive", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(b_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "B", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Smart Stepper - C Drive", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(c_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "C", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Smart Stepper - D Drive", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(d_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "D", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Duet 2 Ethernet", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(duet_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "E", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "Logitech C920 Webcam", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(webcam_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "F", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "USB 4 Port Hub", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(hub_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "G", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + }, + { + "alias": "USB Stick 32GB SanDisk", + "dsType": "influxdb", + "expr": "", + "groupBy": [ + { + "params": [ + "$interval" + ], + "type": "time" + }, + { + "params": [ + "null" + ], + "type": "fill" + } + ], + "intervalFactor": 2, + "measurement": "swap", + "orderByTime": "ASC", + "policy": "default", + "query": "SELECT last(stick_avail) FROM \"usb_devices\" WHERE \"host\" = 'hangprinter-pi.fablabchemnitz.de' AND $timeFilter GROUP BY time($interval)", + "rawQuery": true, + "refId": "H", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "total" + ], + "type": "field" + }, + { + "params": [], + "type": "last" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": "1d", + "timeRegions": [], + "timeShift": null, + "title": "USB Device Availibility Status History", + "tooltip": { + "msResolution": true, + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "$$hashKey": "object:294", + "decimals": 0, + "format": "none", + "label": "", + "logBase": 1, + "max": "1", + "min": "0", + "show": true + }, + { + "$$hashKey": "object:295", + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "30s", + "schemaVersion": 25, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "browser", + "title": "collectd/InfluxDB Metrics", + "uid": "xW5kn7zRz", + "version": 105 +} \ No newline at end of file diff --git a/grafana/grafana-hangprinter.jpg b/grafana/grafana-hangprinter.jpg new file mode 100644 index 0000000..906ffe9 Binary files /dev/null and b/grafana/grafana-hangprinter.jpg differ diff --git a/inkscape_drawings/alignment-60-degrees.svg b/inkscape_drawings/alignment-60-degrees.svg new file mode 100644 index 0000000..7fa623b --- /dev/null +++ b/inkscape_drawings/alignment-60-degrees.svg @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + 60° + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/alignment-misalignment.svg b/inkscape_drawings/alignment-misalignment.svg new file mode 100644 index 0000000..d03976f --- /dev/null +++ b/inkscape_drawings/alignment-misalignment.svg @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + angle misalignment + + + + + diff --git a/inkscape_drawings/anchor-points.svg b/inkscape_drawings/anchor-points.svg new file mode 100644 index 0000000..66e7a2a --- /dev/null +++ b/inkscape_drawings/anchor-points.svg @@ -0,0 +1,564 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + A anchor point + C anchor point + B anchor point + X + Y + + + + + + + + D anchor point + + Z + + origin line lengths + + + + a + a + + + + diff --git a/inkscape_drawings/anchor-positioning.svg b/inkscape_drawings/anchor-positioning.svg new file mode 100644 index 0000000..acd363a --- /dev/null +++ b/inkscape_drawings/anchor-positioning.svg @@ -0,0 +1,3555 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/bearing-shearoff.svg b/inkscape_drawings/bearing-shearoff.svg new file mode 100644 index 0000000..c05c085 --- /dev/null +++ b/inkscape_drawings/bearing-shearoff.svg @@ -0,0 +1,1063 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 22.5° + + regular stress + + + + + + + + + + unreal string guidance + + + 45° + + + + + + + + shear off + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/build-volume-collisions.svg b/inkscape_drawings/build-volume-collisions.svg new file mode 100644 index 0000000..edd804d --- /dev/null +++ b/inkscape_drawings/build-volume-collisions.svg @@ -0,0 +1,870 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + previously printed layer + currently printing layer + line collision + + effector at max. print diameter + + effector at max. print diameter + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/build-volume.svg b/inkscape_drawings/build-volume.svg new file mode 100644 index 0000000..a06341f --- /dev/null +++ b/inkscape_drawings/build-volume.svg @@ -0,0 +1,939 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/coordinate-system-minimized.svg b/inkscape_drawings/coordinate-system-minimized.svg new file mode 100644 index 0000000..fd655c0 --- /dev/null +++ b/inkscape_drawings/coordinate-system-minimized.svg @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + X + Y + + + + + + + + diff --git a/inkscape_drawings/coordinate-system.svg b/inkscape_drawings/coordinate-system.svg new file mode 100644 index 0000000..4f2a896 --- /dev/null +++ b/inkscape_drawings/coordinate-system.svg @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + A anchor + C anchor + B anchor + origin 0,0,0 ("origo") + + X + Y + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/d-drive-unit.svg b/inkscape_drawings/d-drive-unit.svg new file mode 100644 index 0000000..2863fc0 --- /dev/null +++ b/inkscape_drawings/d-drive-unit.svg @@ -0,0 +1,179 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + spool + coil D1 + coil D2 + coil D3 + motor D drive unit + diff --git a/inkscape_drawings/effector-angles.svg b/inkscape_drawings/effector-angles.svg new file mode 100644 index 0000000..701e0db --- /dev/null +++ b/inkscape_drawings/effector-angles.svg @@ -0,0 +1,2288 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + line angle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + line angle + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/effector-coordinate-system.svg b/inkscape_drawings/effector-coordinate-system.svg new file mode 100644 index 0000000..9b12533 --- /dev/null +++ b/inkscape_drawings/effector-coordinate-system.svg @@ -0,0 +1,1230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + A anchor + B anchor + + + C anchor + B1 + B2 + A2 + A1 + C1 + C2 + + + + + + X + Y + + + + + + + + diff --git a/inkscape_drawings/effector-d-offset.svg b/inkscape_drawings/effector-d-offset.svg new file mode 100644 index 0000000..0527a2f --- /dev/null +++ b/inkscape_drawings/effector-d-offset.svg @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d + + + D line + + + A line + B line + + + + + diff --git a/inkscape_drawings/effector-line-angle.svg b/inkscape_drawings/effector-line-angle.svg new file mode 100644 index 0000000..22938da --- /dev/null +++ b/inkscape_drawings/effector-line-angle.svg @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/effector-line-guiding.svg b/inkscape_drawings/effector-line-guiding.svg new file mode 100644 index 0000000..9f1f4dc --- /dev/null +++ b/inkscape_drawings/effector-line-guiding.svg @@ -0,0 +1,315 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/effector-tool-offsets.svg b/inkscape_drawings/effector-tool-offsets.svg new file mode 100644 index 0000000..a947c75 --- /dev/null +++ b/inkscape_drawings/effector-tool-offsets.svg @@ -0,0 +1,1045 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + nozzle withxy offset + C + B + A + X + Y + + + + + + y + x + + + + + + + + + + + + + + diff --git a/inkscape_drawings/feature-double-lines.svg b/inkscape_drawings/feature-double-lines.svg new file mode 100644 index 0000000..5d68270 --- /dev/null +++ b/inkscape_drawings/feature-double-lines.svg @@ -0,0 +1,744 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + C anchor + C1/C2 line pair from C drive spool + + + C1T pivot point + C2B pivot point + + bottom of line C1 + top of line C1 + bottom of line C2 + top of line C2 + + + + + + + to effector + from effector + to effector + from effector + + + knot + C2T pivot point + + C1B pivot point + + + + + + diff --git a/inkscape_drawings/feature-single-lines.svg b/inkscape_drawings/feature-single-lines.svg new file mode 100644 index 0000000..33a0640 --- /dev/null +++ b/inkscape_drawings/feature-single-lines.svg @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + C1/C2 line pair from C drive spool + + + + + line C1 + line C2 + + + to effector + to effector + C anchor + C1 pivot point + C2 pivot point + + + + diff --git a/inkscape_drawings/frame-validation.svg b/inkscape_drawings/frame-validation.svg new file mode 100644 index 0000000..1162af8 --- /dev/null +++ b/inkscape_drawings/frame-validation.svg @@ -0,0 +1,770 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + l + AB + + + l + B + + + l + A + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + l + C + + + l + BC + + l + AC + s + C + s + A + s + B + + + diff --git a/inkscape_drawings/hangprinter.svg b/inkscape_drawings/hangprinter.svg new file mode 100644 index 0000000..e699bda --- /dev/null +++ b/inkscape_drawings/hangprinter.svg @@ -0,0 +1,853 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + frame + print bed + origin 0,0,0 ("origo") + ceiling unit + effector ("mover") + hotend nozzle tip A1 A2 C2 C1 B2 B1 D1 D2 D3 + + + + + + + + + + + + + diff --git a/inkscape_drawings/line-lengths.svg b/inkscape_drawings/line-lengths.svg new file mode 100644 index 0000000..d6621c9 --- /dev/null +++ b/inkscape_drawings/line-lengths.svg @@ -0,0 +1,2181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A1 (A2 or B1 or B2 or C1 or C2) line + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D1 (D2 or C3) line + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/main-drawing.svg b/inkscape_drawings/main-drawing.svg new file mode 100644 index 0000000..923c414 --- /dev/null +++ b/inkscape_drawings/main-drawing.svg @@ -0,0 +1,2610 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ceiling unit + + print bed + + A (or B or C) anchor (2 anchors per drive) + + A (or B or C) spool with 2 lines (1 line per coil) + + effector ("mover")at some random position + + hotend nozzle tip + + + + + + + + + + + + + + + + D spool + + + stopping arm / drive transport fixation + + D line tuner + + + + + + + + + + + + + + + + + + A (or B or C) line tuner + + + + Z + print + + Z + 0 + + + + XY + Offset + + h + 2 + + Z + + current + + h + 1 + + + Z + A + + Z + D + + + + + d + + print + effectoraxis + origoaxis + nozzleaxis + + + h + 3 + + + + h + 4 + + + + + + + + + + + + + + + + + + + + (h ) + 4 + h + 5 + + + + + doubled line mechanism(all lines parallel each) + + + + + + ceilingaxis + max + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/measuring-XY.svg b/inkscape_drawings/measuring-XY.svg new file mode 100644 index 0000000..1b43b1f --- /dev/null +++ b/inkscape_drawings/measuring-XY.svg @@ -0,0 +1,1716 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + A anchor point + C anchor point + B anchor point + X + Y + + + + + + + + D anchor point + + Z + + origin line lengths + + + + a + a + + + + + + + C2_A + C2_E + + + + + + + + + + + + + + + + + + + + + + + + + + B + X + + + + + + + + + B + Y + + + + + + + + C + Y + + + + + C + X + + A + Y + + + + A + X + =0 + + + + + + 2 + C1_A + C1_E + B1_A + B2_A + B2_E + B1_E + A2_E + A2_A + + + + + + A anchor + C anchor + B anchor + A1_E + A1_A + + + + + + + X + Y + + + + + + + diff --git a/inkscape_drawings/measuring-Z.svg b/inkscape_drawings/measuring-Z.svg new file mode 100644 index 0000000..8e46834 --- /dev/null +++ b/inkscape_drawings/measuring-Z.svg @@ -0,0 +1,1020 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + A + Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/pivot-points.svg b/inkscape_drawings/pivot-points.svg new file mode 100644 index 0000000..38ee35c --- /dev/null +++ b/inkscape_drawings/pivot-points.svg @@ -0,0 +1,1110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + A anchor + C anchor + B anchor + C2 pivot point + C1 pivot point + A1 pivot point + A2 pivot point + B2 pivot point + B1 pivot point + + + + + + + + + + + + + + + + + + + origin 0,0,0 ("origo") + X + Y + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/platform.svg b/inkscape_drawings/platform.svg new file mode 100644 index 0000000..5f12778 --- /dev/null +++ b/inkscape_drawings/platform.svg @@ -0,0 +1,88 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/inkscape_drawings/print diameter.svg b/inkscape_drawings/print diameter.svg new file mode 100644 index 0000000..e932967 --- /dev/null +++ b/inkscape_drawings/print diameter.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + angle + + d 1 + + d 2 + d 3 + + + + + + + d 4 + + + + + diff --git a/inkscape_drawings/print volume-shapes.svg b/inkscape_drawings/print volume-shapes.svg new file mode 100644 index 0000000..406bbb5 --- /dev/null +++ b/inkscape_drawings/print volume-shapes.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/inkscape_drawings/random-positions.svg b/inkscape_drawings/random-positions.svg new file mode 100644 index 0000000..97f0d4c --- /dev/null +++ b/inkscape_drawings/random-positions.svg @@ -0,0 +1,975 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + A anchor point + C anchor point + B anchor point + X + Y + + + + + + + + + D anchor point + + Z + nozzle tip with effectorat random position + + + diff --git a/inkscape_drawings/spool-buildup.svg b/inkscape_drawings/spool-buildup.svg new file mode 100644 index 0000000..2b651fc --- /dev/null +++ b/inkscape_drawings/spool-buildup.svg @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + d line + + b coil + + d coil + + winding 1 winding 2 + + + + + + + + + + d + buildup for winding 1 coil + + + d + buildup for winding 2 coil + + + diff --git a/inkscape_drawings/spool-line-deflection.svg b/inkscape_drawings/spool-line-deflection.svg new file mode 100644 index 0000000..ccd9f8e --- /dev/null +++ b/inkscape_drawings/spool-line-deflection.svg @@ -0,0 +1,392 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prusaslicer_profile/config.ini b/prusaslicer_profile/config.ini new file mode 100644 index 0000000..d72a31e --- /dev/null +++ b/prusaslicer_profile/config.ini @@ -0,0 +1,239 @@ +# generated by PrusaSlicer 2.2.0+win64 on 2020-07-11 at 20:15:29 UTC +avoid_crossing_perimeters = 0 +bed_custom_texture = trikarus-bed.svg +bed_shape = 498.097x43.5779,492.404x86.8241,482.963x129.41,469.846x171.01,453.154x211.309,433.013x250,409.576x286.788,383.022x321.394,353.553x353.553,321.394x383.022,286.788x409.576,250x433.013,211.309x453.154,171.01x469.846,129.41x482.963,86.8241x492.404,43.5779x498.097,3.06162e-14x500,-43.5779x498.097,-86.8241x492.404,-129.41x482.963,-171.01x469.846,-211.309x453.154,-250x433.013,-286.788x409.576,-321.394x383.022,-353.553x353.553,-383.022x321.394,-409.576x286.788,-433.013x250,-453.154x211.309,-469.846x171.01,-482.963x129.41,-492.404x86.8241,-498.097x43.5779,-500x6.12323e-14,-498.097x-43.5779,-492.404x-86.8241,-482.963x-129.41,-469.846x-171.01,-453.154x-211.309,-433.013x-250,-409.576x-286.788,-383.022x-321.394,-353.553x-353.553,-321.394x-383.022,-286.788x-409.576,-250x-433.013,-211.309x-453.154,-171.01x-469.846,-129.41x-482.963,-86.8241x-492.404,-43.5779x-498.097,-9.18485e-14x-500,43.5779x-498.097,86.8241x-492.404,129.41x-482.963,171.01x-469.846,211.309x-453.154,250x-433.013,286.788x-409.576,321.394x-383.022,353.553x-353.553,383.022x-321.394,409.576x-286.788,433.013x-250,453.154x-211.309,469.846x-171.01,482.963x-129.41,492.404x-86.8241,498.097x-43.5779,500x-1.22465e-13 +bed_temperature = 0 +before_layer_gcode = +between_objects_gcode = +bottom_fill_pattern = rectilinear +bottom_solid_layers = 2 +bottom_solid_min_thickness = 0 +bridge_acceleration = 0 +bridge_angle = 0 +bridge_fan_speed = 100 +bridge_flow_ratio = 1 +bridge_speed = 60 +brim_width = 0 +clip_multipart_objects = 1 +colorprint_heights = +complete_objects = 0 +cooling = 1 +cooling_tube_length = 5 +cooling_tube_retraction = 91.5 +default_acceleration = 0 +default_filament_profile = "" +default_print_profile = +deretract_speed = 0 +disable_fan_first_layers = 2 +dont_support_bridges = 0 +draft_shield = 0 +duplicate_distance = 6 +elefant_foot_compensation = 0.2 +end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n" +end_gcode = ;PrusaSlicer automatically generates M107 command at the end which turns off the fan. But we want to cool down the last millimeters too for some more seconds\nM106 S255 ;re-enable blower fan\nM104 S0 ;turn off temperature\nG91 ;relative coordinates\nG0 Z3 ;move extruder 3 mm higher\nG90 ;absolute coordinates\nG4 S20 ;wait 30 seconds\nM106 S0 ;then turn off the blower fan again +ensure_vertical_shell_thickness = 1 +external_perimeter_extrusion_width = 1.57 +external_perimeter_speed = 75% +external_perimeters_first = 0 +extra_loading_move = -2 +extra_perimeters = 1 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extruder_colour = #0080FF +extruder_offset = 0x0 +extrusion_axis = E +extrusion_multiplier = 1 +extrusion_width = 1.57 +fan_always_on = 1 +fan_below_layer_time = 60 +filament_colour = #FFFFFF +filament_cooling_final_speed = 3.4 +filament_cooling_initial_speed = 2.2 +filament_cooling_moves = 4 +filament_cost = 18.81 +filament_density = 1.25 +filament_deretract_speed = nil +filament_diameter = 1.8 +filament_load_time = 0 +filament_loading_speed = 28 +filament_loading_speed_start = 3 +filament_max_volumetric_speed = 0 +filament_minimal_purge_on_wipe_tower = 15 +filament_notes = "offical data from spool:\n- density: 1.25 g/cm^3\n- diameter: 1.75 mm +/- 0.05 mm (90% of all filament spools below +/- 0.02 mm)\n- print temperature: 205 C +/- 10 C" +filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" +filament_retract_before_travel = nil +filament_retract_before_wipe = nil +filament_retract_layer_change = nil +filament_retract_length = nil +filament_retract_lift = nil +filament_retract_lift_above = nil +filament_retract_lift_below = nil +filament_retract_restart_extra = nil +filament_retract_speed = nil +filament_settings_id = "Trikarus - Redline Filament PLA" +filament_soluble = 0 +filament_toolchange_delay = 0 +filament_type = PLA +filament_unload_time = 0 +filament_unloading_speed = 90 +filament_unloading_speed_start = 100 +filament_vendor = (Unknown) +filament_wipe = nil +fill_angle = 45 +fill_density = 5% +fill_pattern = gyroid +first_layer_acceleration = 0 +first_layer_bed_temperature = 0 +first_layer_extrusion_width = 1.47 +first_layer_height = 110% +first_layer_speed = 20% +first_layer_temperature = 205 +gap_fill_speed = 40 +gcode_comments = 0 +gcode_flavor = marlin +gcode_label_objects = 0 +high_current_on_filament_swap = 0 +host_type = duet +infill_acceleration = 0 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 1.57 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 45 +interface_shells = 0 +layer_gcode = +layer_height = 1 +machine_max_acceleration_e = 1000,1000 +machine_max_acceleration_extruding = 1500,1500 +machine_max_acceleration_retracting = 1500,1500 +machine_max_acceleration_x = 1000,1000 +machine_max_acceleration_y = 1000,1000 +machine_max_acceleration_z = 1000,1000 +machine_max_feedrate_e = 3600,3600 +machine_max_feedrate_x = 9500,9500 +machine_max_feedrate_y = 9500,9500 +machine_max_feedrate_z = 9500,9500 +machine_max_jerk_e = 2.5,2.5 +machine_max_jerk_x = 10,10 +machine_max_jerk_y = 10,10 +machine_max_jerk_z = 0.2,0.2 +machine_min_extruding_rate = 0,0 +machine_min_travel_rate = 0,0 +max_fan_speed = 100 +max_layer_height = 1.4 +max_print_height = 2000 +max_print_speed = 50 +max_volumetric_speed = 110 +min_fan_speed = 65 +min_layer_height = 0.3 +min_print_speed = 10 +min_skirt_length = 100 +notes = +nozzle_diameter = 1.4 +only_retract_when_crossing_perimeters = 1 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +parking_pos_retraction = 92 +perimeter_acceleration = 0 +perimeter_extruder = 1 +perimeter_extrusion_width = 1.57 +perimeter_speed = 35 +perimeters = 2 +post_process = +print_host = +print_settings_id = Trikarus +printer_model = +printer_notes = - M203 command in PrusaSlicer takes mm/second but Duet RRF takes those values as mm/minute. So you need to enter the mm/minute values without conversion\n- M73 not supported by RRF +printer_settings_id = Trikarus +printer_technology = FFF +printer_variant = +printer_vendor = +printhost_apikey = +printhost_cafile = +raft_layers = 0 +remaining_times = 0 +resolution = 0 +retract_before_travel = 2 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 3 +retract_length_toolchange = 10 +retract_lift = 1.5 +retract_lift_above = 0 +retract_lift_below = 0 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 60 +seam_position = nearest +serial_port = +serial_speed = 250000 +silent_mode = 1 +single_extruder_multi_material = 0 +single_extruder_multi_material_priming = 1 +skirt_distance = 40 +skirt_height = 1 +skirts = 1 +slice_closing_radius = 0.049 +slowdown_below_layer_time = 5 +small_perimeter_speed = 30 +solid_infill_below_area = 70 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 1.57 +solid_infill_speed = 35 +spiral_vase = 0 +standby_temperature_delta = -5 +start_filament_gcode = "; Filament gcode\n" +start_gcode = G28 ;reset coordinates - you must delete the files homex.g and homey.g on Duet Web Control because they contain dangerious moves when using default DWC config\n;deactivated stuff:\n;G92 X0 Y0 Z0 ;reset coordinates - does not always work so we use preceding G28\n;M106 P2 S0 ;turn off laser pointers - this is done by sms_prepare.sh script. no need to do twice\nM117 "Starting new GCode print job" ;M291 PMESSAGE does not work here. It just won't be displayed while printing +support_material = 0 +support_material_angle = 0 +support_material_auto = 1 +support_material_buildplate_only = 1 +support_material_contact_distance = 0.2 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 1.22 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 3 +support_material_interface_spacing = 4 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 10 +support_material_speed = 60 +support_material_synchronize_layers = 0 +support_material_threshold = 0 +support_material_with_sheath = 1 +support_material_xy_spacing = 50% +temperature = 215 +thin_walls = 1 +threads = 8 +thumbnails = +toolchange_gcode = +top_fill_pattern = rectilinear +top_infill_extrusion_width = 1.4 +top_solid_infill_speed = 30 +top_solid_layers = 2 +top_solid_min_thickness = 0 +travel_speed = 130 +use_firmware_retraction = 1 +use_relative_e_distances = 0 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 0 +wipe_into_infill = 0 +wipe_into_objects = 0 +wipe_tower = 0 +wipe_tower_bridging = 10 +wipe_tower_no_sparse_layers = 0 +wipe_tower_rotation_angle = 0 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +wiping_volumes_extruders = 70,70 +wiping_volumes_matrix = 0 +xy_size_compensation = 0 +z_offset = 0 diff --git a/prusaslicer_profile/trikarus-bed.svg b/prusaslicer_profile/trikarus-bed.svg new file mode 100644 index 0000000..78d46e8 --- /dev/null +++ b/prusaslicer_profile/trikarus-bed.svg @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +