Content:
LEDs
Hardware Behavior
LED Brightness
There are two ways to control brightness of LED.-
Analog
It sounds simple - dynamically change voltage (analog) output. As simple as it may sound, processors are all digital and Digital -> Analog are very expensive (compared to Analog -> Digital which is done by multiple resistors of different value). -
Digital Pulse-width Modulation
Pulse-width Modulation (PWM) is way to fake "analog" on digital pin.
Our eyes are not perfect and we can use it for our advantage. If you have a LED blinking fast enough, your eyes will see it glowing instead of blinking. This is used by LED Monitors (LED Matrix) - only 1 led is glowing at a time.
When we know this trick, we can abuse it by PWM. As we know from Virtual Reality, 60 Hz is enough, 90 Hz is good (for displays). You can test it yourself, but for single LED, 20 Hz is enough to fake our eyes but will be visible on a camera. That is why I recommend using 60 Hz.
RGB LED
When we know how to change brightness of single LED, let's do it with 3. To be more specific - Red, Green and Blue LEDs. To be even more specific - single RGB LED because RGB LEDs are 3 LEDs in 1 chasing with shared ground.LED's RGB works same as HTML/CSS color codes. #ffffff is white, #000000 is black, #ff0000 is red...
To select right color, you can try w3schools.com's HTML Color Picker or RGB Color Table.
Software Code
#define PIN_RED 0
#define PIN_GREEN 1
#define PIN_BLUE 2
void setup()
{
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
}
First we need to define our pins.
Own Pulses
To truly understand pulses, let's first write our own. So we can start with a "simple" function.void performPulse(int pin, float active, int totalMicroseconds)
{
}
This function has to arguments. First is target (digital) pin, second ranges from 0.0 to 1.0 and last must me greater then 0 and is in μs (microseconds).
digitalWrite(pin, HIGH);
int activeMicroseconds = (int)(active * totalMicroseconds);
delayMicroseconds(activeMicroseconds);
digitalWrite(pin, LOW);
delayMicroseconds(totalMicroseconds - activeMicroseconds);
We simply calculate activeMicroseconds
by multiplying totalMicroseconds
by active
and flooring the result (by converting to int).During this time, the
pin
will be HIGH
and rest of time (totalMicroseconds - activeMicroseconds
) it will be LOW
(and it will leave function in the LOW
state).float Red = 1.0f;
float Green = 0.3f;
float Blue = 0.1f;
#define frequency 60
#define period 1/frequency
void loop()
{
performPulse(PIN_RED, Red, period);
performPulse(PIN_GREEN, Green, period);
performPulse(PIN_BLUE, Blue, period);
}
Before lighting up the RGB LED, we need to define it's values. For our purpose, leaving them static is enough (but you can create some
for()
loops).Second thing to define are
frequency
(blinks per second), period
(duration of one pulse) and periodOneColor
(duration of one color of pulse).Whole code
#define PIN_RED 0
#define PIN_GREEN 1
#define PIN_BLUE 2
void setup()
{
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
}
// pin = target pin
// active = 0.0 to 1.0, "percentage" of active time
// totalMicroseconds = >0, 1 000 000 μs = 1s
void performPulse(int pin, float active, int totalMicroseconds)
{
digitalWrite(pin, HIGH);
int activeMicroseconds = (int)(active * totalMicroseconds);
delayMicroseconds(activeMicroseconds);
digitalWrite(pin, LOW);
delayMicroseconds(totalMicroseconds - activeMicroseconds);
}
// Static color definition
float Red = 1.0f;
float Green = 0.3f;
float Blue = 0.1f;
// Timing of our pulses
const int frequency = 30;
const int period = 1 / frequency;
const int periodOneColor = period / 3;
void loop()
{
performPulse(PIN_RED, Red, periodOneColor);
performPulse(PIN_GREEN, Green, periodOneColor);
performPulse(PIN_BLUE, Blue, periodOneColor);
}
Arduino's PWM
Second way to make pulses (and mostly better) is Arduino's Pulse-width Modulation. It adds "simple" functionanalogWrite()
which takes 2 parameters - pin (PWN only) and value (0-255).Problem is with pins which you can find in description of the function and I will quote some.
On most Arduino boards, this function works on pins 3, 5, 6, 9, 10, and 11. On the Arduino Mega, it works on pins 2 - 13 and 44 - 46.
The frequency of the PWM signal on most pins is approximately 490 Hz. On the Uno and similar boards, pins 5 and 6 have a frequency of approximately 980 Hz. Pins 3 and 11 on the Leonardo also run at 980 Hz.
While keeping this in mind, we need to change our pins.
Above you can see pins 3, 5, 6, 9, 10 and 11. It is total of 6 but Micro has 7 PWM Outputs so I looked at my Leonardo (I currently do not have Micro but Leonarho has same microcontroller (ATmega32u4) ) and discovered the 7th pin to be pin 13 (all PMW pins have
~
as prefix).
#define PIN_RED 9
#define PIN_GREEN 10
#define PIN_BLUE 11
void setup()
{
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
}
We can remove our own function (
performPule()
) and both frequency
and period
variables.There is also no need for
loop()
function because we can place analogWrite()
into setup
(we must move our colors above it).Whole code
#define PIN_RED 9
#define PIN_GREEN 10
#define PIN_BLUE 11
// Static color definition
byte Red = 255;
byte Green = 256;
byte Blue = 64;
void setup()
{
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_RED, Red);
analogWrite(PIN_GREEN, Green);
analogWrite(PIN_BLUE, Blue);
}
void loop()
{
delay(1000);// To reduce power usage
}
Yes, there is no need for storing the color once we set it but I see no problem with it (and may be used later).
Two LEDs
Because Fursuit has two eyes and we want to change both eyes independently which means to use two LEDs.#define PIN_LED_0_RED 3
#define PIN_LED_0_GREEN 5
#define PIN_LED_0_BLUE 6
#define PIN_LED_1_RED 9
#define PIN_LED_1_GREEN 10
#define PIN_LED_1_BLUE 11
// Static color definition
byte Led_0_Red = 255;
byte Led_0_Green = 128;
byte Led_0_Blue = 64;
byte Led_1_Red = 255;
byte Led_1_Green = 128;
byte Led_1_Blue = 64;
void setup()
{
{
pinMode(PIN_LED_0_RED, OUTPUT);
pinMode(PIN_LED_0_GREEN, OUTPUT);
pinMode(PIN_LED_0_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
pinMode(PIN_LED_1_RED, OUTPUT);
pinMode(PIN_LED_1_GREEN, OUTPUT);
pinMode(PIN_LED_1_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
}
void loop()
{
delay(1000);// To reduce power usage
}
It is just duplicating the code.
Communication
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
Communication.begin(115200);
void CommunicationEvent()
{
}
As usual, we add code for detection of Serial, start it in
setup
and create event on data receive.void CommunicationEvent()
{
if(Communication.available() < 3 * 2)
return;
{
Led_0_Red = Communication.read();
Led_0_Green = Communication.read();
Led_0_Blue = Communication.read();
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
Led_1_Red = Communication.read();
Led_1_Green = Communication.read();
Led_1_Blue = Communication.read();
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
}
The code for communication is straightforward. Just read values from Serial and set them on pins.
Whole code:
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
#define PIN_LED_0_RED 3
#define PIN_LED_0_GREEN 5
#define PIN_LED_0_BLUE 6
#define PIN_LED_1_RED 9
#define PIN_LED_1_GREEN 10
#define PIN_LED_1_BLUE 11
// Static color definition
byte Led_0_Red = 255;
byte Led_0_Green = 128;
byte Led_0_Blue = 64;
byte Led_1_Red = 255;
byte Led_1_Green = 128;
byte Led_1_Blue = 64;
void setup()
{
{
pinMode(PIN_LED_0_RED, OUTPUT);
pinMode(PIN_LED_0_GREEN, OUTPUT);
pinMode(PIN_LED_0_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
pinMode(PIN_LED_1_RED, OUTPUT);
pinMode(PIN_LED_1_GREEN, OUTPUT);
pinMode(PIN_LED_1_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
}
void CommunicationEvent()
{
if(Communication.available() < 3 * 2)
return;
{
Led_0_Red = Communication.read();
Led_0_Green = Communication.read();
Led_0_Blue = Communication.read();
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
Led_1_Red = Communication.read();
Led_1_Green = Communication.read();
Led_1_Blue = Communication.read();
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
}
void loop()
{
delay(1000);// To reduce power usage
}
Servos
Servos are small motors with gears designed for Radio-Controlled Models.Protocol
The protocol is designed to be "easy to implement" and (mainly) to set rotation instead of telling it how much to rotate in which direction (so it may not receive all data and still keep precision).It is from 1 to 2 ms pulse every 20 ms. It means 1ms pulse is one edge of rotation, 2ms is the other. It also means that we can use 10 servos at a time.
On image above you can see the pulse and its "timeframe". As you may guess, the bold bottom line is our time and we are operating in 20ms frames.
At start of the frame we set our servo pin to
HIGH
and keep it that way for at least 1ms. Then anywhere in the gray time (including 1ms and 2ms) we can drop it to LOW
.To control 2 servos, we delay 2nd frame by 2ms which means independently on 1st servo, our 2nd servo will be set to
HIGH
after 1st servo was set to HIGH
"exactly" by 2ms.I was testing my servos which I have at home (after playing with RC models) and it does not depend on exact timing - it just calculates delay of the pulse, rotate its motor and looking for another pulse.
Implementation
I already described it in Protocol so it may be easy.One Servo
#define PIN_DATA 0
void setup()
{
pinMode(PIN_DATA, OUTPUT);
}
As always, we start with our pin.
void pulseServo(int pin, float angle)
{
}
We will also need (use) function which will take pin of our servo and its requested rotation (0.0 to 1.0).
int pulseTime = 1000 + angle * 1000;
int pulseWait = 2000 - pulseTime;
digitalWrite(pin, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(pin, LOW);
delayMicroseconds(pulseWait);
The code itself is simple - we calculate our time (in microseconds) with minimum 1000 and maximum 2000.
void loop()
{
pulseServo(PIN_DATA, 0.0f);
delay(18);
}
The code to keep servo on specific value is easy. Let's try something "harder".
float servo_angle = 0.0f;
void loop()
{
servo_angle += 0.06f;
if(servo_angle >= 2)
servo_angle -= 2;
if(servo_angle <= 1)
pulseServo(PIN_DATA, servo_angle);
else
pulseServo(PIN_DATA, 2 - servo_angle);
delay(18);
}
This code will rotate servo to one edge (servo_angle: 0.0 - 1.0), then to the other (servo_angle: 1.0 - 2.0) and back again in a loop.
You can change the
servo_angle += 0.06f;
but this is maximum value for my servo (bigger value has problem reaching servo's limits).Whole code:
#define PIN_DATA 0
void setup()
{
pinMode(PIN_DATA, OUTPUT);
}
void pulseServo(int pin, float angle)
{
//calculating timing of pulse in μs
int pulseTime = 1000 + angle * 1000;
int pulseWait = 2000 - pulseTime;
digitalWrite(pin, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(pin, LOW);
delayMicroseconds(pulseWait);
}
float servo_angle = 0.0f;
void loop()
{
// step each "tick" (20ms)
servo_angle += 0.06f;
if(servo_angle >= 2)
servo_angle -= 2;
// deciding our current rotation
if(servo_angle <= 1)
pulseServo(PIN_DATA, servo_angle);
else
pulseServo(PIN_DATA, 2 - servo_angle);
// rest 9 servos time (space)
delay(18);
}
Servo Limits
We are currently limiting our servo by its own limits which are 1.0 ms and 2.0 ms.Sometimes we might want to limit them from 1.0 ms to 1.5ms or from 1.3 ms to 1.7 ms to get different angle of movement.
#define SERVO_MIN 1000
#define SERVO_MAX 2000
#define SERVO_RANGE (SERVO_MAX-SERVO_MIN)
int pulseTime = SERVO_MIN + angle * SERVO_RANGE;
Do not forget the bracers in
SERVO_RANGE
because otherwise it will be int pulseTime = angle * SERVO_MAX
because it first multiplies angle
with SERVO_MAX
.To change limits, modify
SERVO_MIN
and SERVO_MAX
but keep them in range (min 1000, max 2000) and SERVO_MIN < SERVO_MAX
.Whole code:
#define PIN_DATA 0
void setup()
{
pinMode(PIN_DATA, OUTPUT);
}
#define SERVO_MIN 1000
#define SERVO_MAX 2000
#define SERVO_RANGE (SERVO_MAX-SERVO_MIN)
void pulseServo(int pin, float angle)
{
//calculating timing of pulse in μs
int pulseTime = SERVO_MIN + angle * SERVO_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(pin, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(pin, LOW);
delayMicroseconds(pulseWait);
}
float servo_angle = 0.0f;
void loop()
{
// step each "tick" (20ms)
servo_angle += 0.06f;
if(servo_angle >= 2)
servo_angle -= 2;
// deciding our current rotation
if(servo_angle <= 1)
pulseServo(PIN_DATA, servo_angle);
else
pulseServo(PIN_DATA, 2 - servo_angle);
// rest 9 servos time (space)
delay(18);
}
Speed Limitation
Another thing which we can limit is speed but it is problematic because only takes target rotation and no speed.That means we need to rewrite some code.
float angle = 0.0;
void pulseServo()
{
//calculating timing of pulse in μs
int pulseTime = SERVO_MIN + angle * SERVO_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_DATA, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_DATA, LOW);
delayMicroseconds(pulseWait);
}
First we want to change some code...
void loop()
{
pulseServo();
...and call it at begining of the loop. Now we only need to change
angle
to move servo.float target_angle = 0.0;
float angle_step = 0.06;
void recalculateServo()
{
if(angle != target_angle)
{
if(angle < target_angle)
angle = max(target_angle, angle + angle_step);
else // angle > target_step
angle = min(target_angle, angle - angle_step);
}
}
To move servo my small steps (causing it to change speed), we need to a function which will increase our current angle (pulse width).
void loop()
{
pulseServo();
recalculateServo();
}
We will also call the function in the
loop()
.Also, we can remove
servo_angle
because we don't need / use it anymore.
Communication
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
void setup()
{
Communication.begin(115200);
}
We first need to define our Serial as it can be found in Communication Protocol.
#define PIN_DATA 2
Do not forget to change your
PIN_DATA
(I changed mine to 2). Pins 0 (RX) and 1 (TX) are used for Serial communication.void CommunicationEvent()
{
}
We use event triggered on receiving data on Serial.
void CommunicationEvent()
{
if(Communication.available() < 2)
return;
// byte 0 - rotation angle
target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
angle_step = Communication.read() / 255.0f;
}
Yes, higher values are not usable so let's fix it.
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
angle_step = 1.0f;
else
angle_step = speed / 255.0f / 10.0f
Maximum step size is 0.1 (1.0 / 10) or full (1.0) for 255.
Nine Servos
We can use 10 servos but the Fursuit is (currently) designed to use only 9 which gives us 2ms "free time".In the "free time" we can just
delay(2)
(which we will) or calculate it more preciously to get better 20ms in total which is not needed at all because we don't need that precision.First, we need to add all 9 servos (0-8) which is renaming all of servo variables.
#define PIN_SERVO_0 2
#define PIN_SERVO_1 3
#define PIN_SERVO_2 4
#define PIN_SERVO_3 5
#define PIN_SERVO_4 6
#define PIN_SERVO_5 7
#define PIN_SERVO_6 8
#define PIN_SERVO_7 9
#define PIN_SERVO_8 10
pinMode(PIN_SERVO_0, OUTPUT);
pinMode(PIN_SERVO_1, OUTPUT);
pinMode(PIN_SERVO_2, OUTPUT);
pinMode(PIN_SERVO_3, OUTPUT);
pinMode(PIN_SERVO_4, OUTPUT);
pinMode(PIN_SERVO_5, OUTPUT);
pinMode(PIN_SERVO_6, OUTPUT);
pinMode(PIN_SERVO_7, OUTPUT);
pinMode(PIN_SERVO_8, OUTPUT);
#define SERVO_0_MIN 1000
#define SERVO_0_MAX 2000
#define SERVO_0_RANGE (SERVO_0_MAX-SERVO_0_MIN)
#define SERVO_1_MIN 1000
#define SERVO_1_MAX 2000
#define SERVO_1_RANGE (SERVO_1_MAX-SERVO_1_MIN)
#define SERVO_2_MIN 1000
#define SERVO_2_MAX 2000
#define SERVO_2_RANGE (SERVO_2_MAX-SERVO_2_MIN)
#define SERVO_3_MIN 1000
#define SERVO_3_MAX 2000
#define SERVO_3_RANGE (SERVO_3_MAX-SERVO_3_MIN)
#define SERVO_4_MIN 1000
#define SERVO_4_MAX 2000
#define SERVO_4_RANGE (SERVO_4_MAX-SERVO_4_MIN)
#define SERVO_5_MIN 1000
#define SERVO_5_MAX 2000
#define SERVO_5_RANGE (SERVO_5_MAX-SERVO_5_MIN)
#define SERVO_6_MIN 1000
#define SERVO_6_MAX 2000
#define SERVO_6_RANGE (SERVO_6_MAX-SERVO_6_MIN)
#define SERVO_7_MIN 1000
#define SERVO_7_MAX 2000
#define SERVO_7_RANGE (SERVO_7_MAX-SERVO_7_MIN)
#define SERVO_8_MIN 1000
#define SERVO_8_MAX 2000
#define SERVO_8_RANGE (SERVO_8_MAX-SERVO_8_MIN)
float servo_0_angle = 0.0;
float servo_0_target_angle = 0.0;
float servo_0_angle_step = 0.06;
float servo_1_angle = 0.0;
float servo_1_target_angle = 0.0;
float servo_1_angle_step = 0.06;
float servo_2_angle = 0.0;
float servo_2_target_angle = 0.0;
float servo_2_angle_step = 0.06;
float servo_3_angle = 0.0;
float servo_3_target_angle = 0.0;
float servo_3_angle_step = 0.06;
float servo_4_angle = 0.0;
float servo_4_target_angle = 0.0;
float servo_4_angle_step = 0.06;
float servo_5_angle = 0.0;
float servo_5_target_angle = 0.0;
float servo_5_angle_step = 0.06;
float servo_6_angle = 0.0;
float servo_6_target_angle = 0.0;
float servo_6_angle_step = 0.06;
float servo_7_angle = 0.0;
float servo_7_target_angle = 0.0;
float servo_7_angle_step = 0.06;
float servo_8_angle = 0.0;
float servo_8_target_angle = 0.0;
float servo_8_angle_step = 0.06;
void recalculateServo()
{
if(servo_0_angle != servo_0_target_angle)
{
if(servo_0_angle < servo_0_target_angle)
servo_0_angle = max(servo_0_target_angle, servo_0_angle + servo_0_angle_step);
else // servo_0_angle > servo_0_target_step
servo_0_angle = min(servo_0_target_angle, servo_0_angle - servo_0_angle_step);
}
if(servo_1_angle != servo_1_target_angle)
{
if(servo_1_angle < servo_1_target_angle)
servo_1_angle = max(servo_1_target_angle, servo_1_angle + servo_1_angle_step);
else // servo_1_angle > servo_1_target_step
servo_1_angle = min(servo_1_target_angle, servo_1_angle - servo_1_angle_step);
}
if(servo_2_angle != servo_2_target_angle)
{
if(servo_2_angle < servo_2_target_angle)
servo_2_angle = max(servo_2_target_angle, servo_2_angle + servo_2_angle_step);
else // servo_2_angle > servo_2_target_step
servo_2_angle = min(servo_2_target_angle, servo_2_angle - servo_2_angle_step);
}
if(servo_3_angle != servo_3_target_angle)
{
if(servo_3_angle < servo_3_target_angle)
servo_3_angle = max(servo_3_target_angle, servo_3_angle + servo_3_angle_step);
else // servo_3_angle > servo_3_target_step
servo_3_angle = min(servo_3_target_angle, servo_3_angle - servo_3_angle_step);
}
if(servo_4_angle != servo_4_target_angle)
{
if(servo_4_angle < servo_4_target_angle)
servo_4_angle = max(servo_4_target_angle, servo_4_angle + servo_4_angle_step);
else // servo_4_angle > servo_4_target_step
servo_4_angle = min(servo_4_target_angle, servo_4_angle - servo_4_angle_step);
}
if(servo_5_angle != servo_5_target_angle)
{
if(servo_5_angle < servo_5_target_angle)
servo_5_angle = max(servo_5_target_angle, servo_5_angle + servo_5_angle_step);
else // servo_5_angle > servo_5_target_step
servo_5_angle = min(servo_5_target_angle, servo_5_angle - servo_5_angle_step);
}
if(servo_6_angle != servo_6_target_angle)
{
if(servo_6_angle < servo_6_target_angle)
servo_6_angle = max(servo_6_target_angle, servo_6_angle + servo_6_angle_step);
else // servo_6_angle > servo_6_target_step
servo_6_angle = min(servo_6_target_angle, servo_6_angle - servo_6_angle_step);
}
if(servo_7_angle != servo_7_target_angle)
{
if(servo_7_angle < servo_7_target_angle)
servo_7_angle = max(servo_7_target_angle, servo_7_angle + servo_7_angle_step);
else // servo_7_angle > servo_7_target_step
servo_7_angle = min(servo_7_target_angle, servo_7_angle - servo_7_angle_step);
}
if(servo_8_angle != servo_8_target_angle)
{
if(servo_8_angle < servo_8_target_angle)
servo_8_angle = max(servo_8_target_angle, servo_8_angle + servo_8_angle_step);
else // servo_8_angle > servo_8_target_step
servo_8_angle = min(servo_8_target_angle, servo_8_angle - servo_8_angle_step);
}
}
void pulseServo()
{
{
//calculating timing of pulse in μs
int pulseTime = SERVO_0_MIN + servo_0_angle * SERVO_0_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_0, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_0, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_1_MIN + servo_1_angle * SERVO_1_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_1, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_1, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_2_MIN + servo_2_angle * SERVO_2_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_2, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_2, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_3_MIN + servo_3_angle * SERVO_3_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_3, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_3, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_4_MIN + servo_4_angle * SERVO_4_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_4, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_4, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_5_MIN + servo_5_angle * SERVO_5_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_5, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_5, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_6_MIN + servo_6_angle * SERVO_6_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_6, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_6, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_7_MIN + servo_7_angle * SERVO_7_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_7, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_7, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_8_MIN + servo_8_angle * SERVO_8_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_8, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_8, LOW);
delayMicroseconds(pulseWait);
}
}
void CommunicationEvent()
{
if(Communication.available() < 2 * 9)
return;
{
// byte 0 - rotation angle
servo_0_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_0_angle_step = 1.0f;
else
servo_0_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_1_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_1_angle_step = 1.0f;
else
servo_1_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_2_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_2_angle_step = 1.0f;
else
servo_2_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_3_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_3_angle_step = 1.0f;
else
servo_3_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_4_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_4_angle_step = 1.0f;
else
servo_4_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_5_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_5_angle_step = 1.0f;
else
servo_5_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_6_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_6_angle_step = 1.0f;
else
servo_6_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_7_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_7_angle_step = 1.0f;
else
servo_7_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_8_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_8_angle_step = 1.0f;
else
servo_8_angle_step = speed / 255.0f / 10.0f;
}
}
As you can see, it is a lot of code do change / add.
Whole code:
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
#define PIN_SERVO_0 2
#define PIN_SERVO_1 3
#define PIN_SERVO_2 4
#define PIN_SERVO_3 5
#define PIN_SERVO_4 6
#define PIN_SERVO_5 7
#define PIN_SERVO_6 8
#define PIN_SERVO_7 9
#define PIN_SERVO_8 10
void setup()
{
pinMode(PIN_SERVO_0, OUTPUT);
pinMode(PIN_SERVO_1, OUTPUT);
pinMode(PIN_SERVO_2, OUTPUT);
pinMode(PIN_SERVO_3, OUTPUT);
pinMode(PIN_SERVO_4, OUTPUT);
pinMode(PIN_SERVO_5, OUTPUT);
pinMode(PIN_SERVO_6, OUTPUT);
pinMode(PIN_SERVO_7, OUTPUT);
pinMode(PIN_SERVO_8, OUTPUT);
Communication.begin(115200);
}
#define SERVO_0_MIN 1000
#define SERVO_0_MAX 2000
#define SERVO_0_RANGE (SERVO_0_MAX-SERVO_0_MIN)
#define SERVO_1_MIN 1000
#define SERVO_1_MAX 2000
#define SERVO_1_RANGE (SERVO_1_MAX-SERVO_1_MIN)
#define SERVO_2_MIN 1000
#define SERVO_2_MAX 2000
#define SERVO_2_RANGE (SERVO_2_MAX-SERVO_2_MIN)
#define SERVO_3_MIN 1000
#define SERVO_3_MAX 2000
#define SERVO_3_RANGE (SERVO_3_MAX-SERVO_3_MIN)
#define SERVO_4_MIN 1000
#define SERVO_4_MAX 2000
#define SERVO_4_RANGE (SERVO_4_MAX-SERVO_4_MIN)
#define SERVO_5_MIN 1000
#define SERVO_5_MAX 2000
#define SERVO_5_RANGE (SERVO_5_MAX-SERVO_5_MIN)
#define SERVO_6_MIN 1000
#define SERVO_6_MAX 2000
#define SERVO_6_RANGE (SERVO_6_MAX-SERVO_6_MIN)
#define SERVO_7_MIN 1000
#define SERVO_7_MAX 2000
#define SERVO_7_RANGE (SERVO_7_MAX-SERVO_7_MIN)
#define SERVO_8_MIN 1000
#define SERVO_8_MAX 2000
#define SERVO_8_RANGE (SERVO_8_MAX-SERVO_8_MIN)
float servo_0_angle = 0.0;
float servo_0_target_angle = 0.0;
float servo_0_angle_step = 0.06;
float servo_1_angle = 0.0;
float servo_1_target_angle = 0.0;
float servo_1_angle_step = 0.06;
float servo_2_angle = 0.0;
float servo_2_target_angle = 0.0;
float servo_2_angle_step = 0.06;
float servo_3_angle = 0.0;
float servo_3_target_angle = 0.0;
float servo_3_angle_step = 0.06;
float servo_4_angle = 0.0;
float servo_4_target_angle = 0.0;
float servo_4_angle_step = 0.06;
float servo_5_angle = 0.0;
float servo_5_target_angle = 0.0;
float servo_5_angle_step = 0.06;
float servo_6_angle = 0.0;
float servo_6_target_angle = 0.0;
float servo_6_angle_step = 0.06;
float servo_7_angle = 0.0;
float servo_7_target_angle = 0.0;
float servo_7_angle_step = 0.06;
float servo_8_angle = 0.0;
float servo_8_target_angle = 0.0;
float servo_8_angle_step = 0.06;
void recalculateServo()
{
if(servo_0_angle != servo_0_target_angle)
{
if(servo_0_angle < servo_0_target_angle)
servo_0_angle = max(servo_0_target_angle, servo_0_angle + servo_0_angle_step);
else // servo_0_angle > servo_0_target_step
servo_0_angle = min(servo_0_target_angle, servo_0_angle - servo_0_angle_step);
}
if(servo_1_angle != servo_1_target_angle)
{
if(servo_1_angle < servo_1_target_angle)
servo_1_angle = max(servo_1_target_angle, servo_1_angle + servo_1_angle_step);
else // servo_1_angle > servo_1_target_step
servo_1_angle = min(servo_1_target_angle, servo_1_angle - servo_1_angle_step);
}
if(servo_2_angle != servo_2_target_angle)
{
if(servo_2_angle < servo_2_target_angle)
servo_2_angle = max(servo_2_target_angle, servo_2_angle + servo_2_angle_step);
else // servo_2_angle > servo_2_target_step
servo_2_angle = min(servo_2_target_angle, servo_2_angle - servo_2_angle_step);
}
if(servo_3_angle != servo_3_target_angle)
{
if(servo_3_angle < servo_3_target_angle)
servo_3_angle = max(servo_3_target_angle, servo_3_angle + servo_3_angle_step);
else // servo_3_angle > servo_3_target_step
servo_3_angle = min(servo_3_target_angle, servo_3_angle - servo_3_angle_step);
}
if(servo_4_angle != servo_4_target_angle)
{
if(servo_4_angle < servo_4_target_angle)
servo_4_angle = max(servo_4_target_angle, servo_4_angle + servo_4_angle_step);
else // servo_4_angle > servo_4_target_step
servo_4_angle = min(servo_4_target_angle, servo_4_angle - servo_4_angle_step);
}
if(servo_5_angle != servo_5_target_angle)
{
if(servo_5_angle < servo_5_target_angle)
servo_5_angle = max(servo_5_target_angle, servo_5_angle + servo_5_angle_step);
else // servo_5_angle > servo_5_target_step
servo_5_angle = min(servo_5_target_angle, servo_5_angle - servo_5_angle_step);
}
if(servo_6_angle != servo_6_target_angle)
{
if(servo_6_angle < servo_6_target_angle)
servo_6_angle = max(servo_6_target_angle, servo_6_angle + servo_6_angle_step);
else // servo_6_angle > servo_6_target_step
servo_6_angle = min(servo_6_target_angle, servo_6_angle - servo_6_angle_step);
}
if(servo_7_angle != servo_7_target_angle)
{
if(servo_7_angle < servo_7_target_angle)
servo_7_angle = max(servo_7_target_angle, servo_7_angle + servo_7_angle_step);
else // servo_7_angle > servo_7_target_step
servo_7_angle = min(servo_7_target_angle, servo_7_angle - servo_7_angle_step);
}
if(servo_8_angle != servo_8_target_angle)
{
if(servo_8_angle < servo_8_target_angle)
servo_8_angle = max(servo_8_target_angle, servo_8_angle + servo_8_angle_step);
else // servo_8_angle > servo_8_target_step
servo_8_angle = min(servo_8_target_angle, servo_8_angle - servo_8_angle_step);
}
}
void pulseServo()
{
{
//calculating timing of pulse in μs
int pulseTime = SERVO_0_MIN + servo_0_angle * SERVO_0_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_0, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_0, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_1_MIN + servo_1_angle * SERVO_1_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_1, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_1, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_2_MIN + servo_2_angle * SERVO_2_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_2, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_2, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_3_MIN + servo_3_angle * SERVO_3_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_3, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_3, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_4_MIN + servo_4_angle * SERVO_4_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_4, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_4, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_5_MIN + servo_5_angle * SERVO_5_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_5, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_5, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_6_MIN + servo_6_angle * SERVO_6_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_6, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_6, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_7_MIN + servo_7_angle * SERVO_7_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_7, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_7, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_8_MIN + servo_8_angle * SERVO_8_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_8, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_8, LOW);
delayMicroseconds(pulseWait);
}
}
void CommunicationEvent()
{
if(Communication.available() < 2 * 9)
return;
{
// byte 0 - rotation angle
servo_0_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_0_angle_step = 1.0f;
else
servo_0_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_1_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_1_angle_step = 1.0f;
else
servo_1_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_2_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_2_angle_step = 1.0f;
else
servo_2_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_3_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_3_angle_step = 1.0f;
else
servo_3_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_4_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_4_angle_step = 1.0f;
else
servo_4_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_5_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_5_angle_step = 1.0f;
else
servo_5_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_6_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_6_angle_step = 1.0f;
else
servo_6_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_7_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_7_angle_step = 1.0f;
else
servo_7_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_8_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_8_angle_step = 1.0f;
else
servo_8_angle_step = speed / 255.0f / 10.0f;
}
}
void loop()
{
pulseServo();
recalculateServo();
}
Complete Code
To be able to send both LED info and Servo info we have two choices - send all info in one packet or have two different packets.We will use only one packet to communicate both LEDs and Servos. The packet will start with 6 bytes for LEDs (2 RGB LEDs), followed by 9 bytes for Servos.
As base code, we use Servo because adding LEDs will be easier then the other way.
if(Communication.available() < 2 * 9 + 3 * 2)
Only change we will make after merging the codes is changing this line to match packet length.
Whole code:
#if defined(__AVR_ATmega32U4__)
#define Communication Serial1
#define CommunicationEvent serialEvent1
#else
#define Communication Serial
#define CommunicationEvent serialEvent
#endif
#define PIN_SERVO_0 2
#define PIN_SERVO_1 3
#define PIN_SERVO_2 4
#define PIN_SERVO_3 5
#define PIN_SERVO_4 6
#define PIN_SERVO_5 7
#define PIN_SERVO_6 8
#define PIN_SERVO_7 9
#define PIN_SERVO_8 10
#define PIN_LED_0_RED 3
#define PIN_LED_0_GREEN 5
#define PIN_LED_0_BLUE 6
#define PIN_LED_1_RED 9
#define PIN_LED_1_GREEN 10
#define PIN_LED_1_BLUE 11
// Static color definition
byte Led_0_Red = 255;
byte Led_0_Green = 128;
byte Led_0_Blue = 64;
byte Led_1_Red = 255;
byte Led_1_Green = 128;
byte Led_1_Blue = 64;
void setup()
{
// Servos
pinMode(PIN_SERVO_0, OUTPUT);
pinMode(PIN_SERVO_1, OUTPUT);
pinMode(PIN_SERVO_2, OUTPUT);
pinMode(PIN_SERVO_3, OUTPUT);
pinMode(PIN_SERVO_4, OUTPUT);
pinMode(PIN_SERVO_5, OUTPUT);
pinMode(PIN_SERVO_6, OUTPUT);
pinMode(PIN_SERVO_7, OUTPUT);
pinMode(PIN_SERVO_8, OUTPUT);
// LEDs
{
pinMode(PIN_LED_0_RED, OUTPUT);
pinMode(PIN_LED_0_GREEN, OUTPUT);
pinMode(PIN_LED_0_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
pinMode(PIN_LED_1_RED, OUTPUT);
pinMode(PIN_LED_1_GREEN, OUTPUT);
pinMode(PIN_LED_1_BLUE, OUTPUT);
// Set colors on output
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
// Serial
Communication.begin(115200);
}
#define SERVO_0_MIN 1000
#define SERVO_0_MAX 2000
#define SERVO_0_RANGE (SERVO_0_MAX-SERVO_0_MIN)
#define SERVO_1_MIN 1000
#define SERVO_1_MAX 2000
#define SERVO_1_RANGE (SERVO_1_MAX-SERVO_1_MIN)
#define SERVO_2_MIN 1000
#define SERVO_2_MAX 2000
#define SERVO_2_RANGE (SERVO_2_MAX-SERVO_2_MIN)
#define SERVO_3_MIN 1000
#define SERVO_3_MAX 2000
#define SERVO_3_RANGE (SERVO_3_MAX-SERVO_3_MIN)
#define SERVO_4_MIN 1000
#define SERVO_4_MAX 2000
#define SERVO_4_RANGE (SERVO_4_MAX-SERVO_4_MIN)
#define SERVO_5_MIN 1000
#define SERVO_5_MAX 2000
#define SERVO_5_RANGE (SERVO_5_MAX-SERVO_5_MIN)
#define SERVO_6_MIN 1000
#define SERVO_6_MAX 2000
#define SERVO_6_RANGE (SERVO_6_MAX-SERVO_6_MIN)
#define SERVO_7_MIN 1000
#define SERVO_7_MAX 2000
#define SERVO_7_RANGE (SERVO_7_MAX-SERVO_7_MIN)
#define SERVO_8_MIN 1000
#define SERVO_8_MAX 2000
#define SERVO_8_RANGE (SERVO_8_MAX-SERVO_8_MIN)
float servo_0_angle = 0.0;
float servo_0_target_angle = 0.0;
float servo_0_angle_step = 0.06;
float servo_1_angle = 0.0;
float servo_1_target_angle = 0.0;
float servo_1_angle_step = 0.06;
float servo_2_angle = 0.0;
float servo_2_target_angle = 0.0;
float servo_2_angle_step = 0.06;
float servo_3_angle = 0.0;
float servo_3_target_angle = 0.0;
float servo_3_angle_step = 0.06;
float servo_4_angle = 0.0;
float servo_4_target_angle = 0.0;
float servo_4_angle_step = 0.06;
float servo_5_angle = 0.0;
float servo_5_target_angle = 0.0;
float servo_5_angle_step = 0.06;
float servo_6_angle = 0.0;
float servo_6_target_angle = 0.0;
float servo_6_angle_step = 0.06;
float servo_7_angle = 0.0;
float servo_7_target_angle = 0.0;
float servo_7_angle_step = 0.06;
float servo_8_angle = 0.0;
float servo_8_target_angle = 0.0;
float servo_8_angle_step = 0.06;
void recalculateServo()
{
if(servo_0_angle != servo_0_target_angle)
{
if(servo_0_angle < servo_0_target_angle)
servo_0_angle = max(servo_0_target_angle, servo_0_angle + servo_0_angle_step);
else // servo_0_angle > servo_0_target_step
servo_0_angle = min(servo_0_target_angle, servo_0_angle - servo_0_angle_step);
}
if(servo_1_angle != servo_1_target_angle)
{
if(servo_1_angle < servo_1_target_angle)
servo_1_angle = max(servo_1_target_angle, servo_1_angle + servo_1_angle_step);
else // servo_1_angle > servo_1_target_step
servo_1_angle = min(servo_1_target_angle, servo_1_angle - servo_1_angle_step);
}
if(servo_2_angle != servo_2_target_angle)
{
if(servo_2_angle < servo_2_target_angle)
servo_2_angle = max(servo_2_target_angle, servo_2_angle + servo_2_angle_step);
else // servo_2_angle > servo_2_target_step
servo_2_angle = min(servo_2_target_angle, servo_2_angle - servo_2_angle_step);
}
if(servo_3_angle != servo_3_target_angle)
{
if(servo_3_angle < servo_3_target_angle)
servo_3_angle = max(servo_3_target_angle, servo_3_angle + servo_3_angle_step);
else // servo_3_angle > servo_3_target_step
servo_3_angle = min(servo_3_target_angle, servo_3_angle - servo_3_angle_step);
}
if(servo_4_angle != servo_4_target_angle)
{
if(servo_4_angle < servo_4_target_angle)
servo_4_angle = max(servo_4_target_angle, servo_4_angle + servo_4_angle_step);
else // servo_4_angle > servo_4_target_step
servo_4_angle = min(servo_4_target_angle, servo_4_angle - servo_4_angle_step);
}
if(servo_5_angle != servo_5_target_angle)
{
if(servo_5_angle < servo_5_target_angle)
servo_5_angle = max(servo_5_target_angle, servo_5_angle + servo_5_angle_step);
else // servo_5_angle > servo_5_target_step
servo_5_angle = min(servo_5_target_angle, servo_5_angle - servo_5_angle_step);
}
if(servo_6_angle != servo_6_target_angle)
{
if(servo_6_angle < servo_6_target_angle)
servo_6_angle = max(servo_6_target_angle, servo_6_angle + servo_6_angle_step);
else // servo_6_angle > servo_6_target_step
servo_6_angle = min(servo_6_target_angle, servo_6_angle - servo_6_angle_step);
}
if(servo_7_angle != servo_7_target_angle)
{
if(servo_7_angle < servo_7_target_angle)
servo_7_angle = max(servo_7_target_angle, servo_7_angle + servo_7_angle_step);
else // servo_7_angle > servo_7_target_step
servo_7_angle = min(servo_7_target_angle, servo_7_angle - servo_7_angle_step);
}
if(servo_8_angle != servo_8_target_angle)
{
if(servo_8_angle < servo_8_target_angle)
servo_8_angle = max(servo_8_target_angle, servo_8_angle + servo_8_angle_step);
else // servo_8_angle > servo_8_target_step
servo_8_angle = min(servo_8_target_angle, servo_8_angle - servo_8_angle_step);
}
}
void pulseServo()
{
{
//calculating timing of pulse in μs
int pulseTime = SERVO_0_MIN + servo_0_angle * SERVO_0_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_0, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_0, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_1_MIN + servo_1_angle * SERVO_1_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_1, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_1, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_2_MIN + servo_2_angle * SERVO_2_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_2, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_2, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_3_MIN + servo_3_angle * SERVO_3_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_3, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_3, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_4_MIN + servo_4_angle * SERVO_4_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_4, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_4, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_5_MIN + servo_5_angle * SERVO_5_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_5, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_5, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_6_MIN + servo_6_angle * SERVO_6_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_6, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_6, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_7_MIN + servo_7_angle * SERVO_7_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_7, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_7, LOW);
delayMicroseconds(pulseWait);
}
{
//calculating timing of pulse in μs
int pulseTime = SERVO_8_MIN + servo_8_angle * SERVO_8_RANGE;
int pulseWait = 2000 - pulseTime;
digitalWrite(PIN_SERVO_8, HIGH);
delayMicroseconds(pulseTime);
digitalWrite(PIN_SERVO_8, LOW);
delayMicroseconds(pulseWait);
}
}
void CommunicationEvent()
{
if(Communication.available() < 2 * 9 + 3 * 2)
return;
// LEDs
{
{
Led_0_Red = Communication.read();
Led_0_Green = Communication.read();
Led_0_Blue = Communication.read();
analogWrite(PIN_LED_0_RED, Led_0_Red);
analogWrite(PIN_LED_0_GREEN, Led_0_Green);
analogWrite(PIN_LED_0_BLUE, Led_0_Blue);
}
{
Led_1_Red = Communication.read();
Led_1_Green = Communication.read();
Led_1_Blue = Communication.read();
analogWrite(PIN_LED_1_RED, Led_1_Red);
analogWrite(PIN_LED_1_GREEN, Led_1_Green);
analogWrite(PIN_LED_1_BLUE, Led_1_Blue);
}
}
// Servos
{
{
// byte 0 - rotation angle
servo_0_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_0_angle_step = 1.0f;
else
servo_0_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_1_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_1_angle_step = 1.0f;
else
servo_1_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_2_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_2_angle_step = 1.0f;
else
servo_2_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_3_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_3_angle_step = 1.0f;
else
servo_3_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_4_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_4_angle_step = 1.0f;
else
servo_4_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_5_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_5_angle_step = 1.0f;
else
servo_5_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_6_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_6_angle_step = 1.0f;
else
servo_6_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_7_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_7_angle_step = 1.0f;
else
servo_7_angle_step = speed / 255.0f / 10.0f;
}
{
// byte 0 - rotation angle
servo_8_target_angle = Communication.read() / 255.0f;
// byte 1 - rotation speed
int speed = Communication.read();
if(speed == 255)
servo_8_angle_step = 1.0f;
else
servo_8_angle_step = speed / 255.0f / 10.0f;
}
}
}
void loop()
{
pulseServo();
recalculateServo();
}