Code for the Spinner - I2C
I2C is a 2 wire interface to connect devices and uses a data (SDA) and clock line (SCL). You have a main controller which sets up a line and sends / receives messages to node follower controllers on the line which have addresses.
The main controller can't tell what order the nodes are connected on so although the hubs are identical, they can't be connected in any order as I planned initially.
The main controller is a rp2040 and the node controllers are ATTiny 412. In order to code the 412 you want to use the legacy Arduino ide.
To begin with I went through and tested all the inputs on the controller using its led.
Code to test the potentiometers.
int const potPin = A1; // analog pin used to connect the potentiometer, A0 or A1 int const ledPin = 29; int potVal; // variable to read the value from the analog pin int bright; // variable to hold the angle for the servo motor void setup() { pinMode(ledPin, OUTPUT); } void loop() { potVal = analogRead(potPin); // read the value of the potentiometer // scale the numbers from the pot bright = map(potVal, 0, 1023, 0, 255); // set brightness analogWrite(ledPin, bright); delay(15); }
Code to test the switches
const int buttonPin = 1; // the number of the pushbutton pin const int buttonPintwo = 2; // the number of the pushbutton pin const int ledPin = 29; // the number of the LED pin int buttonState = 0; // variable for reading the pushbutton status int buttonStatetwo = 0; // variable for reading the pushbutton status void setup() { // initialize the LED pin as an output: pinMode(ledPin, OUTPUT); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT_PULLUP); // initialize the pushbutton pin as an input: pinMode(buttonPintwo, INPUT_PULLUP); } void loop() { // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); buttonStatetwo = digitalRead(buttonPintwo); // check if the pushbutton is pressed. If it is, the buttonState is HIGH: if (buttonState == HIGH) { // turn LED off: digitalWrite(ledPin, HIGH); } else { // turn LED on: digitalWrite(ledPin, LOW); } if (buttonStatetwo == HIGH) { // turn LED off: digitalWrite(ledPin, HIGH); } else { // turn LED on: digitalWrite(ledPin, LOW); } }
I then connected one node board to the main controller so I could test the potentiometer controlling the led on the nodes board.
The value the from the potentiometer 0-1023 was mapped between the 0-255 brightness value of the led. This is then sent along the wire to the node address connected to the clock and data lines.
Code for the main controller - one node, led control
#includeconst int nodeAddress = 1; const int potenPin = A0; int potVal; int bright; void setup() { Wire.begin(); Serial.begin( 9600 ); } void loop() { potVal = analogRead(potenPin); bright = map(potVal, 0, 1023, 0, 255); Wire.beginTransmission(nodeAddress); Wire.write(bright); Wire.endTransmission(); }
The node controller one passes the value through to the esc, it does not do any calculations or specific actions other than its set address. This means this code does not change much. The 'Wire.begin(1)' sets up which address it responds to.
The node boards are coded using updi.
Node code for led.
#includeint ledPin = 1; void setup() { pinMode (ledPin, OUTPUT); Wire.begin(1); Wire.onReceive(receiveEvent); } void loop(){ } void receiveEvent( int howMany ) { int bright = Wire.read(); analogWrite(ledPin, bright); }
Now I added the second node board with the code to dim the second led separately. This will be slowing down the second motor in the final code which is necessary for spinning.
We also have a check to make sure the value doesn't make the breaking value doesn't go negative.
Two nodes and difference control
#includeconst int nodeAddress = 1; const int node2Address = 2; const int potenPin = A0; const int poten2Pin = A1; int potVal; int pot2Val; int bright; int differ; int breaking; void setup() { Wire.begin(); Serial.begin( 9600 ); } void loop() { potVal = analogRead(potenPin); bright = map(potVal, 0, 1023, 10, 255); pot2Val = analogRead(poten2Pin); differ = map(pot2Val, 0, 1023, 1, 127); breaking = bright-differ; if (breaking < 0) { breaking = 0; } Wire.beginTransmission(nodeAddress); Wire.write(bright); Wire.endTransmission(); Wire.beginTransmission(node2Address); Wire.write(breaking); Wire.endTransmission(); }
Node code
#includeint ledPin = 1; int bright = 0; void setup() { pinMode (ledPin, OUTPUT); Wire.begin(1); Wire.onReceive(receiveEvent); } void loop(){ analogWrite(ledPin, bright); delay (10); } void receiveEvent( int howMany ) { bright = Wire.read(); }
#includeint ledPin = 1; int bright = 0; void setup() { pinMode (ledPin, OUTPUT); Wire.begin(2); Wire.onReceive(receiveEvent); } void loop() { analogWrite(ledPin, bright); delay (10); } void receiveEvent( int howMany ) { bright = Wire.read(); }
Motor working.
Final Code
We went through a few iterations and changes but here is the final code.
When you first set up the esc you calibrate the thresholds between neutral, forward max, and backwards max. You turn the potentiometer to certain points to mark these. As this involves some leeway the thresholds for the two motors are slightly different so we have two variables for the different motor set ups.
The about of breaking is a fraction on the current speed which means it scales with the speed instead of a fixed range.
#includeconst int nodeAddress = 1; const int node2Address = 2; const int potenPin = A0; const int poten2Pin = A1; const int pausePin = 2; const int dirPin = 1; const int ledPin = 29; const int threshold = 67; const int threshold2 = 65; const int breakingratio = 10; //percentage of speed int potVal; int pot2Val; int speed1; // speed of motor 1 range 0-1000 int speed2; // speed of motor 1 - difference range 0-1000 int speedpot; int differpot; int motor1; int motor2; int pauseState = 0; int dirState = 0; void setup() { analogWrite(ledPin, 255); Wire.begin(); pinMode(pausePin, INPUT_PULLUP); pinMode(dirPin, INPUT_PULLUP); Serial.begin(9600); } void loop() { // potentiometer set up potVal = analogRead(potenPin); speedpot = map(potVal, 0, 1023, 0, 1000); //Serial.println(bright); pot2Val = analogRead(poten2Pin); differpot = map(pot2Val, 0, 1023, 0, speedpot/breakingratio); // pause check pauseState = digitalRead(pausePin); dirState = digitalRead(dirPin); if (pauseState == LOW) { Wire.beginTransmission(nodeAddress); Wire.write(threshold); // whatever the mid point angle is Wire.endTransmission(); //Serial.println(threshold); Wire.beginTransmission(node2Address); Wire.write(threshold2); // whatever the mid point angle is Wire.endTransmission(); //Serial.println(threshold, threshold2); } else if (dirState == HIGH) { // forward speed1 = speedpot; speed2 = speedpot - differpot; if (speed2 < 0) { speed2 = 0; } Serial.print("speed1 "); Serial.print(speed1); Serial.print(" speed2 "); Serial.print(speed2); motor1 = map(speed1, 0, 1000, threshold, threshold+20); motor2 = map(speed2, 0, 1000, threshold2, threshold2+20); Wire.beginTransmission(nodeAddress); Wire.write(motor1); Wire.endTransmission(); Serial.print(" motor1 "); Serial.print(motor1); Wire.beginTransmission(node2Address); Wire.write(motor2); Wire.endTransmission(); Serial.print(" motor2 "); Serial.println(motor2); } else if (dirState == LOW) { //backwards speed1 = speedpot; speed2 = speedpot + differpot; if (speed2 < 0) { speed2 = 0; } Serial.print("speed1 "); Serial.print(speed1); Serial.print(" speed2 "); Serial.print(speed2); motor1 = map(speed1, 0, 1000, threshold, threshold-20); //whatever forward angle range is motor2 = map(speed2, 0, 1000, threshold2, threshold2-20); Wire.beginTransmission(nodeAddress); Wire.write(motor1); Wire.endTransmission(); Serial.print(" motor1 "); Serial.print(motor1); Wire.beginTransmission(node2Address); Wire.write(motor2); Wire.endTransmission(); Serial.print(" motor2 "); Serial.println(motor2); } }
Node codes.
#include#include Servo myServo; int ledPin = 1; int angle; void setup() { pinMode (ledPin, OUTPUT); myServo.attach(0); Wire.begin(1); Wire.onReceive(receiveEvent); } void loop() { analogWrite(ledPin, 255); myServo.write(angle); delay (10); } void receiveEvent( int howMany ) { angle = Wire.read(); }
#include#include Servo myServo; int ledPin = 1; int angle; void setup() { pinMode (ledPin, OUTPUT); myServo.attach(0); Wire.begin(2); Wire.onReceive(receiveEvent); } void loop() { analogWrite(ledPin, 255); myServo.write(angle); delay (10); } void receiveEvent( int howMany ) { angle = Wire.read(); }
In the future I want to investigate different ways of setting up the servo library as the backwards range did not have enough detail in the number of angles it was allocated so did not have a slow enough range. However, it is possible to increase the range.