Code upload

Code upload

error: pathspec 'AOA_TONE_EFIS_SERIAL/AOA_TONE_EFIS_SERIAL.ino' did not match any file(s) known to git

--- AOA_TONE_EFIS_SERIAL/AOA_TONE_EFIS_SERIAL.ino
+++ AOA_TONE_EFIS_SERIAL/AOA_TONE_EFIS_SERIAL.ino
@@ -0,0 +1,321 @@
+////////////////////////////////////////////////////
+////////////////////////////////////////////////////
+// AOA EFIS Serial to audio tone
+// Supports: Dynon EFIS data using a Arduino Due board
+// Ver 1.5
+// Christopher Jones 6/10/2016
+//
+// - Read data in from Serial3 on DUE board. (Dynon is at 115200 baud)
+// - Serial is used for debugging to computer IDE. (115200 baud)
+// - Audio ouput on pin 2
+// - If no serial data is detected audio tone turns off and LED1 is off
+// - MUTE_AUDIO_UNDER_IAS define is used to only activate audio tones if above a given airspeed
+//
+
+#include <DueTimer.h>         // timer lib functions for using DUE timers and callbacks.
+#include <stdint.h>
+#include <Arduino.h>
+
+#include <Gaussian.h>         // gaussian lib used for avg out AOA values.
+#include <LinkedList.h>       // linked list is also required.
+#include <GaussianAverage.h>  // more info at https://github.com/ivanseidel/Gaussian
+
+// Output serial debug infomation. (comment out the following line to turn off serial debug output)
+#define SHOW_SERIAL_DEBUG
+
+// Average out AOA values to give a smoother transtition between values.
+//#define USE_AOA_AVERAGE
+// set how many previous AOA values we store to create avg and help smooth out the data values.
+#define AOA_HISTORY_MAX       5
+
+// set Freq of callback function used to create the pulse tones.
+#define FREQ_OF_FUNCTION      100
+
+// set the sample rate of how often to pull the AOA value from the serial stream.
+// example
+// 1 = sample every AOA value received from the efis.
+// 5 = skip every 5 lines then sample the AOA value.
+#define SERIAL_SAMPLE_RATE    3
+
+// Min airspeed in knots before the audio tone is turned on
+// This is useful because if your on the ground you don't need a beeping in your ear.
+#define MUTE_AUDIO_UNDER_IAS  35
+
+// dynon expected string length
+#define DYNON_SERIAL_LEN      53
+
+// Tone Pulse Per Sec (PPS) for high and low tones.
+#define HIGH_TONE_PPS_MAX     6.5
+#define HIGH_TONE_PPS_MIN     1.5
+#define LOW_TONE_PPS_MAX      8.5
+#define LOW_TONE_PPS_MIN      1.5
+
+
+#define TONE_PIN          2     // TIOA0
+#define PIN_LED1          13    // internal LED for showing AOA status.
+#define PIN_LED2          54    // external LED for showing serial input.
+#define TONE1600hz        1600
+#define TONE400hz         400
+#define PULSE_TONE        1
+#define SOLID_TONE        2
+#define TONE_OFF          3
+
+uint8_t toneState = false;
+unsigned char toneMode = PULSE_TONE;  // current mode of tone.  PULSE_TONE, SOLID_TONE, or TONE_OFF
+boolean highTone = false;             // are we playing high tone or low tone?
+uint32_t toneFreq = 0;                // store current freq of tone playing.
+float pps = 0;                        // store current PPS of tone (used for debuging)
+int liveAOA;                          // realtime AOA value.
+int AOA = 0;                          // avaraged AOA value is stored here.
+int lastAOA = 0;                      // save last AOA value here.
+int ASI = 0;                          // live Air Speed Indicated
+unsigned int cyclesWOSerialData = 0;  // keep track if not serial data is recieved.
+GaussianAverage myAverageAOA = GaussianAverage(AOA_HISTORY_MAX);
+static Tc *chTC = TC0;
+static uint32_t chNo = 0;
+
+// vars for converting AOA scale value to PPS scale value.
+int OldRange,  OldValue;
+float NewRange, NewValue;
+
+char inChar;                    // store single serial input char here.
+#define MAXSIZE 70              // max length of string
+char input[MAXSIZE+1];          // buffer for full serial data input string.
+int inputPos = 0;               // current postion of serial data.
+char tempBuf[50];               // misc char buffer used for debug
+
+void setup() {
+  // put your setup code here, to run once:
+  pinMode(TONE_PIN, OUTPUT);
+  pinMode(PIN_LED1, OUTPUT);
+  pinMode(PIN_LED2, OUTPUT);
+
+  // timer callback is used for turning tone on/off.
+  Timer4.attachInterrupt(tonePlayHandler);
+  Timer4.setFrequency(FREQ_OF_FUNCTION);  // set how often we should run the callback function.
+  Timer4.start();
+
+  Serial.begin(115200);   //Init hardware serial port (ouput to computer for debug)
+  Serial3.begin(115200);  //Init hardware serial port (input from EFIS)
+
+  configureToneTimer();   //setup timer used for tone
+}
+
+// We use our own counter for how often we should pause between tones (pulses per sec PPS)
+int cycleCounter = 0;
+int cycleCounterResetAt = FREQ_OF_FUNCTION;
+void tonePlayHandler(){
+  cycleCounter++;
+  // check if our counter has reach the reset mark.  if so flip the tone on/off and start again.
+  // cycleCounterResetAt is set by the PPS set function.
+  if(cycleCounter >= cycleCounterResetAt) {
+    toneState = toneState ^ 1;  // flip tone state
+    cycleCounter = 0;
+  } else {
+    return;
+  }
+
+  if(toneMode==TONE_OFF) {
+    setFrequencytone(0);  // if tone off skip the rest.
+    return;
+  }
+  if(toneMode==SOLID_TONE) {  // check for a solid tone.
+#ifdef SHOW_SERIAL_DEBUG
+    Serial.println("SOLID TONE");
+#endif
+    setFrequencytone(TONE400hz);
+    return; // skip the rest
+  }
+
+  // cylce tone on/off depending on toneState which is flipped in code above.
+  if(toneState) {
+     digitalWrite(PIN_LED1, digitalRead(PIN_LED1)^1);  // cycle led on/off
+     //sprintf(tempBuf, "handler() AOA:%i ASI:%i tone: %i PPS:%f handlerFreq: %i",AOA,ASI,toneFreq,pps, handlerFreq);
+     //Serial.println(tempBuf);
+     if(highTone)
+        setFrequencytone(TONE1600hz);
+     else
+        setFrequencytone(TONE400hz);
+
+  } else {
+    setFrequencytone(0);
+  }
+}
+
+void checkAOA_Dynon() {
+  if(ASI <= MUTE_AUDIO_UNDER_IAS) {
+#ifdef SHOW_SERIAL_DEBUG
+  // show audio muted and debug info.
+  sprintf(tempBuf, "AUDIO MUTED: Airspeed to low. Min:%i ASI:%i",MUTE_AUDIO_UNDER_IAS, ASI);
+  Serial.println(tempBuf);
+#endif
+  }
+
+  if(lastAOA == AOA) {
+    return; // skip this if the AOA value has not changed.
+  }
+
+  // check AOA value and set tone and pauses between tones according to
+  if(AOA >= 90) {
+    // play 20 pps 1600hz tone
+    highTone = true;
+    setPPSTone(20);
+    toneMode = PULSE_TONE;
+  } else if(AOA >= 70) {
+    // play 1600hz tone at Pulse Rate 1.5 PPS to 6.2 PPS (depending on AOA value)
+    highTone = true;
+    OldValue = AOA-69;
+    toneMode = PULSE_TONE;
+    // scale number using this. http://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio
+    OldRange = 20 - 1;  //(OldMax - OldMin)
+    NewRange = HIGH_TONE_PPS_MAX - HIGH_TONE_PPS_MIN; // (NewMax - NewMin)
+    NewValue = (((OldValue - 1) * NewRange) / OldRange) + HIGH_TONE_PPS_MIN; //(((OldValue - OldMin) * NewRange) / OldRange) + NewMin
+    setPPSTone(NewValue);
+  } else if(AOA >= 60) {
+    // play a steady 400hz tone
+    highTone = false;
+    toneMode = SOLID_TONE;
+    //setFrequencytone(TONE400hz);
+  } else if(AOA > 20) {
+    toneMode = PULSE_TONE;
+    highTone = false;
+    // play 400hz tone at Pulse Rate 1.5 PPS to 8.2 PPS (depending on AOA value)
+    // scale number using this. http://stackoverflow.com/questions/929103/convert-a-number-range-to-another-range-maintaining-ratio
+    OldValue = AOA-20;
+    OldRange = 40 - 1;  //(OldMax - OldMin)
+    NewRange = LOW_TONE_PPS_MAX - LOW_TONE_PPS_MIN; // (NewMax - NewMin)
+    NewValue = (((OldValue - 1) * NewRange) / OldRange) + LOW_TONE_PPS_MAX; //(((OldValue - OldMin) * NewRange) / OldRange) + NewMin
+    setPPSTone(NewValue);
+  } else {
+    toneMode = TONE_OFF;
+  }
+
+  lastAOA = AOA;
+#ifdef SHOW_SERIAL_DEBUG
+  // show serial debug info.
+  sprintf(tempBuf, "AOA:%i Live:%i ASI:%i PPS:%f cycleCounterResetAt: %i",AOA, liveAOA, ASI,pps, cycleCounterResetAt);
+  Serial.println(tempBuf);
+#endif
+}
+
+void setPPSTone(float newPPS) {
+  // set PPS by setting cycleCounterResetAt which is used in the tonePlayHandler()
+  cycleCounterResetAt = (1/(newPPS*1.5)) * FREQ_OF_FUNCTION;
+  pps = newPPS;  // store pps for debug purposes.
+}
+
+// counter for how often to cycle led and sample AOA from serial data.
+int LedCountDown = SERIAL_SAMPLE_RATE;
+// main loop of app
+void loop() {
+      // check for serial in from efis.
+      while(Serial3.available()) {
+        inChar = (char)Serial3.read();
+        input[inputPos]=inChar;
+        inputPos++;
+        cyclesWOSerialData = 0;
+        if (inChar == '\n' && inputPos == DYNON_SERIAL_LEN) {  // is EOL?
+          // get AOA from dynon efis string.  details of format can be found from dynon pdf manual.
+          tempBuf[0] = input[39]; //
+          tempBuf[1] = input[40]; //
+          tempBuf[2] = '\0'; //term string
+          liveAOA = strtol(tempBuf, NULL, 10); //convert to int
+
+          // get AOA value
+#ifdef USE_AOA_AVERAGE
+          myAverageAOA += liveAOA;            // store and calcute the mean average AOA from previous values.
+          AOA = myAverageAOA.process().mean;
+#else
+          AOA = liveAOA;  // else just use the live AOA value.
+#endif
+
+          // get ASI (4 digits) but we only want the first 3 because its in meters per second.
+          tempBuf[0] = input[20]; //
+          tempBuf[1] = input[21]; //
+          tempBuf[2] = input[22]; //
+          tempBuf[3] = '\0'; //
+          ASI = strtol(tempBuf, NULL, 10) * 1.943; //convert to int (and from m/s to knots)
+
+          // check how often we want to sample the serial data.
+          LedCountDown --;
+          if(LedCountDown<1) {
+             digitalWrite(PIN_LED2, digitalRead(PIN_LED2)^1);  // cycle serial RX led on/off
+             LedCountDown = SERIAL_SAMPLE_RATE;
+             checkAOA_Dynon();  // check AOA data from dynon and store result into AOA var.
+             // TODO: check if we have a different EFIS and create seperate parse function.
+          }
+          inputPos = 0;  // reset postion to start of buffer string for next round.
+        }
+        // else safety check, if we went past the number of expected chars then reset to 0.
+        if(inputPos>DYNON_SERIAL_LEN) inputPos = 0;
+
+      }
+
+      // check if no serial has been sent in a while.
+      cyclesWOSerialData++;
+      if(cyclesWOSerialData > 55500) {
+        toneMode = TONE_OFF;        // stop tone
+        cyclesWOSerialData == 0;
+        digitalWrite(PIN_LED2, 0);  // no EFIS serial data so turn off led.
+#ifdef SHOW_SERIAL_DEBUG
+        Serial.println("NO DATA");
+#endif
+      }
+}
+
+
+
+void configureToneTimer() {
+  // Configure TONE_PIN pin as timer output
+  // pmc_enable_periph_clk( ID_PIOB ) ;
+  int result = PIO_Configure( PIOB,
+            PIO_PERIPH_B,
+            PIO_PB25B_TIOA0,
+            PIO_DEFAULT);
+
+  pmc_set_writeprotect(false);
+  pmc_enable_periph_clk(ID_TC0);
+ TC_Configure(chTC, chNo,
+         TC_CMR_TCCLKS_TIMER_CLOCK4 |
+         TC_CMR_WAVE |         // Waveform mode
+         TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC
+         TC_CMR_ACPA_SET |     // RA compare sets TIOA
+         TC_CMR_ACPC_CLEAR );  // RC compare clears TIOA
+
+  chTC->TC_CHANNEL[chNo].TC_IER=TC_IER_CPCS;  // RC compare interrupt
+  chTC->TC_CHANNEL[chNo].TC_IDR=~TC_IER_CPCS;
+  //NVIC_EnableIRQ(TC0_IRQn);
+}
+
+void setFrequencytone(uint32_t frequency)
+{
+
+  if(frequency < 20 || frequency > 20000) {
+    //Serial.print("cancel tone: ");Serial.println(frequency);
+    TC_Stop(chTC, chNo);
+    toneFreq = frequency;
+    return;
+  }
+
+  if(toneFreq == frequency) {
+    // if the new frequency is the same as the current freq then don't do anything.
+    return;
+  }
+
+  const uint32_t rc = VARIANT_MCK / 128 / frequency;
+  const uint32_t ra = rc >> 2; // 50% duty cycle
+  const uint32_t rb = ra >> 2; // 20% duty cycle
+
+  //Serial.print("rc=");Serial.println(rc);
+  //Serial.print("ra=");Serial.println(ra);
+  //Serial.print("rb=");Serial.println(rb);
+
+  TC_Stop(chTC, chNo);
+  TC_SetRC(chTC, chNo, rc);    // set frequency
+  TC_SetRA(chTC, chNo, ra);
+  TC_SetRB(chTC, chNo, rb);
+  TC_Start(chTC, chNo);
+  toneFreq = frequency;
+
+}
+


Adding a basic LED blink sketch.

Adding a basic LED blink sketch.

error: pathspec 'LED_Blink/LED_Blink.ino' did not match any file(s) known to git

--- LED_Blink/LED_Blink.ino
+++ LED_Blink/LED_Blink.ino
@@ -0,0 +1,14 @@
+void setup(void)
+{
+  // Initialize the digital pin 13 as an output.
+  pinMode(13, OUTPUT);
+}
+
+
+void loop(void)
+{
+  digitalWrite(13, HIGH);   // set the LED on
+  delay(1000);              // wait for a second
+  digitalWrite(13, LOW);    // set the LED off
+  delay(1000);              // wait for a second
+}


Added photo resistor.

Added photo resistor.

error: pathspec '5.Photo' did not match any file(s) known to git
error: pathspec 'Resistor.ino' did not match any file(s) known to git


Create dg_tinkerkit_temperatur_sensor.ino

error: pathspec 'dg_tinkerkit_temperatur_sensor.ino' did not match any file(s) known to git

--- dg_tinkerkit_temperatur_sensor.ino
+++ dg_tinkerkit_temperatur_sensor.ino
@@ -0,0 +1,44 @@
+/*
+Thermistor
+http://www.tinkerkit.com/thermistor/
+The TinkerKit Thermistor Module [T00020] is hooked up on I0.
+Three values are displayed on the Serial Monitor every second:
+- the value between 0 and 1023 that represent the Analog Input reading
+- the temperature expressed in Celsius degrees
+- the temperature expressed in Fahrenheit dedegrees
+created 29 Nov 2011
+by Federico Vanzati
+modified in Jun 2013
+by Matteo Loglio<http://matlo.me>
+This example code is in the public domain.
+*/
+
+// include the TinkerKit library
+#include <TinkerKit.h>
+
+TKThermistor therm(I0);       // creating the object 'therm' that belongs to the 'TKThermistor' class
+                              // and giving the value to the desired output pin
+
+float C, F;          // temperature readings are returned in float format
+
+void setup()
+{
+  // initialize serial communications at 9600 bps
+  Serial.begin(9600);
+}
+
+void loop()
+{
+  C = therm.readCelsius();      // Reading the temperature in Celsius degrees and store in the C variable
+  F = therm.readFahrenheit();   // Reading the temperature in Fahrenheit degrees and store in the F variable
+
+  // Print the collected data in a row on the Serial Monitor
+  Serial.print("Analog reading: "); // Reading the analog value from the thermistor
+  Serial.print(therm.read());
+  Serial.print("\tC: ");
+  Serial.print(C);
+  Serial.print("\tF: ");
+  Serial.println(F);
+
+  delay(1000);                // Wait one second before get another temperature reading
+}


Create Elcano_C2_LowLevel_RC

Create Elcano_C2_LowLevel_RC

Added RC-compatible duplicate of Elcano_C2_LowLevel.

error: pathspec 'Elcano_C2_LowLevel/Elcano_C2_LowLevel_RC.ino' did not match any file(s) known to git

--- Elcano_C2_LowLevel/Elcano_C2_LowLevel_RC.ino
+++ Elcano_C2_LowLevel/Elcano_C2_LowLevel_RC.ino
@@ -0,0 +1,1251 @@
+#include <SPI.h>
+#include <Elcano_Serial.h>
+//#include <SoftwareSerial.h>
+
+// Read in VEHICLE_NUMBER, which specifies which trike is being used.
+// Also provides definitions specific to that trike, under
+// VEHICLE_NUMBER conditionals. See README.txt for how to use and
+// modify Settings.h.
+#include <Settings.h>
+
+// On Mega, TX must use d10-15, d50-53, or a8-a15 (62-69)
+const int softwareTx = 10;  // to 7 segment LED display
+const int softwareRx = 7;   // not used
+//SoftwareSerial s7s(softwareRx, softwareTx);
+#define s7s Serial3
+
+#define LOOP_TIME_MS 400
+#define ERROR_HISTORY 20 //number of errors to accumulate
+
+// Distance the wheel outer circumference moves during one phase cycle.
+const float WHEEL_PHASE_DISTANCE_MM = WHEEL_DIAMETER_MM * PI / MOTOR_POLE_PAIRS;
+// Conversion factor from 1 / (motor phase cycle time in microseconds) to speed
+// in km/h:
+// There are MOTOR_POLE_PAIRS phase cycles per wheel rotation, so the time for
+// one wheel rotation (based on a single phase cycle) is the duration of that
+// phase cycle times the number of pole pairs.  Also, we want km / h rather
+// than mm / usec.  Units conversion:
+// speed measured in km / hr
+// = (speed measured in mm / usec) * (km / 10^6 mm) * (3600 * 10^6 usec / hr)
+// = (speed in mm / usec) * 3600
+// = (wheel phase distance in mm / motor feedback cycle time in usec) * 3600
+// = (wheel phase distance in mm * 3600) / (motor feedback cycle time in usec)
+// The first part is a constant for a given motor and wheel diameter:
+const float HUB_PHASE_TO_KMPH = WHEEL_PHASE_DISTANCE_MM * 3600;
+// For a motor with 23 pole pairs and a 500 mm diameter drive wheel, this is
+// about 245863.8.
+
+/*================ReadTurnAngle ================*/
+// Value measured at analog input A2 from right steering column when wheels pointed straight ahead.
+// An analog voltage can be 0 to 5V, which correspond to angles from 0 to 360 degrees.
+// Analog input reads this as a value form 0 to 1024.
+// We may want to mount the sensors so that straight is close to 500.
+// This number is not critical, since actual wheel turn range is much less than 360
+int RightStraight_A2 = 750; // Original value 181
+// Value measured at analog input A3 from left steering column when wheels pointed straight ahead.
+int LeftStraight_A3  = 914; // Original value 181
+// Calibration constants
+// Aangle (degrees) = (Value - RightStraight_A2) * RIGHT_DEGx1000pCOUNT / 1000
+#define RIGHT_DEGx1000pCOUNT  333
+#define LEFT_DEGx1000pCOUNT  333
+// A correct sensor will produce a reading between these values
+int Left_Min_Count = 850; // Real values are in setup().
+int Left_Max_Count = 980;
+int Right_Min_Count = 698;
+int Right_Max_Count = 808;
+
+// Channel order differs for different vehicles
+// Indices for information stored in arrays RC_rise, RC_elapsed, local_results,...
+// Right joystick left/right to D21
+#define RC_TURN 1
+#define RC_AUTO 2
+// Right joystick up/down to D19
+#define RC_GO   3
+// Red (Gear) Switch to D18
+#define RC_ESTP 4
+// Left joystick left/right to D20
+#define RC_RDR  5
+// Left joystick up/down to D2
+#define RC_RVS  6
+// There are six channels, but we are limited to five interrupts
+#define NUMBER_CHANNELS 6
+
+// RC_rise contains the time value collected in the rising edge interrupts.
+// RC_elapsed contains the width of the pulse. The rise and fall interrupts
+// should alternate.
+#define ProcessFallOfINT(Index)  RC_elapsed[Index]=(micros()-RC_rise[Index])
+#define ProcessRiseOfINT(Index) RC_rise[Index]=micros()
+
+
+const int SelectCD = 49; // Select IC 3 DAC (channels C and D)
+const int SelectAB = 53; // Select IC 2 DAC (channels A and B)
+
+const unsigned long INVALID_DATA = 0;
+volatile int rc_index = 0;
+volatile unsigned long RC_rise[7];
+volatile unsigned long RC_elapsed[7];
+volatile boolean synced = false;
+volatile unsigned long last_fallingedge_time = 4294967295; // max long
+volatile int RC_Done[7] = {0,0,0,0,0,0,0};
+
+// interrupt number handling a function depends on the RC controller.
+
+#ifdef RC_SPEKTRUM
+const int IRPT_RVS  = 0; // D2  = Int 0
+const int IRPT_TURN = 2; // D21 = Int 2
+const int IRPT_GO   = 3; // D20 = Int 3
+const int IRPT_RDR  = 5; // D18 = Int 5
+// RDR (rudder) is not used. Instead, use this interrupt for the motor phase feedback, which gives speed.
+const int IRPT_ESTOP = 4; // D19 = Int 4
+//RC input values - pulse widths in microseconds
+const int DEAD_ZONE = 75;
+const int MIDDLE = 1500;  // was 1322; new stable value = 1510
+// extremes of RC pulse width
+const int MIN_RC = 1090;  // was 911;
+const int MAX_RC = 1930; // was 1730;
+#endif
+
+#ifdef RC_HITEC
+const int IRPT_RVS = 0;   // D2  = Int 0
+const int IRPT_TURN = 2;  // D21 = Int 2
+const int IRPT_GO = 3;   //  D20 = Int 3
+// RDR (rudder) is not used. Instead, use this interrupt for the motor phase
+// feedback, which gives speed.
+const int IRPT_RDR = 5;   // D18 = Int 5
+const int IRPT_ESTOP = 4; // D19 = Int 4
+//RC input values - pulse widths in microseconds
+const int DEAD_ZONE = 75;
+const int MIDDLE = 1380;
+// extremes of RC pulse width
+const int MIN_RC = 960;
+const int MAX_RC = 1800;
+#endif
+//  D3 = Int 1  Wheel Click
+
+// Currently different interrupts are used for the motor phase feedback.
+#if (VEHICLE_NUMBER == 1)
+#define RC_MOTOR_FEEDBACK RC_RVS
+const int IRPT_MOTOR_FEEDBACK = IRPT_RVS;
+#endif
+#if (VEHICLE_NUMBER == 2)
+#define RC_MOTOR_FEEDBACK RC_RDR
+const int IRPT_MOTOR_FEEDBACK = IRPT_RDR;
+#endif
+
+long speed_errors[ERROR_HISTORY];
+long old_turn_degx1000;
+unsigned long calibrationTime_ms;
+unsigned long stoppedTime_ms;
+unsigned long straightTime_ms;
+int  throttle_control = MIN_ACC_OUT;
+int  brake_control = MAX_BRAKE_OUT;
+int  steer_control = STRAIGHT_TURN_OUT;
+float Odometer_m = 0;
+float HubSpeed_kmPh;
+const float  HubSpeed2kmPh = 13000000;
+const unsigned long HubAtZero = 1159448;
+//==========================================================================================
+void ISR_TURN_rise() {
+  noInterrupts();
+  ProcessRiseOfINT(RC_TURN);
+  attachInterrupt(IRPT_TURN, ISR_TURN_fall, FALLING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+// RDR (rudder) is currently not used.
+void ISR_RDR_rise() {
+  noInterrupts();
+  unsigned long old_phase_rise = RC_rise[RC_RDR];
+  ProcessRiseOfINT(RC_RDR);
+  RC_elapsed[RC_RDR] = RC_rise[RC_RDR] - old_phase_rise;
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_GO_rise() {
+  noInterrupts();
+  ProcessRiseOfINT(RC_GO);
+  attachInterrupt(IRPT_GO, ISR_GO_fall, FALLING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_ESTOP_rise() {
+  noInterrupts();
+  ProcessRiseOfINT(RC_ESTP);
+  attachInterrupt(IRPT_ESTOP, ISR_ESTOP_fall, FALLING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_RVS_rise() {
+  noInterrupts();
+  ProcessRiseOfINT(RC_RVS);
+  attachInterrupt(IRPT_RVS, ISR_RVS_fall, FALLING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_TURN_fall() {
+  noInterrupts();
+  ProcessFallOfINT(RC_TURN);
+  RC_Done[RC_TURN] = 1;
+  attachInterrupt(IRPT_TURN, ISR_TURN_rise, RISING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_GO_fall() {
+  noInterrupts();
+  ProcessFallOfINT(RC_GO);
+  RC_Done[RC_GO] = 1;
+  attachInterrupt(IRPT_GO, ISR_GO_rise, RISING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_ESTOP_fall() {
+  noInterrupts();
+  ProcessFallOfINT(RC_ESTP);
+  RC_Done[RC_ESTP] = 1;
+//  if (RC_elapsed[RC_ESTP] > MIDDLE)
+//     E_Stop();
+  attachInterrupt(IRPT_ESTOP, ISR_ESTOP_rise, RISING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+void ISR_RVS_fall() {
+  noInterrupts();
+  ProcessFallOfINT(RC_RVS);
+  RC_Done[RC_RVS] = 1;
+  attachInterrupt(IRPT_RVS, ISR_RVS_rise, RISING);
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+// An e-bike hub motor is powered by giving it 3 phase power. This is supplied
+// by the motor controller. The controller needs feeback from the hub.  It
+// receives three feedback signals from the motor, one for each phase.  These
+// are the *actual* phase rotation of the motor, not the phases supplied by the
+// controller, which differ from what the motor is currently doing whenever the
+// controller is attempting to speed up or slow down or change direction of the
+// motor. The motor phase feedback pulse rate is an integer multiple of wheel
+// rotation rate. The factor is the number of pole pairs in the motor. Note
+// that the controller has no idea how many pole pairs the motor has, so it
+// only controls the phase rate, not the actual rotation rate.  It is "someone
+// else's problem" to limit the actual rotation rate or speed. The feedback
+// signals are 5V square waves.  They have some noise -- spikes of several
+// volts, which exceeds the maximum voltage allowed for Arduino inputs, which
+// is 5.5V.  The signal is cleaned up by an RC low pass filter with R = 1K,
+// C = 100 nF.
+void ISR_MOTOR_FEEDBACK_rise() {
+  noInterrupts();
+  // This differs from the other interrupt routines since we need the *cycle*
+  // duration, not the width of the high pulse.  So here, we get the time from
+  // the previous rising edge to the current rising edge.  Q: Are we properly
+  // ignoring the first value from all of these interval computations?
+  unsigned long old_phase_rise = RC_rise[RC_MOTOR_FEEDBACK];
+  ProcessRiseOfINT(RC_MOTOR_FEEDBACK);
+  RC_elapsed[RC_MOTOR_FEEDBACK] = RC_rise[RC_MOTOR_FEEDBACK] - old_phase_rise;
+  interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+//----------------------------------------------------------------------------
+void setup()
+{ //Set up pins
+      pinMode(BRAKE_OUT_PIN, OUTPUT);
+      pinMode(STEER_OUT_PIN, OUTPUT);
+      // SPI: set the slaveSelectPin as an output:
+      pinMode (SelectAB, OUTPUT);
+      pinMode (SelectCD, OUTPUT);
+      pinMode (10, OUTPUT);
+      SPI.setDataMode( SPI_MODE0);
+      SPI.setBitOrder( MSBFIRST);
+      // initialize SPI:
+      // The following line should not be neccessary. It uses a system library.
+      // Note PRR0 and PRR1 are defined for the Mega 2560 but smaller boards have just PRR.
+      PRR0 &= ~4; // turn off PRR0.PRSPI bit so power isn't off
+      SPI.begin();
+      for (int channel = 0; channel < 4; channel++)
+      DAC_Write (channel, 0); // reset did not clear previous states
+      // put vehicle in initial state
+      steer(STRAIGHT_TURN_OUT);
+      brake(MAX_BRAKE_OUT);
+      moveVehicle(MIN_ACC_OUT);
+      setup7seg();    // Initialize 7 segment display for speedometer
+      delay(500);   // let vehicle stabilize
+
+      Serial.begin(9600);
+      rc_index = 0;
+      for (int i = 0; i < 8; i++)
+      {
+          RC_rise[i] = INVALID_DATA;
+          RC_elapsed[i] = INVALID_DATA;
+      }
+      for (int i = 0; i < ERROR_HISTORY; i++)
+      {
+          speed_errors[i] = 0;
+      }
+      setupWheelRev(); // WheelRev4 addition
+      CalibrateTurnAngle(32, 20);
+      calibrationTime_ms = millis();
+      attachInterrupt(IRPT_TURN,  ISR_TURN_rise,  RISING);
+      //attachInterrupt(IRPT_RDR,   ISR_RDR_rise,   RISING);
+      attachInterrupt(IRPT_GO,    ISR_GO_rise,    RISING);
+      attachInterrupt(IRPT_ESTOP, ISR_ESTOP_rise, RISING);
+      //attachInterrupt(IRPT_RVS,   ISR_RVS_rise,   RISING);
+      attachInterrupt(IRPT_MOTOR_FEEDBACK, ISR_MOTOR_FEEDBACK_rise, RISING);
+      //Print7headers(false);
+      PrintHeaders();
+}
+/*---------------------------------------------------------------------------------------*/
+void loop() {
+    SerialData Results;
+
+    // Save start time for performance report.
+    unsigned long startTime = micros();
+    // Get the next loop start time.
+    unsigned long nextTime = startTime + LOOP_TIME_MS;
+
+    startCapturingRCState();
+
+    unsigned long local_results[7];
+//  PrintDone();
+
+  // ToDo: Refactor this to not have a spinloop.
+  // We get three signals from the RC controller in turn, one each for RC_ESTP,
+  // RC_GO, and RC_TURN. The three signals are sent separately. We get triples of
+  // new RC values at about 30Hz, which is faster than the loop runs. It doesn't
+  // really matter if we are using exactly the latest value, as there isn't much
+  // change between one an the next, except for ESTP, and if we wait til the next
+  // loop pass for that, it should be ok. So just have the interrupt routines read
+  // the RC information and store it, then the loop can use the latest values.
+  // It should check that it has received any values, since the Arduino may be
+  // started before the RC controller is turned on.
+  while (micros() < nextTime &&
+    ~((RC_Done[RC_ESTP] == 1) && (RC_Done[RC_GO] == 1) && (RC_Done[RC_TURN] == 1) ))
+    ;  //wait
+
+    // got data;
+    for (int i = 0; i < 8; i++)
+        local_results[i] = RC_elapsed[i];
+    //Print7(false, local_results);
+    processRC(local_results);
+//    Print7( true, local_results);
+
+    Results.Clear();
+    Results.kind = MSG_SENSOR;
+    Results.angle_deg = TurnAngle_degx10() / 10;
+    show_speed (&Results);
+
+    // Report how long the loop took.
+    unsigned long endTime = micros();
+    unsigned long elapsedTime = endTime - startTime;
+    //Serial.print("loop elapsed time = ");
+    //Serial.println(elapsedTime);
+
+    LogData(local_results, &Results);  // data for spreadsheet
+
+    calibrationTime_ms += LOOP_TIME_MS;
+    straightTime_ms = (steer_control == STRAIGHT_TURN_OUT)? straightTime_ms + LOOP_TIME_MS: 0;
+    stoppedTime_ms = (throttle_control == MIN_ACC_OUT)? stoppedTime_ms + LOOP_TIME_MS: 0;
+    if (calibrationTime_ms > 40000 && straightTime_ms > 3000 && stoppedTime_ms > 3000)
+    {
+//       int oldBrake = brake_control;
+//       brake(MAX_BRAKE_OUT);  // put on brakes
+         CalibrateTurnAngle(16, 10);  // WARNING: No response to controls while calibrating
+//       brake(oldBrake);       // restore brake state
+         calibrationTime_ms = 0;
+    }
+
+    // Did we spend long enough in the loop that we should immediately
+    // start the next pass?
+    if (nextTime > endTime) {
+        // No, pause til the next loop start time.
+        delay(nextTime - endTime);
+    } else {
+        // Yes, we overran the expected loop interval. Extend the time.
+        nextTime = endTime + 1000 * LOOP_TIME_MS;
+    }
+}
+/*---------------------------------------------------------------------------------------*/
+void PrintDone()
+{
+  Serial.print("RC_Done values: RC_ESTP "); Serial.print(RC_Done[RC_ESTP]);
+  Serial.print(" RC_GO "); Serial.print(RC_Done[RC_GO]);
+  Serial.print(" RC_TURN "); Serial.print(RC_Done[RC_TURN]);
+  //Serial.print(" RC_RVS "); Serial.print(RC_Done[RC_RVS]);
+  // Not currently using RC_RVS, and it is always zero.
+
+}
+/*---------------------------------------------------------------------------------------*/
+void Print7headers (bool processed)
+{
+    processed? Serial.print("processed data \t") : Serial.print("received data \t");
+ #ifdef RC_SPEKTRUM
+    Serial.print("Time\t");
+    Serial.print("TURN\t");
+    Serial.print("AUTO\t");
+    Serial.print("GO\t");
+    Serial.print("Rudder\t");
+    Serial.print("E-Stop\t");
+    Serial.println("Reverse\t");
+#endif
+
+#ifdef RC_HITEC
+    Serial.print("Time\t");
+    Serial.print("TURN\t");
+    Serial.print("AUTO\t");
+    Serial.print("GO\t");
+    Serial.print("E-Stop\t");
+    Serial.print("Rudder\t");
+    Serial.println("Reverse\t");
+#endif
+}
+/*---------------------------------------------------------------------------------------*/
+void Print7 (bool processed, unsigned long results[7])
+{
+    processed? Serial.print("processed data \t") : Serial.print("received data \t");
+    Serial.print(results[0]); Serial.print("\t");
+    Serial.print(results[1]); Serial.print("\t");
+    Serial.print(results[2]); Serial.print("\t");
+    Serial.print(results[3]); Serial.print("\t");
+    Serial.print(results[4]); Serial.print("\t");
+    Serial.print(results[5]); Serial.print("\t");
+    Serial.println(results[6]);
+}
+/*---------------------------------------------------------------------------------------*/
+void LogData(unsigned long commands[7], SerialData *sensors)  // data for spreadsheet
+{
+     /*Serial.print("(ms) Time\t");
+     Serial.print("(cm/s) Speed\t");
+     Serial.print("(km/h) Speed\t");
+     Serial.print("(km/h) Hub Speed\t");
+     Serial.print("(deg) Angle\t");
+     Serial.print("Right\t");
+     Serial.print("Left\t");
+     Serial.print("Throttle\t");
+     Serial.print("Brake\t");
+     Serial.print("Steer\t");
+     Serial.println("(m) Distance");*/
+     Serial.print(millis()); Serial.print("\t");                        //(ms) Time
+     Serial.print(sensors->speed_cmPs); Serial.print("\t");             //(cm/s) Speed
+     Serial.print(sensors->speed_cmPs*36.0/1000.); Serial.print("\t");  //(km/h) Speed
+     Serial.print(HubSpeed_kmPh); Serial.print("\t");                   //(km/h) Hub Speed
+     Serial.print(sensors->angle_deg); Serial.print("\t");              //(deg) Angle
+     int right = analogRead(A3);
+     int left = analogRead(A2);
+     Serial.print(right); Serial.print("\t");                           //Right turn sensor
+     Serial.print(left); Serial.print("\t");                            //Left turn sensor
+     Serial.print(throttle_control); Serial.print("\t");                //Throttle
+     Serial.print(brake_control); Serial.print("\t");                   //Brake
+     Serial.print(steer_control); Serial.print("\t");                   //Steer
+     Serial.println(Odometer_m);                                        //(m) Distance
+//     Print7 (true, commands);
+}
+/*---------------------------------------------------------------------------------------*/
+void PrintHeaders (void)
+{
+    Serial.print("(ms) Time\t");
+    Serial.print("(cm/s) Speed\t");
+    Serial.print("(km/h) Speed\t");
+    Serial.print("(km/h) Hub Speed\t");
+    Serial.print("(deg) Angle\t");
+    Serial.print("Right\t");
+    Serial.print("Left\t");
+    Serial.print("Throttle\t");
+    Serial.print("Brake\t");
+    Serial.print("Steer\t");
+    Serial.println("(m) Distance");
+}
+/*---------------------------------------------------------------------------------------*/
+void startCapturingRCState()
+{
+  for (int i = 1; i < 7; i++) {
+    RC_Done[i] = 0;
+  }
+}
+/*---------------------------------------------------------------------------------------*/
+// processRC modified by TCF  9/17/15
+void processRC (unsigned long *results)
+{
+    // 1st pulse is aileron (position 5 on receiver; controlled by Right left/right joystick on transmitter)
+    //     used for Steering
+    int aileron = results[RC_TURN];
+//    Serial.print("\tTurn input "); Serial.print(aileron);
+    results[RC_TURN] = convertTurn(aileron);
+//    Serial.print("\tTurn Cmd "); Serial.println(results[RC_TURN]);
+    /* 2nd pulse is aux (position 1 on receiver; controlled by flap/gyro toggle on transmitter)
+       will be used for selecting remote control or autonomous control. */
+//    Serial.print("In processRC, received results[RC_AUTO] = "); Serial.println(results[RC_AUTO]);
+    if (NUMBER_CHANNELS > 5)
+        results[RC_AUTO] = (results[RC_AUTO] > MIDDLE? HIGH: LOW);
+//    Serial.print("processed results[RC_AUTO] = "); Serial.println(results[RC_AUTO]);
+
+    /* 4th pulse is gear (position 2 on receiver; controlled by gear/mode toggle on transmitter)
+    will be used for emergency stop. D38 */
+    results[RC_ESTP] = (results[RC_ESTP] > MIDDLE? HIGH: LOW);
+
+    if (results[RC_ESTP] == HIGH)
+    {
+        E_Stop();  // already done at interrupt level
+        if ((results[RC_AUTO] == LOW)  && (NUMBER_CHANNELS > 5)) // under RC control
+            steer(results[RC_TURN]);
+        Serial.println("Exiting processRC due to E-stop.");
+        return;
+    }
+
+
+    if ((results[RC_AUTO] == HIGH)  && (NUMBER_CHANNELS > 5))
+    {
+        Serial.println("Exiting processRC as not under RC control.");
+        return;  // not under RC control
+    } else {
+//        Serial.println("Continuing processRC as under RC control.");
+    }
+    /*  6th pulse is marked throttle (position 6 on receiver; controlled by Left up/down joystick on transmitter).
+    It will be used for shifting from Drive to Reverse . D40
+    */
+    results[RC_RVS] = (results[RC_RVS] > MIDDLE? HIGH: LOW);
+
+// TO DO: Select Forward / reverse based on results[RC_RVS]
+
+    /*   3rd pulse is elevator (position 4 on receiver; controlled by Right up/down.
+       will be used for throttle/brake: RC_Throttle
+    */
+    // Braking or Throttle
+    if (liveBrake(results[RC_GO]))
+         convertBrake (&(results[RC_GO]));
+
+    //Accelerating
+    else if(liveThrottle(results[RC_GO]))
+    {
+        results[RC_GO] = convertThrottle(results[RC_GO]);
+        moveVehicle(results[RC_GO]);
+    }
+    else
+        moveVehicle(MIN_ACC_OUT);
+
+    steer(results[RC_TURN]);
+
+    /* 5th pulse is rudder (position 3 on receiver; controlled by Left left/right joystick on transmitter)
+    Not used */
+//    results[RC_RDR] = (results[RC_RDR] > MIDDLE? HIGH: LOW);  // could be analog
+    Serial.println(results[RC_MOTOR_FEEDBACK]);
+    if (results[RC_MOTOR_FEEDBACK] >= HubAtZero)
+        HubSpeed_kmPh = 0;
+    else
+        HubSpeed_kmPh = HubSpeed2kmPh / results[RC_MOTOR_FEEDBACK];
+
+//  Serial.println("");  // New line
+
+}
+/*---------------------------------------------------------------------------------------*/
+//Converts RC values to corresponding values for the PWM output
+int convertTurn(int input)
+{
+     long int steerRange, rcRange;
+     long output;
+     int trueOut;
+//     Serial.print("\tconvertTurn: input = \t"); Serial.print(input);
+     //  Check if Input is in steer dead zone
+     if ((input <= MIDDLE + DEAD_ZONE) && (input >= MIDDLE - DEAD_ZONE))
+       return STRAIGHT_TURN_OUT;
+       // On SPEKTRUM, MIN_RC = 1 msec = stick right; MAX_RC = 2 msec = stick left
+       // On HI_TEC, MIN_RC = 1 msec = stick left; MAX_RC = 2 msec = stick right
+      // LEFT_TURN_OUT > RIGHT_TURN_OUT
+#ifdef RC_HITEC
+  input = MAX_RC - (input - MIN_RC);
+#endif
+
+      if (input > MIDDLE + DEAD_ZONE)
+      {  // left turn
+         steerRange = LEFT_TURN_OUT - STRAIGHT_TURN_OUT;
+         rcRange = MAX_RC - (MIDDLE + DEAD_ZONE);
+        input = input - MIDDLE - DEAD_ZONE; // originally input = middle + dead_zone
+        output = STRAIGHT_TURN_OUT + input * steerRange / rcRange;
+        //set max and min values if out of range
+        trueOut = (int)output;
+        if(trueOut > LEFT_TURN_OUT)
+            trueOut = LEFT_TURN_OUT;
+        if(trueOut < STRAIGHT_TURN_OUT)
+            trueOut = STRAIGHT_TURN_OUT;
+        return trueOut;
+    }
+      if (input < MIDDLE - DEAD_ZONE)
+      {  // right turn
+         steerRange = STRAIGHT_TURN_OUT - RIGHT_TURN_OUT;
+         rcRange = MIDDLE - DEAD_ZONE - MIN_RC;
+        input = input - DEAD_ZONE - MIDDLE;  // input is negative
+        output = STRAIGHT_TURN_OUT + input * steerRange / rcRange;
+        //set max and min values if out of range
+        trueOut = (int)output;
+        if(trueOut < RIGHT_TURN_OUT)
+            trueOut = RIGHT_TURN_OUT;
+        if(trueOut > STRAIGHT_TURN_OUT)
+            trueOut = STRAIGHT_TURN_OUT;
+        return trueOut;
+    }
+}
+/*---------------------------------------------------------------------------------------*/
+int convertThrottle(int input)
+{
+      //full throttle = 227, min = 40
+      const int dacRange = MAX_ACC_OUT - MIN_ACC_OUT;
+      const int rcRange = MAX_RC - (MIDDLE + DEAD_ZONE);
+      input -= (MIDDLE + DEAD_ZONE);
+      double output = (double)input /(double)rcRange;
+      output *= dacRange;
+      output += MIN_ACC_OUT;
+      //set max values if out of range
+      int trueOut = (int)output;
+      if(trueOut > MAX_ACC_OUT)
+          trueOut = MAX_ACC_OUT;
+      return trueOut;
+}
+/*---------------------------------------------------------------------------------------*/
+//Tests for inputs
+// Input not in throttle dead zone
+boolean liveThrottle(int acc)
+{
+      return (acc > MIDDLE + DEAD_ZONE);
+}
+/*---------------------------------------------------------------------------------------*/
+// Input is not in brake dead zone
+boolean liveBrake(int brake)
+{
+      return (brake < MIDDLE - DEAD_ZONE);
+}
+/*---------------------------------------------------------------------------------------*/
+// Emergency stop
+void E_Stop()
+{
+    brake(MAX_BRAKE_OUT);
+    moveVehicle(MIN_ACC_OUT);
+    delay (2000);   // inhibit output
+    // TO DO: disable 36V power
+}
+/*---------------------------------------------------------------------------------------*/
+//Send values to output pin
+void steer(int pos)
+{
+      analogWrite(STEER_OUT_PIN, pos);
+//      Serial.print("\tSteering to: \t"); Serial.print(pos);
+     steer_control = pos;
+}
+/*---------------------------------------------------------------------------------------*/
+void convertBrake(long unsigned *amount)
+{
+      if (*amount < (MIDDLE + MIN_RC)/2)
+          *amount = MAX_BRAKE_OUT;
+      else
+           *amount = MIN_BRAKE_OUT;
+      brake (*amount);
+}
+/*---------------------------------------------------------------------------------------*/
+void brake (int amount)
+{
+      analogWrite(BRAKE_OUT_PIN, amount);
+ //     Serial.print("\tBraking to: \t"); Serial.print(*amount);
+      brake_control = amount;
+}
+/*---------------------------------------------------------------------------------------*/
+/* DAC_Write applies value to address, producing an analog voltage.
+// address: 0 for chan A; 1 for chan B; 2 for chan C; 3 for chan D
+// value: digital value converted to analog voltage
+// Output goes to mcp 4802 Digital-Analog Converter Chip via SPI
+// There is no input back from the chip.
+*/
+void DAC_Write(int address, int value)
+/*
+REGISTER 5-3: WRITE COMMAND REGISTER FOR MCP4802 (8-BIT DAC)
+A/B — GA SHDN D7 D6 D5 D4 D3 D2 D1 D0 x x x x
+bit 15 bit 0
+bit 15 A/B: DACA or DACB Selection bit
+1 = Write to DACB
+0 = Write to DACA
+bit 14 — Don’t Care
+bit 13 GA: Output Gain Selection bit
+1 = 1x (VOUT = VREF * D/4096)
+0 = 2x (VOUT = 2 * VREF * D/4096), where internal VREF = 2.048V.
+bit 12 SHDN: Output Shutdown Control bit
+1 = Active mode operation. VOUT is available.
+0 = Shutdown the selected DAC channel. Analog output is not available at the channel that was shut down.
+VOUT pin is connected to 500 k (typical)
+bit 11-0 D11:D0: DAC Input Data bits. Bit x is ignored.
+With 4.95 V on Vcc, observed output for 255 is 4.08V.
+This is as documented; with gain of 2, maximum output is 2 * Vref
+*/
+{
+      int byte1 = ((value & 0xF0)>>4) | 0x10; // acitve mode, bits D7-D4
+      int byte2 = (value & 0x0F)<<4; // D3-D0
+      if (address < 2)
+      {
+          // take the SS pin low to select the chip:
+          digitalWrite(SelectAB,LOW);
+          if (address >= 0)
+          {
+              if (address == 1)
+                  byte1 |= 0x80; // second channnel
+              SPI.transfer(byte1);
+              SPI.transfer(byte2);
+          }
+          // take the SS pin high to de-select the chip:
+          digitalWrite(SelectAB,HIGH);
+      }
+      else
+      {
+          // take the SS pin low to select the chip:
+          digitalWrite(SelectCD,LOW);
+          if (address <= 3)
+          {
+              if (address == 3)
+                  byte1 |= 0x80; // second channnel
+              SPI.transfer(byte1);
+              SPI.transfer(byte2);
+          }
+          // take the SS pin high to de-select the chip:
+          digitalWrite(SelectCD,HIGH);
+      }
+}
+/*---------------------------------------------------------------------------------------*/
+void moveVehicle(int acc)
+{
+      /* Observed behavior on ElCano #1 E-bike no load (May 10, 2013, TCF)
+      0.831 V at rest 52 counts
+      1.20 V: nothing 75
+      1.27 V: just starting 79
+      1.40 V: slow, steady 87
+      1.50 V: brisker 94
+      3.63 V: max 227 counts
+      255 counts = 4.08 V
+      */
+      DAC_Write(DAC_CHANNEL, acc);
+      throttle_control = acc;    // post most recent throttle.
+}
+
+/*========================================================================/
+ *============================WheelRev4 code==============================/
+ *=======================================================================*/
+
+/* Wheel Revolution Interrupt routine
+   Ben Spencer 10/21/13
+   Modified by Tyler Folsom 3/16/14; 3/3/16
+
+   A cyclometer gives a click once per revolution.
+   This routine computes the speed.
+*/
+
+#define SerialOdoOut  Serial3
+#define SerialMonitor Serial
+
+#define MEG 1000000
+#define MAX_SPEED_KPH 50
+#define MAX_SPEED_mmPs   ((MAX_SPEED_KPH * MEG) / 3600)
+// MAX_SPEED_mmPs = 13,888 mm/s = 13.888 m/s
+unsigned long MinTickTime_ms;
+// ((WHEEL_DIAMETER_MM * 3142) / MAX_SPEED_mmPs)
+// MinTickTime_ms = 89 ms
+#define MIN_SPEED_mPh 3000
+// A speed of less than 0.3 KPH is zero.
+unsigned long MaxTickTime_ms;
+// ((WHEEL_DIAMETER_MM * 3142) / MIN_SPEED_mmPs)
+// MinTickTime_ms = 9239 ms = 9 sec
+
+long SpeedCyclometer_mmPs = 0;
+// Speed in revolutions per second is independent of wheel size.
+float SpeedCyclometer_revPs = 0.0;//revolutions per sec
+
+#define IRQ_NONE 0
+#define IRQ_FIRST 1
+#define IRQ_SECOND 2
+#define IRQ_RUNNING 3
+#define NO_DATA 0x7FFFFFFF
+volatile byte InterruptState = IRQ_NONE;  // Tells us if we have initialized.
+volatile byte ClickNumber = 0;         // Used to distinguish old data from new.
+volatile unsigned long TickTime = 0;  // Time from one wheel rotation to the next gives speed.
+volatile unsigned long OldTick = 0;
+
+   static struct hist {
+     long olderSpeed_mmPs;  // older data
+     unsigned long olderTime_ms;   // time stamp of older speed
+
+     long oldSpeed_mmPs;  // last data from the interrupt
+     byte oldClickNumber;
+     unsigned long oldTime_ms;  // time stamp of old speed
+
+     byte nowClickNumber;  // situation when we want to display the speed
+     byte InterruptState;
+     unsigned long nowTime_ms;
+     unsigned long TickTime_ms;  // Tick times are used to compute speeds
+     unsigned long OldTick_ms;   // Tick times may not match time stamps if we don't process
+                                 // results of every interrupt
+   } history;
+
+/*---------------------------------------------------------------------------------------*/
+// WheelRev is called by an interrupt.
+void WheelRev()
+{
+    static int flip = 0;
+    unsigned long tick;
+    noInterrupts();
+    tick = millis();
+    if (InterruptState != IRQ_RUNNING)
+    // Need to process 1st two interrupts before results are meaningful.
+        InterruptState++;
+
+    if (tick - TickTime > MinTickTime_ms)
+    {
+        OldTick = TickTime;
+        TickTime = tick;
+        ++ClickNumber;
+    }
+    if (flip)
+        digitalWrite(13, LOW);
+    else
+        digitalWrite(13, HIGH);
+    flip =!flip;
+
+    interrupts();
+}
+/*---------------------------------------------------------------------------------------*/
+
+void setupWheelRev()
+{
+
+    SerialOdoOut.begin(115200); // C6 to C4
+    pinMode(13, OUTPUT); //led
+    digitalWrite(13, LOW);//turn LED off
+
+    pinMode(3, INPUT);//pulls input HIGH
+    float MinTick = WHEEL_DIAMETER_MM * PI;
+//    SerialMonitor.print (" MinTick = ");
+//    SerialMonitor.println (MinTick);
+    MinTick *= 1000.0;
+    MinTick /= MAX_SPEED_mmPs;
+//    SerialMonitor.print (MinTick);
+    MinTickTime_ms = MinTick;
+    SerialMonitor.print (" MinTickTime_ms = ");
+    SerialMonitor.println (MinTickTime_ms);
+
+//    SerialMonitor.print (" MIN_SPEED_mPh = ");
+//    SerialMonitor.print (MIN_SPEED_mPh);
+    float MIN_SPEED_mmPs =  ((MIN_SPEED_mPh * 1000.0) / 3600.0);
+    // MIN_SPEED_mmPs = 135 mm/s
+//    SerialMonitor.print (" MIN_SPEED_mmPs = ");
+//    SerialMonitor.print (MIN_SPEED_mmPs);
+    float MaxTick = (WHEEL_DIAMETER_MM * PI * 1000.0) / MIN_SPEED_mmPs;
+//    SerialMonitor.print (" MaxTick = ");
+//    SerialMonitor.print (MaxTick);
+    MaxTickTime_ms = MaxTick;
+//    SerialMonitor.print (" MaxTickTime = ");
+//    SerialMonitor.println (MaxTickTime_ms);
+    TickTime = millis();
+    // OldTick will normally be less than TickTime.
+    // When it is greater, TickTime - OldTick is a large positive number,
+    // indicating that we have not moved.
+    // TickTime would overflow after days of continuous operation, causing a glitch of
+    // a display of zero speed.  It is unlikely that we have enough battery power to ever see this.
+    OldTick = TickTime;
+    InterruptState = IRQ_NONE;
+    ClickNumber = 0;
+    history.oldSpeed_mmPs = history.olderSpeed_mmPs = NO_DATA;
+
+    attachInterrupt (1, WheelRev, RISING);//pin 3 on Mega
+    SerialMonitor.print("TickTime: ");
+    SerialMonitor.print(TickTime);
+    SerialMonitor.print(" OldTick: ");
+    SerialMonitor.println(OldTick);
+
+    SerialMonitor.println("WheelRev setup complete");
+
+}
+/*---------------------------------------------------------------------------------------*/
+void ComputeSpeed( struct hist *data)
+{
+    if (data->InterruptState == IRQ_NONE || data->InterruptState == IRQ_FIRST)
+    {  // No data
+       SpeedCyclometer_mmPs = 0;
+       SpeedCyclometer_revPs = 0;
+       return;
+    }
+    float Circum_mm = (WHEEL_DIAMETER_MM * PI);
+    long WheelRev_ms = data->TickTime_ms - data->OldTick_ms;
+    if (data->InterruptState >= IRQ_SECOND && data->oldSpeed_mmPs == NO_DATA && WheelRev_ms > 0)
+    {   //  first computed speed
+        SpeedCyclometer_revPs = 1000.0 / WheelRev_ms;
+        SpeedCyclometer_mmPs  =
+        data->oldSpeed_mmPs = Circum_mm * SpeedCyclometer_revPs;
+        data->oldTime_ms = data->TickTime_ms;  // time stamp for oldSpeed_mmPs
+        data->oldClickNumber = data->nowClickNumber;
+        return;
+    }
+    if (data->InterruptState == IRQ_RUNNING && data->olderSpeed_mmPs == NO_DATA && WheelRev_ms > 0
+       && data->nowClickNumber != data->oldClickNumber)
+    {   //  new data for second computed speed
+        data->olderSpeed_mmPs = data->oldSpeed_mmPs;
+        data->olderTime_ms = data->oldTime_ms;
+
+        SpeedCyclometer_revPs = 1000.0 / WheelRev_ms;
+        SpeedCyclometer_mmPs  =
+        data->oldSpeed_mmPs = Circum_mm * SpeedCyclometer_revPs;
+        data->oldTime_ms = data->TickTime_ms;  // time stamp for oldSpeed_mmPs
+        data->oldClickNumber = data->nowClickNumber;
+        return;
+    }
+    if (data->InterruptState == IRQ_RUNNING && data->olderSpeed_mmPs != NO_DATA && WheelRev_ms > 0)
+    {  // Normal situation after initialization
+        if (data->nowClickNumber == data->oldClickNumber)
+        {  // No new information; extrapolate the speed if decelerating; else keep old speed
+            if (data->olderSpeed_mmPs > data->oldSpeed_mmPs)
+            {   // decelerrating
+                float deceleration = (float) (data->olderSpeed_mmPs - data->oldSpeed_mmPs) /
+                (data->oldTime_ms - data->olderTime_ms);
+                SpeedCyclometer_mmPs = data->oldSpeed_mmPs - deceleration *
+                (data->nowTime_ms - data->oldTime_ms);
+                if (SpeedCyclometer_mmPs < 0)
+                    SpeedCyclometer_mmPs = 0;
+                SpeedCyclometer_revPs = SpeedCyclometer_mmPs / Circum_mm;
+            }
+            else
+            {  // accelerating; should get new data soon
+
+            }
+            if(data->nowTime_ms - data->oldTime_ms > MaxTickTime_ms)
+            {  // too long without getting a tick
+                SpeedCyclometer_mmPs = 0;
+                SpeedCyclometer_revPs = 0;
+                if(data->nowTime_ms - data->oldTime_ms > 2 * MaxTickTime_ms)
+                {
+                    InterruptState = IRQ_FIRST;  //  Invalidate old data
+                    data->oldSpeed_mmPs = NO_DATA;
+                    data->olderSpeed_mmPs = NO_DATA;
+                }
+            }
+        }
+        else
+        {  // moving; use new data to compute speed
+            data->olderSpeed_mmPs = data->oldSpeed_mmPs;
+            data->olderTime_ms = data->oldTime_ms;
+
+            SpeedCyclometer_revPs = 1000.0 / WheelRev_ms;
+            SpeedCyclometer_mmPs  =
+          data->oldSpeed_mmPs = Circum_mm * SpeedCyclometer_revPs;
+            data->oldTime_ms = data->TickTime_ms;  // time stamp for oldSpeed_mmPs
+            data->oldClickNumber = data->nowClickNumber;
+        }
+    }
+    if(data->nowTime_ms - data->TickTime_ms > WheelRev_ms)
+    {  // at this speed, should have already gotten a tick?; If so, we are slowing.
+        float SpeedSlowing_revPs = 1000.0 / (data->nowTime_ms - data->TickTime_ms);
+        long SpeedSlowing_mmPs  = Circum_mm * SpeedCyclometer_revPs;
+        SpeedCyclometer_revPs = min(SpeedCyclometer_revPs, SpeedSlowing_revPs);
+        SpeedCyclometer_mmPs  = min(SpeedCyclometer_mmPs, SpeedSlowing_mmPs);
+   }
+    return;
+}
+/*---------------------------------------------------------------------------------------*/
+void PrintSpeed( struct hist *data)
+{
+      Serial.print(SpeedCyclometer_mmPs); Serial.print("\t");
+      Serial.print(data->InterruptState); Serial.print("\t");
+      Serial.print(data->oldSpeed_mmPs); Serial.print("\t");
+      Serial.print(data->olderSpeed_mmPs); Serial.print("\t");
+      Serial.print(data->oldClickNumber); Serial.print("\t");
+      Serial.print(data->nowClickNumber); Serial.print("\t");
+      Serial.print(data->olderTime_ms); Serial.print("\t");
+      Serial.print(data->oldTime_ms); Serial.print("\t");
+      Serial.print(data->nowTime_ms); Serial.print("\t");
+      Serial.print(data->TickTime_ms); Serial.print("\t");
+      Serial.println(data->OldTick_ms);
+}
+/*---------------------------------------------------------------------------------------*/
+void show_speed(SerialData *Results)
+{
+   history.nowTime_ms = millis();
+   noInterrupts();
+   history.TickTime_ms = TickTime;
+   history.OldTick_ms = OldTick;
+   history.nowClickNumber = ClickNumber;
+   history.InterruptState = InterruptState;
+   interrupts();
+
+   ComputeSpeed (&history);
+//   PrintSpeed(&history);
+
+    Odometer_m += (float)(LOOP_TIME_MS * SpeedCyclometer_mmPs) / MEG;
+// Since Results have not been cleared, angle information will also be sent.
+    Results->speed_cmPs = SpeedCyclometer_mmPs / 10;
+    writeSerial(&Serial3, Results);  // Send speed to C6
+
+    show7seg( SpeedCyclometer_mmPs);   // Show speed on 7 segment LEDs
+
+}
+/*---------------------------------------------------------------------------------------*/
+/*========================CalibrateTurnAngle======================*/
+/*  This routine should only be called when
+          - Wheels are pointed straight ahead, and have been for a while.
+          - Trike is not moving, and is stable.
+    Calibration will block any response to controls; there will be no turning or movemnet during calibration.
+    Angle sensors can drift, and should periodically be zeroed.
+*/
+void CalibrateTurnAngle(int count, int pause)
+{
+    int totalRight = 0;
+    int totalLeft = 0;
+    int i, left, right;
+    for (i = 0; i < count; i++)
+    {
+          totalRight += analogRead(A2);
+          totalLeft += analogRead(A3);
+          delay(pause);
+    }
+    right = totalRight / count;
+    left  = totalLeft  / count;
+    // Only recalibrate when instruments are reasonable
+    // Do not make garbage readings the new normal.
+    if(RIGHT_MIN_COUNT <= right && right <= RIGHT_MAX_COUNT)
+    {
+         RightStraight_A2 = right;
+         Right_Min_Count = RightStraight_A2 - 60;   // 60 counts is 20 degrees
+         Right_Max_Count = RightStraight_A2 + 60;
+     }
+    else
+    {
+         RightStraight_A2 = RIGHT_MIN_COUNT + (RIGHT_MAX_COUNT - RIGHT_MIN_COUNT)/2 ;
+         Right_Min_Count = RIGHT_MIN_COUNT;
+         Right_Max_Count = RIGHT_MAX_COUNT;
+    }
+    if  (LEFT_MIN_COUNT  <= left  && left  <= LEFT_MAX_COUNT)
+    {
+        LeftStraight_A3  = left;
+        Left_Min_Count  = LeftStraight_A3  - 60;
+        Left_Max_Count  = LeftStraight_A3  + 60;
+    }
+    else
+    {
+        LeftStraight_A3  = LEFT_MIN_COUNT + (LEFT_MAX_COUNT - LEFT_MIN_COUNT)/2 ;
+        Left_Min_Count = LEFT_MIN_COUNT;
+        Left_Max_Count = LEFT_MAX_COUNT;
+    }
+//    Serial.print("\tCALIBRATE: Left Straight\t"); Serial.print(LeftStraight_A3);
+//    Serial.print("\tRight Straight\t"); Serial.println(RightStraight_A2);
+    old_turn_degx1000 = 0; // straight
+}
+/*---------------------------------------------------------------------------------------*/
+/*======================ReadTurnAngle======================*/
+int TurnAngle_degx10()
+{
+    long new_turn_degx1000;
+    long expected_turn_degx1000;
+    int new_turn_degx10;
+    long min_ang, max_ang;
+    bool OK_right = false;
+    bool OK_left = false;
+    int right = analogRead(A2);
+    int left = analogRead(A3);
+//    Serial.print("Left"); Serial.print("\t"); Serial.print(left);
+//    Serial.print("\tRight"); Serial.print("\t"); Serial.print(right);
+//    Serial.print("LeftStraight_A3"); Serial.print("\t"); Serial.print(LeftStraight_A3);
+//    Serial.print("\tRightStraight_A2"); Serial.print("\t"); Serial.print(RightStraight_A2);
+    if ((Right_Min_Count <= right) && (right <= Right_Max_Count))
+       OK_right = true;
+    if ((Left_Min_Count <= left) && (left <= Left_Max_Count))
+       OK_left = true;
+    long right_degx1000 = (right - RightStraight_A2) * RIGHT_DEGx1000pCOUNT;
+    long left_degx1000  = (left -  LeftStraight_A3) *  LEFT_DEGx1000pCOUNT;
+//    Serial.print("Left"); Serial.print("\t"); Serial.print(left_degx1000);
+//    Serial.print("\tRight"); Serial.print("\t"); Serial.print(right_degx1000);
+
+    expected_turn_degx1000 = old_turn_degx1000;
+    if (OK_left && OK_right)
+    {  // use the median
+        if (right_degx1000 < left_degx1000)
+        {
+            min_ang = right_degx1000;
+            max_ang = left_degx1000;
+        }
+        else
+        {
+            min_ang = left_degx1000;
+            max_ang = right_degx1000;
+        }
+        if (expected_turn_degx1000 < min_ang)
+            new_turn_degx1000 = min_ang;
+        else if (expected_turn_degx1000 > max_ang)
+            new_turn_degx1000 = max_ang;
+        else
+            new_turn_degx1000 = expected_turn_degx1000;
+    }
+    else if (OK_left)
+    {
+        new_turn_degx1000 = (left_degx1000 + expected_turn_degx1000)/2;
+    }
+    else if (OK_right)
+    {
+        new_turn_degx1000 = (right_degx1000 + expected_turn_degx1000)/2;
+    }
+    else
+    {   // No sensors; use last valid measurement
+        new_turn_degx1000 = old_turn_degx1000;
+    }
+    new_turn_degx10 = (int) (new_turn_degx1000 / 100);
+    old_turn_degx1000 = new_turn_degx1000;
+//  Serial.print("\tnew_turn_degx10"); Serial.print("\t"); Serial.println(new_turn_degx10);
+    return new_turn_degx10;
+}
+/*---------------------------------------------------------------------------------------*/
+void Throttle_PID(long error_speed_mmPs)
+
+/* Use throttle and brakes to keep vehicle at a desired speed.
+   A PID controller uses the error in the set point to increase or decrease the juice.
+   P = proportional; change based on present error
+   I = integra;  change based on recent sum of errors
+   D = derivative: change based on how error is changing.
+   The controller needs to avoid problems of being too sluggish or too skittery.
+   A sluggish control (overdamped) takes too long to reach the set-point.
+   A skitterish control (underdamped) can overshoot, then undershoot, producing
+   oscillations and jerky motion.
+   Getting the right control is a matter of tuning right parts of P, I, and D,
+   which is something of a black art.
+   For more information, search for:
+   VanDoren Proportional Integral Derivative Control
+*/
+{
+  static int  throttle_control = MIN_ACC_OUT;
+  static int  brake_control = MAX_BRAKE_OUT;
+  static int error_index = 0;
+  int i;
+  static long error_sum = 0;
+  long mean_speed_error = 0;
+  long extrapolated_error = 0;
+  long PID_error;
+  const float P_tune = 0.4;
+  const float I_tune = 0.5;
+  const float D_tune = 0.1;
+  const long speed_tolerance_mmPs = 75;  // about 0.2 mph
+  // setting the max_error affacts control: anything bigger gets maximum response
+  const long max_error_mmPs = 2500; // about 5.6 mph
+
+//lets look through this
+  error_sum -= speed_errors[error_index];
+  speed_errors[error_index] = error_speed_mmPs;
+  error_sum += error_speed_mmPs;
+  mean_speed_error = error_sum / ERROR_HISTORY;
+  i = (error_index -1) % ERROR_HISTORY;
+  if (++error_index >= ERROR_HISTORY)
+      error_index = 0;
+  extrapolated_error = 2 * error_speed_mmPs - speed_errors[i];
+    PID_error = P_tune * error_speed_mmPs
+            + I_tune * mean_speed_error
+            + D_tune * extrapolated_error;
+  if (PID_error > speed_tolerance_mmPs)
+  {  // too fast
+    long throttle_decrease = (MAX_ACC_OUT - MIN_ACC_OUT) * PID_error / max_error_mmPs;
+    throttle_control -= throttle_decrease;
+    if (throttle_control < MIN_ACC_OUT)
+        throttle_control = MIN_ACC_OUT;
+    moveVehicle(throttle_control);
+
+    long brake_increase = (MAX_BRAKE_OUT - MIN_BRAKE_OUT) * PID_error / max_error_mmPs;
+    // MIN_BRAKE_OUT = 180; MAX_BRAKE_OUT = 250;
+    brake_control -= brake_increase;
+    if (brake_control > MAX_BRAKE_OUT)
+        brake_control = MAX_BRAKE_OUT;
+    brake(brake_control);
+  }
+  else if (PID_error < speed_tolerance_mmPs)
+  {  // too slow
+    long throttle_increase = (MAX_ACC_OUT - MIN_ACC_OUT) * PID_error / max_error_mmPs;
+    throttle_control += throttle_increase;
+    if (throttle_control > MAX_ACC_OUT)
+        throttle_control = MAX_ACC_OUT;
+    moveVehicle(throttle_control);
+
+    // release brakes
+    long brake_decrease = (MAX_BRAKE_OUT - MIN_BRAKE_OUT) * PID_error / max_error_mmPs;
+    // MIN_BRAKE_OUT = 180; MAX_BRAKE_OUT = 250;
+    brake_control += brake_decrease;
+    if (brake_control < MIN_BRAKE_OUT)
+        brake_control = MIN_BRAKE_OUT;
+    brake(brake_control);
+  }
+  // else maintain current speed
+  Serial.print("\tThrottle Brake \t");  // csv for spreadsheet
+  Serial.print(throttle_control);
+  Serial.print("\t");
+  Serial.print(brake_control);
+  Serial.print("\t");
+//  Serial.print(drive_speed_mmPs);  Serial.print("\t");
+//  Serial.println(sensor_speed_mmPs);
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Serial 7-Segment Display Example Code
+    Serial Mode Stopwatch
+   by: Jim Lindblom
+     SparkFun Electronics
+   date: November 27, 2012
+   license: This code is public domain.
+
+   This example code shows how you could use software serial
+   Arduino library to interface with a Serial 7-Segment Display.
+
+   There are example functions for setting the display's
+   brightness, decimals and clearing the display.
+
+   The print function is used with the SoftwareSerial library
+   to send display data to the S7S.
+
+   Circuit:
+   Arduino -------------- Serial 7-Segment
+     3.3V   --------------------  VCC
+     GND  --------------------  GND
+      10   --------------------  RX
+*/
+
+void setup7seg()
+{
+  // Must begin s7s software serial at the correct baud rate.
+  //  The default of the s7s is 9600.
+  s7s.begin(9600);
+
+  // Clear the display, and then turn on all segments and decimals
+  clearDisplay();  // Clears display, resets cursor
+  setBrightness(127);  // Medium brightness
+//  setBrightness(255);  // High brightness
+}
+/*---------------------------------------------------------------------------------------*/
+void show7seg(int speed_mmPs)
+{
+  char tempString[10];  // Will be used with sprintf to create strings
+  // convert mm/s to km/h
+  int speed_kmPhx10 = (speed_mmPs*.036);
+  // Magical sprintf creates a string for us to send to the s7s.
+  //  The %4d option creates a 4-digit integer.
+  sprintf(tempString, "%4d", speed_kmPhx10);
+//  Serial.println(tempString);
+  // This will output the tempString to the S7S
+  s7s.print(tempString);
+  setDecimals(0b00000100);  // Sets digit 3 decimal on
+}
+/*---------------------------------------------------------------------------------------*/
+// Send the clear display command (0x76)
+//  This will clear the display and reset the cursor
+void clearDisplay()
+{
+  s7s.write(0x76);  // Clear display command
+}
+/*---------------------------------------------------------------------------------------*/
+// Set the displays brightness. Should receive byte with the value
+//  to set the brightness to
+//  dimmest------------->brightest
+//     0--------127--------255
+void setBrightness(byte value)
+{
+  s7s.write(0x7A);  // Set brightness command byte
+  s7s.write(value);  // brightness data byte
+}
+/*---------------------------------------------------------------------------------------*/
+// Turn on any, none, or all of the decimals.
+//  The six lowest bits in the decimals parameter sets a decimal
+//  (or colon, or apostrophe) on or off. A 1 indicates on, 0 off.
+//  [MSB] (X)(X)(Apos)(Colon)(Digit 4)(Digit 3)(Digit2)(Digit1)
+void setDecimals(byte decimals)
+{
+  s7s.write(0x77);
+  s7s.write(decimals);
+}


pump working

pump working

error: pathspec 'SAM' did not match any file(s) known to git
error: pathspec 'arduino' did not match any file(s) known to git
error: pathspec 'code/minimal_SAM/minimal_SAM.ino' did not match any file(s) known to git


Pushing first version of the Arduino controller's firmware

error: pathspec 'Arduino/arduino.ino' did not match any file(s) known to git

--- Arduino/arduino.ino
+++ Arduino/arduino.ino
@@ -0,0 +1,212 @@
+// *************************************
+//   StromBewusst - Arduino Controller
+// *************************************
+// Configuration
+
+// Uncomment these liness if you use an Ethernet Shield
+//#define USE_ETHERNET_SHIELD
+//#define ETHERNET_USE_DHCP
+//#define ETHERNET_MAC { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+// Uncomment these lines if you use a WiFi Shield
+//#define USE_WIFI_SHIELD
+//#define WIFI_SSID "ssid"
+//#define WIFI_KEY "wpakey"
+
+// Uncomment these lines if you use NeoPixel for status visualization
+//#define USE_NEOPIXEL
+//#define NEOPIXEL_PIN 6
+
+// Uncomment these lines if you wish to use the the free strombewusstsein Web Service!
+//#define USE_STROMBEWUSST_SERVER
+//#define STROMBEWUSST_SERVER "se.esse.es"
+//#define STROMBEWUSST_PORT 8888
+//#define STROMBEWUSST_KEY "foobar"
+
+// TriggerPin - the PIN that gets HIGH when 1.25W/h were used on the line
+#define TRIGGER_PIN 8
+
+// TIMEFRAME defines the datastorages time segmenting (256 hits in that time frame max)
+#define TIMEFRAME 60
+
+// STORAGE_HOURS defines how many hours of detailed information are stored in RAM
+#define STORAGE_HOURS 12
+
+#define SERVER_PORT 80
+
+// *************************************
+
+// Due to weird ifdef handling of the Arudino IDE, all libraries must be included on spot :(
+//#include <Adafruit_NeoPixel.h>
+#include <SPI.h>
+#include <Ethernet.h>
+#include <EthernetUdp.h>
+#include <WiFi.h>
+#include <WiFiUdp.h>
+
+// Our prototypes!
+void setup();
+void loop();
+void wifiConnect();
+void ethernetConnect();
+void triggerCheck();
+void gotTriggered();
+void strombewusstInit();
+void strombewusstPush();
+int storageSum(int frames);
+void pointerLoop();
+void pointerChanged();
+
+#ifdef USE_ETHERNET_SHIELD
+  EthernetServer server = EthernetServer(SERVER_PORT);
+  EthernetUDP udp;
+  byte ethernetMac[] = ETHERNET_MAC;
+#endif
+#ifdef USE_WIFI_SHIELD
+  WiFiServer server = WiFiServer(SERVER_PORT);
+  WiFiUDP udp;
+  int connectionStatus = WL_IDLE_STATUS;
+#endif
+#ifdef USE_STROMBEWUSST_SERVER
+  char udpBuffer[33] = STROMBEWUSST_KEY;
+#endif
+// TimeStorage - stores the # of bytes needed to store the information
+const int timeStorage = 60 / TIMEFRAME * 60 * STORAGE_HOURS;
+byte storage[timeStorage];
+
+int storagePointer = 0;
+
+void setup() {
+  Serial.begin(9600);
+  pinMode(TRIGGER_PIN, INPUT);
+
+  #ifdef USE_WIFI_SHIELD
+    wifiConnect();
+  #endif
+  #ifdef USE_ETHERNET_SHIELD
+    ethernetConnect();
+  #endif
+  #ifdef USE_STROMBEWUSST_SERVER
+    strombewusstInit();
+  #endif
+}
+
+void strombewusstInit()
+{
+  #ifdef USE_ETHERNET_SHIELD
+
+  #endif
+}
+
+void loop()
+{
+  pointerLoop();
+  triggerCheck();
+}
+
+// All the Ethernet related methods only needed when the shield is used
+#ifdef USE_ETHERNET_SHIELD
+void ethernetConnect()
+{
+  Ethernet.begin(ethernetMac);
+
+  // print our Ethernet shield's IP address
+  IPAddress ip = WiFi.localIP();
+  Serial.println(Ethernet.localIP());
+}
+#endif USE_ETHERNET_SHIELD
+
+// All the WiFi related methods only needed when the shield is used
+#ifdef USE_WIFI_SHIELD
+void wifiConnect()
+{
+  // check for the presence of the shield
+  if (WiFi.status() == WL_NO_SHIELD) {
+    Serial.println("WiFi shield not present");
+    while(1);
+  }
+
+  // connect to our network
+  while ( connectionStatus != WL_CONNECTED) {
+    Serial.print("Connecting to SSID: ");
+    Serial.println(WIFI_SSID);
+    connectionStatus = WiFi.begin(WIFI_SSID, WIFI_KEY);
+
+    // wait 10 seconds for connection
+    delay(10000);
+  }
+
+  // print our WiFi shield's IP address
+  IPAddress ip = WiFi.localIP();
+  Serial.print("IP Address: ");
+  Serial.println(ip);
+}
+#endif
+
+void triggerCheck()
+{
+  // Check if we got an trigger signal
+  if (digitalRead(TRIGGER_PIN) == HIGH)
+  {
+    // Wait until input gets LOW again
+    while(digitalRead(TRIGGER_PIN) == HIGH);
+    gotTriggered();
+  }
+}
+
+void gotTriggered()
+{
+  Serial.println("Trigger got high!");
+  storage[storagePointer]++;
+}
+
+
+void pointerLoop()
+{
+  int pointer = millis() / 1000 / TIMEFRAME % STORAGE_HOURS;
+  if (pointer != storagePointer)
+  {
+    #ifdef USE_STROMBEWUSST_SERVER
+      strombewusstPush();
+    #endif
+    storagePointer = pointer;
+    pointerChanged();
+  }
+}
+
+void strombewusstPush()
+{
+  #ifdef USE_ETHERNET_SHIELD
+
+  #endif
+  #ifdef USE_WIFI_SHIELD
+
+  #endif
+}
+
+void pointerChanged()
+{
+  Serial.println("Last 5 seconds: "+String(storageSum(1)));
+  Serial.println("Last 30 seconds: "+String(storageSum(6)));
+  Serial.println("Last minute: "+String(storageSum(12)));
+  Serial.println("Pointer changed to "+String(storagePointer));
+  storage[storagePointer] = 0;
+}
+
+
+int storageSum(int frames)
+{
+  int sum = 0;
+  int pos = storagePointer;
+  for (int i=0; i<frames; i++)
+  {
+    pos--;
+    if (pos == -1)
+    {
+      pos = timeStorage-1;
+    }
+    sum = sum + (int)storage[pos];
+  }
+  return sum;
+}
+


Chris get to work or I'll eat your children

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/markwatneyy/ttt_arduino.git/'


Update MYBL_DEV.ino

Update MYBL_DEV.ino

--- MYBL_DEV/MYBL_DEV.ino
+++ MYBL_DEV/MYBL_DEV.ino
@@ -3,7 +3,7 @@

  Arduboy version 0.1:  http://www.team-arg.org/mybl-downloads.html

- MADE by TEAM a.r.g. : http://www.team-arg.org/About.html
+ MADE by TEAM a.r.g. : http://www.team-arg.org/more-about.html

  2016 - GEVANO - pixelart by CastPixel: https://twitter.com/castpixel


Fixed bad adjustment on the servo. Added poor mans version check for the Arduino firmware since this change in OpenROV would send values that the old firmware may not be ready to accept

--- OpenROV/OpenROV.ino
+++ OpenROV/OpenROV.ino
@@ -5,6 +5,7 @@
 #include "Device.h"
 #include "Timer.h"
 #include "FreeMem.h"
+

 Motors motors(9, 10, 11);
 Command cmd;
@@ -97,7 +98,7 @@
     if (s>c_motors) c_motors += min(aggro,s-c_motors);
     if (tilt_val<c_tilt) c_tilt -= min(aggro,c_tilt-tilt_val);
     if (tilt_val>c_tilt) c_tilt += min(aggro,tilt_val-c_tilt);
-    tilt.writeMicroseconds(tilt_val);
+    tilt.writeMicroseconds(c_tilt);
     motors.go(c_motorp, c_motorv, c_motors);
   }

@@ -142,6 +143,17 @@
     Serial.print(",");
     Serial.print(s);
     Serial.print(";");
+    Serial.print("servo:");
+    Serial.print(c_tilt);
+    Serial.print(";");
+    Serial.print("starg:");
+    Serial.print(tilt_val);
+    Serial.print(";");
+    Serial.print("ver:");
+    //Version Number of last change from UTC date: .YYYYMMDDHHMMSS. If you make a change between this and the cockpit that requires the firmware to be in sync or it breaks the system your should update this version number
+    // and update the cockpit software lib/OpenROVControler.js to check and ensure the firmware is at this version.
+    Serial.print(".20130314034900");
+    Serial.print(";");
     Serial.print("time:");
     Serial.println(millis());
   }


Upload yellow/GenDisarray.

Upload yellow/GenDisarray.

error: pathspec 'yellow/GenDisarray/GenDisarray.ino' did not match any file(s) known to git

--- yellow/GenDisarray/GenDisarray.ino
+++ yellow/GenDisarray/GenDisarray.ino
@@ -0,0 +1,315 @@
+/*************************************************************************
+* File Name          : IR_Ultrasonic.ino
+* Author             : Ander, Mark Yan
+* Updated            : Ander, Mark Yan
+* Version            : V01.01.003
+* Date               : 01/19/2016
+* Description        : Firmware for Makeblock Electronic modules with Scratch.
+* License            : CC-BY-SA 3.0
+* Copyright (C) 2013 - 2016 Maker Works Technology Co., Ltd. All right reserved.
+* http://www.makeblock.cc/
+**************************************************************************/
+// Alternaive names:
+// neic_tank
+// Disasterbot
+// General disarray
+
+#include <Wire.h>
+#include <SoftwareSerial.h>
+#include <Arduino.h>
+#include <MeOrion.h>
+
+MeDCMotor dc;
+MeUltrasonicSensor us(PORT_3);
+Me7SegmentDisplay sd(PORT_4);
+MeLimitSwitch killswitch(PORT_7,SLOT2);
+MeLimitSwitch buttswitch(PORT_5,SLOT2);
+MeInfraredReceiver infraredReceiverDecode(PORT_6);
+MeBuzzer buzzer;
+
+int analogs[8]={A0,A1,A2,A3,A4,A5,A6,A7};
+String mVersion = "01.01.003";
+unsigned char irRead = 0;
+
+//Just for Start
+int moveSpeed = 220;
+int turnSpeed = 200;
+int minSpeed = 45;
+int factor = 23;
+int distance=0;
+int randnum = 0;
+boolean leftflag;
+boolean rightflag;
+int starter_mode = 1;
+
+void Forward()
+{
+  dc.reset(M1);
+  dc.run(moveSpeed);
+  dc.reset(M2);
+  dc.run(moveSpeed);
+}
+
+void Backward()
+{
+  dc.reset(M1);
+  dc.run(-moveSpeed);
+  dc.reset(M2);
+  dc.run(-moveSpeed);
+}
+
+void BackwardAndTurnLeft()
+{
+  dc.reset(M1);
+  dc.run(-moveSpeed/2);
+  dc.reset(M2);
+  dc.run(-moveSpeed);
+}
+
+void BackwardAndTurnRight()
+{
+  dc.reset(M1);
+  dc.run(-moveSpeed);
+  dc.reset(M2);
+  dc.run(-moveSpeed/2);
+}
+
+void TurnLeft()
+{
+  dc.reset(M1);
+  dc.run(-moveSpeed);
+  dc.reset(M2);
+  dc.run(moveSpeed);
+}
+
+void TurnRight()
+{
+  dc.reset(M1);
+  dc.run(moveSpeed);
+  dc.reset(M2);
+  dc.run(-moveSpeed);
+}
+
+void Stop()
+{
+  dc.reset(M1);
+  dc.run(0);
+  dc.reset(M2);
+  dc.run(0);
+}
+void ChangeSpeed(int spd)
+{
+  moveSpeed = spd;
+}
+
+void ultrCarProcess()
+{
+  distance = us.distanceCm();
+  Serial.println(distance);
+  randomSeed(analogRead(A4));
+  if((distance > 10) && (distance < 40))
+  {
+    randnum=random(300);
+    if((randnum > 190) && (!rightflag))
+    {
+      leftflag=true;
+      TurnLeft();
+    }
+    else
+    {
+      rightflag=true;
+      TurnRight();
+    }
+  }
+  else if(distance < 10)
+  {
+    randnum=random(300);
+    if(randnum > 190)
+    {
+      BackwardAndTurnLeft();
+    }
+    else
+    {
+      BackwardAndTurnRight();
+    }
+  }
+  else
+  {
+    leftflag=false;
+    rightflag=false;
+    Forward();
+  }
+}
+
+void IrProcess()
+{
+  infraredReceiverDecode.loop();
+  irRead = infraredReceiverDecode.getCode();
+  if((irRead != IR_BUTTON_TEST) && (starter_mode != 0))
+  {
+    return;
+  }
+  switch(irRead)
+  {
+    case IR_BUTTON_PLUS:
+      Forward();
+      break;
+    case IR_BUTTON_MINUS:
+      Backward();
+      break;
+    case IR_BUTTON_NEXT:
+      TurnRight();
+      break;
+    case IR_BUTTON_PREVIOUS:
+      TurnLeft();
+      break;
+    case IR_BUTTON_9:
+      ChangeSpeed(factor*9+minSpeed);
+      break;
+    case IR_BUTTON_8:
+      ChangeSpeed(factor*8+minSpeed);
+      break;
+    case IR_BUTTON_7:
+      ChangeSpeed(factor*7+minSpeed);
+      break;
+    case IR_BUTTON_6:
+      ChangeSpeed(factor*6+minSpeed);
+      break;
+    case IR_BUTTON_5:
+      ChangeSpeed(factor*5+minSpeed);
+      break;
+    case IR_BUTTON_4:
+      ChangeSpeed(factor*4+minSpeed);
+      break;
+    case IR_BUTTON_3:
+      ChangeSpeed(factor*3+minSpeed);
+      break;
+    case IR_BUTTON_2:
+      ChangeSpeed(factor*2+minSpeed);
+      break;
+    case IR_BUTTON_1:
+      ChangeSpeed(factor*1+minSpeed);
+      break;
+    case IR_BUTTON_TEST:
+      Stop();
+      while(infraredReceiverDecode.buttonState() != 0)
+      {
+        infraredReceiverDecode.loop();
+      }
+      starter_mode = starter_mode + 1;
+      if(starter_mode == 2)
+      {
+        starter_mode = 0;
+      }
+      break;
+    default:
+      Stop();
+      break;
+  }
+}
+
+int ramlength = 100; // miliseconds to spend in all ahead full ramming speed.
+int turnlength = 500; // miliseconds it takes to do a 90 degree turn
+int dismountlength = 250; // miliseconds it takes to climb back down off a wall
+int correctionlength = 50; // miliseconds it takes to do a minor course correction.
+double personal_space = 8.0; // desired minimum distance to wall in cm.
+double agoraphobia = 12.0; // desired maximum distance to wall in cm.
+
+void Hunt()
+{
+  // Turn ca 90 degrees left.
+  TurnLeft();
+  delay(turnlength);
+  Stop();
+}
+
+void Dismount()
+{
+  // Back up, turn ca 90 degrees left.
+  Backward();
+  delay(dismountlength);
+  Hunt();
+  Stop();
+}
+
+void CorrectLeft()
+{
+  dc.reset(M1);
+  //dc.run(-moveSpeed);
+  dc.run(moveSpeed/8);
+  dc.reset(M2);
+  dc.run(moveSpeed);
+  delay(correctionlength);
+  Stop();
+}
+
+void CorrectRight()
+{
+  dc.reset(M1);
+  dc.run(moveSpeed);
+  dc.reset(M2);
+  //dc.run(-moveSpeed);
+  dc.run(moveSpeed/8);
+  delay(correctionlength);
+  Stop();
+}
+
+void Ram()
+{
+  double distance = us.distanceCm();
+  sd.display((int) distance);
+  if (distance < personal_space ) {
+    CorrectLeft();
+  } else if (distance > agoraphobia) {
+    CorrectRight();
+  }
+  Forward();
+  delay(ramlength);
+}
+
+void Destroy()
+{
+  if(killswitch.touched())
+  {
+    // Target destroyed.
+    Hunt();
+  }
+  if(buttswitch.touched())
+  {
+    // Target destroyed.
+    Dismount();
+  }
+  // TODO: unfinished.
+  Ram();
+}
+
+void setup(){
+  pinMode(13,OUTPUT);
+  digitalWrite(13,HIGH);
+  delay(300);
+  digitalWrite(13,LOW);
+  Serial.begin(115200);
+  delay(500);
+  buzzerOn();
+  delay(100);
+  buzzerOff();
+  delay(500);
+  infraredReceiverDecode.begin();
+  leftflag=false;
+  rightflag=false;
+  randomSeed(analogRead(0));
+  Stop();
+  Serial.print("Version: ");
+  Serial.println(mVersion);
+}
+
+void loop(){
+  IrProcess();
+  if(starter_mode == 1)
+  {
+    //ultrCarProcess();
+    Destroy();
+  }
+}
+
+


Create userFunctions.ino

Create userFunctions.ino

error: pathspec '1.1/Arduino/HAL-E/userFunctions.ino' did not match any file(s) known to git

--- 1.1/Arduino/HAL-E/userFunctions.ino
+++ 1.1/Arduino/HAL-E/userFunctions.ino
@@ -0,0 +1,23 @@
+//modify this file with the functions you need to run your commands
+//import aditional libraries (ones not used in HAL-E.ino) here
+
+
+//This is the primary switch that takes the input (your command number) and then does you commands
+void mainSwitch(unsigned long cmdNumber)
+{
+  switch(cmdNumber) {
+    case 0:
+      Serial.println("locked");
+      break;
+    case 1:
+      Serial.println("Command 1");
+      //code for command 1
+      break;
+    default:
+      Serial.println("UNKNOWN COMMAND");
+      break;
+  }
+}
+
+//add aditional functions for your commands here
+


reciever switch plays dial tone

reciever switch plays dial tone

error: pathspec 'turing-old-rotary.ino' did not match any file(s) known to git

--- turing-old-rotary.ino
+++ turing-old-rotary.ino
@@ -0,0 +1,169 @@
+/*
+Turing Old Rotary
+
+This is the Arduino code for the old black rotary phone prop
+used in the Theater Ninjas play Turing Machine.
+
+Coded by Eric Faehnrich
+*/
+
+#include <WaveHC.h>
+#include <WaveUtil.h>
+
+enum State {
+  nodial,
+  dialed,
+  done
+};
+
+
+
+SdReader card;    // This object holds the information for the card
+FatVolume vol;    // This holds the information for the partition on the card
+FatReader root;   // This holds the information for the volumes root directory
+FatReader f;      // This holds the information for the file we're play
+WaveHC wave;      // This is the only wave (audio) object, since we will only play one at a time
+
+uint8_t dirLevel; // indent level for file/dir names    (for prettyprinting)
+dir_t dirBuf;     // buffer for directory reads
+
+const int hangPin = 6; //pin for reciever switch. closed (HIGH) when hung up, open (LOW) when off the hook
+
+const int ledPin = 13; //LED pin
+
+int ledState = HIGH;
+int hangState; //current reciever reading
+int lastHangState = LOW; //previous reciever reading
+
+long lastHangDebounceTime = 0;  // the last time the reciever pin was toggled
+const long debounceDelay = 50;    // the debounce time; increase if the output flickers
+
+State dialState = nodial;
+
+void playfile(char *name) {
+  if (wave.isplaying) {
+    wave.stop();
+  }
+
+  if (!f.open(root, name)) {
+    putstring_nl("Couldn't open file ");
+    Serial.print(name);
+    return;
+  }
+
+  if (!wave.create(f)) {
+    putstring_nl("Not a valid WAV"); return;
+  }
+
+  wave.play();
+}
+
+
+void setup() {
+
+  Serial.begin(9600);           // set up Serial library at 9600 bps for debugging
+
+  putstring_nl("\nTest");  // say we woke up!
+
+  putstring("Free RAM: ");       // This can help with debugging, running out of RAM is bad
+  Serial.println(FreeRam());
+
+  //  if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
+  if (!card.init()) {         //play with 8 MHz spi (default faster!)
+    putstring_nl("Card init. failed!");  // Something went wrong, lets print out why
+  }
+
+  // enable optimize read - some cards may timeout. Disable if you're having problems
+  card.partialBlockRead(true);
+
+  // Now we will look for a FAT partition!
+  uint8_t part;
+  for (part = 0; part < 5; part++) {   // we have up to 5 slots to look in
+    if (vol.init(card, part))
+      break;                           // we found one, lets bail
+  }
+  if (part == 5) {                     // if we ended up not finding one  :(
+    putstring_nl("No valid FAT partition!");  // Something went wrong, lets print out why
+  }
+
+  // Lets tell the user about what we found
+  putstring("Using partition ");
+  Serial.print(part, DEC);
+  putstring(", type is FAT");
+  Serial.println(vol.fatType(), DEC);     // FAT16 or FAT32?
+
+  // Try to open the root directory
+  if (!root.openRoot(vol)) {
+    putstring_nl("Can't open root dir!");      // Something went wrong,
+  }
+
+  // Whew! We got past the tough parts.
+  putstring_nl("Files found (* = fragmented):");
+
+  // Print out all of the files in all the directories.
+  root.ls(LS_R | LS_FLAG_FRAGMENTED);
+
+
+  pinMode(hangPin, INPUT);
+  pinMode(ledPin, OUTPUT);
+
+  digitalWrite(ledPin, ledState);
+}
+
+void loop() {
+  int hangReading = digitalRead(hangPin);
+
+  //debounce the reciever switch
+  if (hangReading != lastHangState) {
+    lastHangDebounceTime = millis();
+  }
+
+  if ((millis() - lastHangDebounceTime) > debounceDelay) { //then the bounce settled
+    if (hangReading != hangState) {//then reciever state has changed
+      hangState = hangReading;
+      ledState = hangState;
+
+      if(hangState == LOW) {//if first time off hook, start dial tone
+        dialState = nodial;
+      }
+    }
+  }
+
+  //debounce the reciever switch
+  if (hangReading != lastHangState) {
+    lastHangDebounceTime = millis();
+  }
+
+  if ((millis() - lastHangDebounceTime) > debounceDelay) { //then the bounce settled
+    if (hangReading != hangState) {//then reciever state has changed
+      hangState = hangReading;
+      ledState = hangState;
+
+      if(hangState == LOW) {//if first time off hook, start dial tone
+        dialState = nodial;
+      }
+    }
+  }
+
+  digitalWrite(ledPin, ledState);
+
+
+
+  if(hangState == HIGH) {//then hung up
+    //stop any playback
+    wave.stop();
+    //reset any state
+  }
+  else {//off the hook
+    switch(dialState) {
+      case nodial:
+        if(!wave.isplaying) {//if stopped playing, start again
+          playfile("DIALTONE.WAV");
+        }
+        break;
+    }
+  }
+
+  lastHangState = hangReading;
+}
+


Add arduino code to the repository

Add arduino code to the repository

error: pathspec 'Arduino/fishfeeder.ino' did not match any file(s) known to git

--- Arduino/fishfeeder.ino
+++ Arduino/fishfeeder.ino
@@ -0,0 +1,389 @@
+#include <SoftwareServo.h>
+#include <EEPROM.h>
+
+int pinled = 2;
+int pinservo = 3;
+int pinmotor = 4;
+int pinmotorspeed = 5;
+int pingreen = 10;
+int pinblue = 9;
+int pinred = 11;
+int pincounter1 = A0;
+int pincounter2 = A1;
+int pinbrightness = A2;
+
+const int threshold1 = 200;
+const int threshold2 = 400;
+const int fullrotation = 210;
+const int containers = 28;
+const int motorspeed = 255;
+
+const int servoup = 159;
+const int servodown = 63;
+
+const int address_calibrated = 1;
+const int address_position = 2;
+
+float position = 0.0;
+boolean calibrated = false; // Set true to skip calibration
+
+boolean customcolor = true;
+long timeout = 0;
+
+boolean errorstate = false;
+
+SoftwareServo servo;
+
+void setup() {
+	pinMode(pinled, OUTPUT);
+	pinMode(pinservo, OUTPUT);
+	pinMode(pinmotor, OUTPUT);
+	pinMode(pinmotorspeed, OUTPUT);
+	pinMode(pinred, OUTPUT);
+	pinMode(pingreen, OUTPUT);
+	pinMode(pinblue, OUTPUT);
+	pinMode(pincounter1, INPUT);
+	pinMode(pincounter2, INPUT);
+	pinMode(pinbrightness, INPUT);
+	setcolor(0,0,0);
+
+	Serial.begin(9600);
+
+	servo.attach(pinservo);
+	servo.write(servoup);
+
+	if (EEPROM.read(address_calibrated) == 1) {
+		calibrated = true;
+		position = (float)EEPROM.read(address_position) * (float)containers / (float)fullrotation;
+	}
+
+	for (int i = 0; i < 255; i++) {
+		setcolor(0,(int)(256.0 * pow((double)i / 256.0, 5)),0);
+		delayandrefresh(5);
+	}
+
+	for (int i = 0; i < 3; i++) {
+		delay(200);
+		if (calibrated)
+			setcolor(0,255,0);
+		else setcolor(100,255,0);
+		delay(200);
+		setcolor(0,0,0);
+	}
+}
+
+void saveposition() {
+	EEPROM.write(address_calibrated, 1);
+	EEPROM.write(address_position, (byte)(position * (float)fullrotation / (float)containers));
+}
+
+void setcolor(int r, int g, int b) {
+	analogWrite(pinred, 255 - r);
+	analogWrite(pingreen, 255 - g);
+	analogWrite(pinblue, 255 - b);
+}
+
+int getCounter1() {
+	digitalWrite(pinled, true);
+	delay(1);
+	int value = analogRead(pincounter1);
+	digitalWrite(pinled, false);
+	digitalWrite(pinred, value < threshold1);
+	digitalWrite(pingreen, value < threshold1);
+	return value;
+}
+
+int getCounter2() {
+	digitalWrite(pinled, true);
+	delay(1);
+	int value = analogRead(pincounter2);
+	digitalWrite(pinled, false);
+	return value;
+}
+
+void startMotor(int v) {
+	EEPROM.write(address_calibrated, 0);
+	digitalWrite(pinmotor, true);
+	digitalWrite(pinmotorspeed, v);
+}
+
+void stopMotor(boolean brake) {
+	digitalWrite(pinmotorspeed, 0);
+
+	if (brake) {
+		digitalWrite(pinmotor, true);
+		delay(200);
+	}
+	digitalWrite(pinmotor, false);
+}
+
+boolean rotate(int r, boolean brake) {
+	startMotor(motorspeed);
+	const int cooldown1 = 200;
+	long last1 = millis();
+
+	while (getCounter1() > threshold1) {
+		delay(40);
+		if (millis() > last1 + 1000) {
+			errorstate = true;
+			stopMotor(false);
+			return false;
+		}
+	}
+
+	while (r > 0) {
+		int v = getCounter1();
+		if (v > threshold1 && last1 + cooldown1 < millis()) {
+			r--;
+			Serial.write(20 + r);
+			last1 = millis();
+		}
+		if (millis() > last1 + 1000) {
+			errorstate = true;
+			stopMotor(false);
+			return false;
+		}
+	}
+	stopMotor(brake);
+	setcolor(0,0,0);
+	return true;
+}
+
+void findstart() {
+	Serial.write(16);
+
+	long last1 = millis();
+	long start = millis();
+	int progress = fullrotation;
+
+	startMotor(motorspeed);
+	while (getCounter2() > threshold2 || millis() < start + 10000) {
+		if ((getCounter1() > threshold1)) {
+			if (millis() > last1 + 200) {
+				last1 = millis();
+				progress--;
+				Serial.write(20 + progress);
+			}
+		}
+		else setcolor(0, 255, 0);
+
+		if (getCounter2() < threshold2)
+			progress = fullrotation;
+
+		if (millis() > last1 + 2000) {
+			calibrated = false;
+			errorstate = true;
+			Serial.write(20);
+			stopMotor(false);
+			return;
+		}
+		delay(10);
+	}
+	rotate(2, true);
+
+	position = 0;
+	calibrated = true;
+
+	Serial.write(20);
+	saveposition();
+}
+
+boolean gotocontainer(int n) {
+	if (errorstate)
+		return false;
+	if (!calibrated)
+		findstart();
+	if (errorstate)
+		return false;
+
+	int p = (int)position;
+	if (n < p) n += containers;
+	return skipcontainer(n - p);
+}
+
+boolean skipcontainer(int n) {
+	if (errorstate)
+		return false;
+	//Serial.print("pos: "); Serial.print(position); Serial.print(" - maxr: ");
+	float maxr = (float)n * (float)fullrotation / containers;
+	//Serial.print(maxr); Serial.print(" - corrected: ");
+	maxr += (- position + floor(position)) * (float)fullrotation / containers;
+	//Serial.print(maxr); Serial.print(" - r: ");
+	int r = (int)maxr + 1;
+	//Serial.print(r);	Serial.println();
+	position += (float)r * (float)containers / fullrotation;
+	if (position > containers) position -= (float)containers;
+
+	boolean result = rotate(r, true);
+	saveposition();
+
+	return result;
+}
+
+void delayandrefresh(int t) {
+	long end = millis() + t;
+	while (millis() < end)
+		SoftwareServo::refresh();
+}
+
+void flush() {
+	setcolor(128,0,200);
+	servo.write(servodown);
+	delayandrefresh(600);
+	servo.write(servoup);
+
+	delayandrefresh(1000);
+	servo.write(servodown);
+	delayandrefresh(2000);
+	servo.write(servoup);
+
+	setcolor(0,0,0);
+	delayandrefresh(600);
+}
+
+void checkserial() {
+	const int confirm = 13;
+	int requestshandled = 0;
+	if (Serial.available()) {
+		while(Serial.available()) {
+			requestshandled++;
+			byte command = Serial.read();
+			if (command != 105)
+				setcolor(0,0,255);
+			delay(20);
+			setcolor(0,0,0);
+			switch (command) {
+				case 100: { // Move
+					if (!Serial.available()) return;
+					int pos = Serial.read();
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					Serial.write(14);
+					if (!gotocontainer(pos))
+						Serial.write(1);
+					break;
+				}
+				case 101: { // Move relative
+					if (!Serial.available()) return;
+					int pos = Serial.read();
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					Serial.write(14);
+					if (!skipcontainer(pos))
+						Serial.write(1);
+					break;
+				}
+				case 102: { // Flush
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					Serial.write(15);
+					flush();
+					break;
+				}
+				case 103: { // Move & Flush
+					if (!Serial.available()) return;
+					int pos = Serial.read();
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					Serial.write(14);
+					if (!gotocontainer(pos)) {
+						Serial.write(1);
+						break;
+					}
+					Serial.write(15);
+					flush();
+					break;
+				}
+				case 104: { // Calibrate
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					findstart();
+					if (!calibrated)
+						Serial.write(1);
+					break;
+				}
+				case 105: { // Set color
+					if (!Serial.available()) return;
+					int r = Serial.read();
+					if (!Serial.available()) return;
+					int g = Serial.read();
+					if (!Serial.available()) return;
+					int b = Serial.read();
+					if (!Serial.available()) return;
+					int t = Serial.read();
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					setcolor(r,g,b);
+					customcolor = true;
+					timeout = millis() + t * 100;
+					break;
+				}
+				case 106: { // Get brightness
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					byte v = analogRead(pinbrightness) / 4;
+					Serial.write(v);
+					break;
+				}
+				case 107: { // Get position
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					byte v = (int)position;
+					Serial.write(v);
+					break;
+				}
+				case 108: { // Get ping
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					break;
+				}
+				case 109: { // Get calibrated
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					if (calibrated) Serial.write(1);
+						else Serial.write(0);
+					break;
+				}
+				case 110: { // Set calibrated
+					if (!Serial.available()) return;
+					boolean v = Serial.read() == 1;
+					if (Serial.read() != confirm) return;
+					calibrated = v;
+					break;
+				}
+				case 111: { // Get error state
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					Serial.write(errorstate);
+					break;
+				}
+				case 112: { // Set error state
+					if (!Serial.available()) return;
+					if (Serial.read() != confirm) return;
+					errorstate = false;
+					break;
+				}
+				default: { // Red light
+					requestshandled--;
+					setcolor(255,0,0);
+					delay(500);
+					setcolor(0,0,0);
+					while (Serial.available())
+						Serial.read();
+				}
+			}
+		}
+		if (!errorstate && requestshandled != 0)
+			Serial.write(confirm);
+	}
+}
+
+void loop() {
+	checkserial();
+	if (customcolor && timeout < millis()) {
+		customcolor = false;
+		setcolor(0,0,0);
+	} else if (errorstate) {
+		setcolor(millis() % 1000 < 200 ? 255 : 0, 0, 0);
+	}
+}


ok, wait and info is definitively different …

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/trinamic/T-Bone.git/'


Init for new nodes (esp8266)

Init for new nodes (esp8266)

- this is for the first connect to a access point

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/glumanda/nodes_at_home.git/'


Arduino Sketch to read distance sensor and send result over serial.

error: pathspec 'ArduinoDistance/ArduinoDistance.ino' did not match any file(s) known to git

--- ArduinoDistance/ArduinoDistance.ino
+++ ArduinoDistance/ArduinoDistance.ino
@@ -0,0 +1,27 @@
+#include <EVShield.h>
+#include <EVs_EV3Ultrasonic.h>
+#include <LiquidCrystal.h>
+#include <Wire.h>
+
+EVShield evshield(0x34, 0x36);
+EVs_EV3Ultrasonic ultrasonicSensor;
+LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
+
+void setup() {
+  evshield.init(SH_HardwareI2C);
+  ultrasonicSensor.init(&evshield, SH_BAS1);
+  ultrasonicSensor.setMode(MODE_Sonar_CM);
+  lcd.clear();
+  Serial.begin(115200);
+}
+
+void loop() {
+  double distance = ultrasonicSensor.getDist();
+  lcd.clear();
+  lcd.print("Distance:");
+  lcd.print(distance);
+  Serial.print("[Distance:");
+  Serial.print(distance);
+  Serial.println("]");
+  delay(1000);
+}


Added more testing code

Added more testing code

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/snowdenator/EarlHomeAutomation.git/'


Moved comment.

Moved comment.

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/FirstBuild/pizzaduino.git/'


Switch LED pins, print warning if wrong MCU is selected

error: pathspec 'arduino/Test' did not match any file(s) known to git
error: pathspec 'sketches/HandshakeTester/HandshakeTester.ino' did not match any file(s) known to git


Added quick example to show reading a Pot as a slave

error: pathspec 'examples/ReadPOT_ArduinoSlave/ReadPOT_ArduinoSlave.ino' did not match any file(s) known to git

--- examples/ReadPOT_ArduinoSlave/ReadPOT_ArduinoSlave.ino
+++ examples/ReadPOT_ArduinoSlave/ReadPOT_ArduinoSlave.ino
@@ -0,0 +1,31 @@
+/* Read a Potentiometer on Analog input 0 and store in local buffer waiting for Amulet to request the data.
+*  To make Amulet request the proper variable, place this command in a view widget's (bargraph, numericField, etc) Href in GEmstudio:
+*  Amulet:uart1.word(0).value()
+*/ For other ports, change uart1 to your selected port.
+
+#include <AmuletLCD.h>
+
+#define VDP_SIZE 32
+//Virtual Dual Port memory used for communicating with Amulet Display
+uint16_t AmuletWords[VDP_SIZE]  = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+AmuletLCD myModule;
+
+void setup() {
+  //start communication with Amulet Display at default baud
+  myModule.begin(115200);
+  //register our local buffer with Amulet state machine
+  myModule.setWordPointer(AmuletWords,VDP_SIZE);
+}
+
+void loop() {
+  //store analog data in local buffer and wait for Amulet to poll that buffer.
+  AmuletWords[0] = analogRead(0);
+  delay(100);
+}
+
+//This method automatically gets called if there is any serial data available
+//http://www.arduino.cc/en/Tutorial/SerialEvent
+void serialEvent() {
+    myModule.serialEvent();  //send any incoming data to the Amulet state machine
+}