Lost in Space banner

ELECTRONIC EXPERIMENTS

Continuous Rotation Servo Motor

Blinking Chest Lights Rev 1.0

Blinking Chest Lights Rev 3.0

Sound Display VU Meter Using A Microphone

Return to Skips Messy Workbench Homepage

CONTINUOUS ROTATION SERVO MOTOR

As it's name describes, a continuous rotation servo is a servo motor that rotates 360°. Regular servo motors can only rotate 180°. Other than rotation angle, following are some of the differences:

Beware that the two types of servo motors look exactly the same except for the label. Be sure to read the label on the servo motor. The following photo shows a continuous rotation servo motor on the left and a standard servo motor on the right. These motors are also wired the same, see the schematic of the circuit I used while learning about the continuous rotation servo motor.

Continuous and standard servo look the same

How a continuous rotation motor works

This explanation will be assuming the motor will be wired to an Arduino micro processor board. It can be any of the various Arduino boards provided they have at least one output pin that is a Pulse Width Modulation (PWM) pin. On an Arduino Uno these pins are marked with a Tilde (~). For other board check the data sheet for that board.

The motor speed and direction are controlled by sending a PWM pulse to the motor between 0.50mS to 2.50mS. The pulse width is controlled by writing a value of 0 to 180 to the PWM pin.

Pulses describing continuous servo operation

Figures 1 through 3 show the pulse width that is sent to a continuous rotation servo motor to make it run. A short video is included of the motor and an oscilloscope screen showing the pulse change versus motor action.

Figure 1 shows a pulse width of 0.50mS. The width from 1.5mS to 0.50mS is 1.0mS and is created by values in the range of 0 to 89 being written to the PWM pin that the motor is attached to. When the pulse varies from 1.50mS to 0.50mS (value of 90 to 0), the motor will be turning clock-wise (CW). At a value of 89 the motor will be turning CW and running very slow. As the value being written is decrease toward zero (0), the motor will continue turning CW and will increase in speed until achieving full speed in the CW direction at a value of zero (0).

Figure 2 shows a pulse width of 1.50mS. When the pulse width is 1.50mS the value written to the PWM pin that the motor is attached to is 90 and the motor is stopped.

Figure 3 shows a pulse width of 2.50mS. The width from 1.50mS to 2.50mS is 1.0mS and is created by values in the range of 91 to 180 being written to the PWM pin that the motor is attached to. When the pulse varies from 1.50mS to 2.50mS (value of 91 to 180), the motor will be turning counter-clock-wise (CCW). At the value of 91 the motor will be turning CCW and running very slow. As the value being written is increased toward 180, the motor will continue turning CCW and will increase in speed until achieving full speed in the CCW direction at a value of 180.



Continuous rotation servo adjustment location

Click to enlarge image





Schematic Diagram and Bill of Material (BOM)

Schematic Diagram

Here is the schematic diagram that is using an Arduino UNO. Most any Arduino board can be used as long as there is at least one PWM output pin available. The schematic was created using Easy EDA. Click the schematic image to enlarge.

Schematic of continuous rotation servo with Arduino UNO

Bill of Material (BOM)

Prices are as of March 11, 2024

Quantity Description Part Number Vendor ASIN Number Price Per Extended Price
1 Arduino Uno or similar Uno R3 [A000066] Amazon B008GRTSV6 $27.60 $27.60
1 Continuous rotation servo FS90R Adafruit.com N/A $7.50 $7.50
3 Male-to-Male wire jumpers
Set of 130pcs 12, 16, 20, 25cm
Only 3 wires required for this project
41383 Amazon B016KI622U $0.06 per wire $0.18

Program Code Used to Test Motor with Explanation

The code in the following window can be selected, copied and pasted directly into your IDE. It should work well on a Windows or Mac. Simply place you mouse cursor where you want to start copying and then click and drag to select the text. Then copy the selection and paste it into your Integrated Development Environment (IDE).

Program code I wrote to learn how to use the continuous rotation Servo

                    
// Testing Continuous Servo Test Code
// John G. (Skip) Todora
// Date: February 29, 2024

/*
  Servo.h Methods:
    attach()
    write()
    writeMicroseconds()
    read()
    attached()
    detach()
*/

/* 
    Motor Number: FS90R - From Adafruit.com

    To control with an Arduino, Adafruit suggest connecting the orange control wire 
    to pin 9 or 10 and using the Servo library included with the Arduino 
    IDE. 
    Write a value of "90" (1.5ms pulse) to the PWM pin to stop the motor. 
    Write a value of 180, (2.50ms pulse) is full speed CCW.
    Write a value of zero '0' (0.50ms pulse) is full speed CW.
    The motor may require some simple calibration. Simply tell the servo 
    to 'stop' and then gently adjust the potentiometer in the recessed hole 
    on the bottom of the servo using a small screwdriver until the servo stops moving.

    *** 
        During testing this is what I discovered:
        CW direction count down from 89 to 0, pulse width = 0.50mS (1.0mS less than full stop)
        CCW direction count up from 91 to 180, pulse width = 2.5mS (1.0mS greater than full stop)
        Motor stopped count = 90, pulse width = 1.5mS
        Adjustment screw on bottom of motor to tweak the motor stop position
    ***

    MOTOR SPECIFICATIONS
    No load speed: 110RPM (4.8v) / 130RPM (6v)
    Running Current (at no load): 100mA (4.8v) / 120mA (6v)
    Peak Stall Torque (4.8v): 1.3 kg/cm / 18.09 oz/in
    Peak Stall Torque (6v): 1.5 kg/cm / 20.86 oz/in
    Stall Current: 550mA (4.8v) / 650mA (6v)
    Dimensions: 32mm x 30mm x 12mm / 1.3" x 1.2" x 0.5"
    Wire Length: 240mm / 9.4"
    Weight: 10g
    Spline Count: 21
*/

#include<servo.h> // Include the servo library.

#define servoMtr 10   // Assign the servo motor to pin 10

Servo myServo;  // Create a servo object

int i = 90;			  // Motor stopped
int rotDir = 0;		// 0 = CCW, 1 = CW. Not really for rotation. Flag used to change operation

void setup() {
  Serial.begin(9600);         // Set up the Serial port
  myServo.attach(servoMtr);   // Attach the servo object to the defined pin
  myServo.write(90);          // Make sure the motor is stopped
}

void loop() {
  
  // Count up from 90 to 180. CCW stop to full speed
  if (rotDir == 0) {
    Serial.print("i = "); Serial.print(i); Serial.print("   ");   // Can be removed
    Serial.print("rotDir = "); Serial.println(rotDir);            // Can be removed
    i++;
    myServo.write(i);
    delay(300);                                                   // Can be removed
    if (i == 180) {
      rotDir = 1;
      Serial.print("i = "); Serial.print(i); Serial.print("   "); // Can be removed
      Serial.print("rotDir = "); Serial.println(rotDir);          // Can be removed
    }
  }
  
  // Count down from 180 to 90. CCW full speed to stop
  if (rotDir == 1) {
    Serial.print("i = "); Serial.print(i); Serial.print("   ");   // Can be removed
    Serial.print("rotDir = "); Serial.println(rotDir);            // Can be removed
    i--;
    myServo.write(i);
    delay(300);                                                   // Can be removed
    if (i == 90) {
      rotDir = 2;
      Serial.print("i = "); Serial.print(i); Serial.print("   "); // Can be removed
      Serial.print("rotDir = "); Serial.println(rotDir);          // Can be removed
    }
  }
  
  // Count down from 90 to 0. Stop to CW full speed
  if (rotDir == 2) {
    Serial.print("i = "); Serial.print(i); Serial.print("   ");   // Can be removed
    Serial.print("rotDir = "); Serial.println(rotDir);            // Can be removed
    i--;
    myServo.write(i);
    delay(300);                                                   // Can be removed
    if (i == 0) {
      rotDir = 3;
      Serial.print("i = "); Serial.print(i); Serial.print("   "); // Can be removed
      Serial.print("rotDir = "); Serial.println(rotDir);          // Can be removed
    }
  }
  
  // Count up from 0 to 90. Full speed CW to stop
  if (rotDir == 3) {
    Serial.print("i = "); Serial.print(i); Serial.print("   ");   // Can be removed
    Serial.print("rotDir = "); Serial.println(rotDir);            // Can be removed
    i++;
    myServo.write(i);
    delay(300);                                                   // Can be removed
    if (i == 90) {
      rotDir = 0;
      Serial.print("i = "); Serial.print(i); Serial.print("   "); // Can be removed
      Serial.print("rotDir = "); Serial.println(rotDir);          // Can be removed 
    }
  }
}

                


Explanation of the code

This video is best viewed in full screen mode.

RETURN TO TOP OF PAGE


BLINKING CHEST LIGHTS Rev 1.0, PROGRAM Rev 2.0

As it's name describes, this section will demonstrate my first attempt at blinking the robots chest lights, the Function Indicators, in a completely random pattern.

This experiment uses an Arduino Mega 2560 board. This board will not be used in the final robot animation because the Mega board is too large to be self contained within the robot body.

Random Blinking of Function Lights Testing

Schematic Diagram and Bill of Material (BOM)

Schematic Diagram Rev 1.0

Here is the schematic diagram that is using an Arduino Mega 2560. Most any Arduino board can be used. The schematic was created using Easy EDA. Click the schematic image to enlarge.

Schematic of robot chest lights using Arduino Mega 2560

Bill of Material (BOM)

Prices are as of March 11, 2024

Quantity Description Part Number Vendor ASIN Number Price Per Extended Price
1 Arduino Mega 2560 or similar Mega 2560 Rev3 [A000067] Amazon B0046AMGW0 $48.90 $48.90
22 LED, 5mm Defused
Pack - 5 LEDs each
in 5 colors
25-pack
4203 Adafruit.com N/A $4.95 $4.95
22 YOKIVE 100 pcs Carbon Film
Resistors, 1/4W, 300Ω 5%
Amazon B0BNHTXS1S $0.0499 $1.098
24 Male-to-Male wire jumpers
Set of 130pcs 12, 16, 20, 25cm
Only 3 wires required for this project
41383 Amazon B016KI622U $0.06 per wire $0.18

Program Code Used to Test Motor with Explanation

The code in the following window can be selected, copied and pasted directly into your IDE. It should work well on a Windows or Mac. Simply place you mouse cursor where you want to start copying and then click and drag to select the text. Then copy the selection and paste it into your Integrated Development Environment (IDE).

Program code I wrote to produce random blinking of LED's

// Blink without using delay and using a random 
// number for the duty cycle

// Programmed for an Arduino Mega or Arduino Mega 2560
// By: John G. (Skip) Todora
// Date: March 03, 2024
// Revision: 02

// B9 Robot chest lights: Function Indicators and Programming Buttons

// Two rows of six lights per row; small round lamps
// Bottom row of Function Indicators
#define botRow00 22
#define botRow01 24
#define botRow02 26
#define botRow03 28
#define botRow04 30
#define botRow05 32

// Top row of Function Indicators
#define topRow00 23
#define topRow01 25
#define topRow02 27
#define topRow03 29
#define topRow04 31
#define topRow05 33

// Bottom rows of five lights per row; Programming Buttons
#define botRowSq00 44
#define botRowSq01 46
#define botRowSq02 48
#define botRowSq03 50
#define botRowSq04 52

// Top rows or five lights per row: Programming Buttons
#define topRowSq00 45
#define topRowSq01 47
#define topRowSq02 49
#define topRowSq03 51
#define topRowSq04 53

// The variable: range and min form the data for creating a duty cycle for blinking
// These values will most likely need to be adjusted depending upon what processor
// board is being used.
unsigned long range = 80000;  // Max duty cycle for blink in mS
unsigned long min = 700;      // Min duty cycle for blink in mS

int runOnce = 1;              // Used for lamp test on power up

// Variable to store the current time
// unsigned long curTime = 0;

// Bottom row of the six; Function Indicators
// Assign Current Time and Previous time values
unsigned long botRow00CurTime = 0;
unsigned long botRow01CurTime = 0;
unsigned long botRow02CurTime = 0;
unsigned long botRow03CurTime = 0;
unsigned long botRow04CurTime = 0;
unsigned long botRow05CurTime = 0;
unsigned long botRow00PrevTime = 0;
unsigned long botRow01PrevTime = 0;
unsigned long botRow02PrevTime = 0;
unsigned long botRow03PrevTime = 0;
unsigned long botRow04PrevTime = 0;
unsigned long botRow05PrevTime = 0;

// Top row of the six; Function Indicators
// Assign Current Time and Previous time values
unsigned long topRow00CurTime = 0;
unsigned long topRow01CurTime = 0;
unsigned long topRow02CurTime = 0;
unsigned long topRow03CurTime = 0;
unsigned long topRow04CurTime = 0;
unsigned long topRow05CurTime = 0;
unsigned long topRow00PrevTime = 0;
unsigned long topRow01PrevTime = 0;
unsigned long topRow02PrevTime = 0;
unsigned long topRow03PrevTime = 0;
unsigned long topRow04PrevTime = 0;
unsigned long topRow05PrevTime = 0;

// Bottom row of five square: Programming Buttons
// Assign Current Time values. Previous time not needed because 
// these lights do not blink
unsigned long botRowSq00CurTime = 0;
unsigned long botRowSq01CurTime = 0;
unsigned long botRowSq02CurTime = 0;
unsigned long botRowSq03CurTime = 0;
unsigned long botRowSq04CurTime = 0;

// Top row of five square: Programming Buttons
// Assign Current Time values. Previous time not needed because 
// these lights do not blink
unsigned long topRowSq00CurTime = 0;
unsigned long topRowSq01CurTime = 0;
unsigned long topRowSq02CurTime = 0;
unsigned long topRowSq03CurTime = 0;
unsigned long topRowSq04CurTime = 0;

// Initialize state of bottom row of small round lights: 
// Function Indicators
int botRow00State = LOW;
int botRow01State = LOW;
int botRow02State = LOW;
int botRow03State = LOW;
int botRow04State = LOW;
int botRow05State = LOW;

// Intitialize state of top row of small round lights:
// Function Indicators
int topRow00State = LOW;
int topRow01State = LOW;
int topRow02State = LOW;
int topRow03State = LOW;
int topRow04State = LOW;
int topRow05State = LOW;

// Initialize state of bottom row of square lights:
// Programming Push Buttons
int botRowSq00State = LOW;
int botRowSq01State = LOW;
int botRowSq02State = LOW;
int botRowSq03State = LOW;
int botRowSq04State = LOW;

// Initialize state of top row of square lights
// Programming Push Buttons
int topRowSq00State = LOW;
int topRowSq01State = LOW;
int topRowSq02State = LOW;
int topRowSq03State = LOW;
int topRowsq04State = LOW;

void setup() {
  Serial.begin(9600);
  
  // Declare all lamp pins as data outputs
  pinMode(botRow00, OUTPUT);
  pinMode(botRow01, OUTPUT);
  pinMode(botRow02, OUTPUT);
  pinMode(botRow03, OUTPUT);
  pinMode(botRow04, OUTPUT);
  pinMode(botRow05, OUTPUT);
  
  pinMode(topRow00, OUTPUT);
  pinMode(topRow01, OUTPUT);
  pinMode(topRow02, OUTPUT);
  pinMode(topRow03, OUTPUT);
  pinMode(topRow04, OUTPUT);
  pinMode(topRow05, OUTPUT);

  pinMode(botRowSq00, OUTPUT);
  pinMode(botRowSq01, OUTPUT);
  pinMode(botRowSq02, OUTPUT);
  pinMode(botRowSq03, OUTPUT);
  pinMode(botRowSq04, OUTPUT);

  pinMode(topRowSq00, OUTPUT);
  pinMode(topRowSq01, OUTPUT);
  pinMode(topRowSq02, OUTPUT);
  pinMode(topRowSq03, OUTPUT);
  pinMode(topRowSq04, OUTPUT);
}

void loop() {
  // Run once - Lamp Test
  if (runOnce == 1) {
    lampTest();   // Function that controls lamp test
  }
    
  // Assign millis() to each light
  // curTime = millis();
  
  botRow00CurTime = millis();
  botRow01CurTime = millis();
  botRow02CurTime = millis();
  botRow03CurTime = millis();
  botRow04CurTime = millis();
  botRow05CurTime = millis();
  
  topRow00CurTime = millis();
  topRow01CurTime = millis();
  topRow02CurTime = millis();
  topRow03CurTime = millis();
  topRow04CurTime = millis();
  topRow05CurTime = millis();
  
  
  // Control the lights
  // Bottom Row LED 00
  unsigned long botRow00DutyCycle = rand() % range + min; // rand() C stdlib.h (0 to 32767)
  if (botRow00CurTime - botRow00PrevTime > botRow00DutyCycle / 2) {
  // if (curTime - botRow00PrevTime > botRow00DutyCycle / 2) {
    botRow00Blink();
    botRow00PrevTime = botRow00CurTime;
  }
    
  // Bottom Row LED 01
  unsigned long botRow01DutyCycle = rand() % range + min;
  if (botRow01CurTime - botRow01PrevTime > botRow01DutyCycle / 2) {
  // if (curTime - botRow01PrevTime > botRow01DutyCycle / 2) {
    botRow01Blink();
    botRow01PrevTime = botRow01CurTime;
  }
   
  // Bottom Row LED 02
  unsigned long botRow02DutyCycle = rand() % range + min;
  if (botRow02CurTime - botRow02PrevTime > botRow02DutyCycle / 2) {
  // if (curTime - botRow02PrevTime > botRow02DutyCycle / 2) {
    botRow02Blink();
    botRow02PrevTime = botRow02CurTime;
  }
    
  // Bottom Row LED 03
  unsigned long botRow03DutyCycle = rand() % range + min;
  if (botRow03CurTime - botRow03PrevTime > botRow03DutyCycle / 2) {
  // if (curTime - botRow03PrevTime > botRow03DutyCycle / 2) {  
    botRow03Blink();
    botRow03PrevTime = botRow03CurTime;
  }
    
  // Bottom Row LED 04
  unsigned long botRow04DutyCycle = rand() % range + min;
  if (botRow04CurTime - botRow04PrevTime > botRow04DutyCycle / 2) {
  // if (curTime - botRow04PrevTime > botRow04DutyCycle / 2) {
    botRow04Blink();
    botRow04PrevTime = botRow04CurTime;
  }
    
  // Bottom Row LED 05
  unsigned long botRow05DutyCycle = rand() % range + min;
  if (botRow05CurTime - botRow05PrevTime > botRow05DutyCycle / 2) {
  // if (curTime - botRow05PrevTime > botRow05DutyCycle / 2) {
    botRow05Blink();
    botRow05PrevTime = botRow05CurTime;
  }
    
  
  
  // Top Row LED 00
  unsigned long topRow00DutyCycle = rand() % range + min;
  if (topRow00CurTime - topRow00PrevTime > topRow00DutyCycle / 2) {
  // if (curTime - topRow00PrevTime > topRow00DutyCycle / 2) {
    topRow00Blink();
    topRow00PrevTime = topRow00CurTime;
  }
    
  // Top Row LED 01
  unsigned long topRow01DutyCycle = rand() % range + min;
  if (topRow01CurTime - topRow01PrevTime > topRow01DutyCycle / 2) {
  // if (curTime - topRow01PrevTime > topRow01DutyCycle / 2) {
    topRow01Blink();
    topRow01PrevTime = topRow01CurTime;
  }
    
  // Top Row LED 02
  unsigned long topRow02DutyCycle = rand() % range + min;
  if (topRow02CurTime - topRow02PrevTime > topRow02DutyCycle / 2) {
  // if (curTime - topRow02PrevTime > topRow02DutyCycle / 2) {  
    topRow02Blink();
    topRow02PrevTime = botRow02CurTime;
  }
    
  // Top Row LED 03
  unsigned long topRow03DutyCycle = rand() % range + min;
  if (topRow03CurTime - topRow03PrevTime > topRow03DutyCycle / 2) {
  // if (curTime - topRow03PrevTime > topRow03DutyCycle / 2) {  
    topRow03Blink();
    topRow03PrevTime = topRow03CurTime;
  }
    
  // Top Row LED 04
  unsigned long topRow04DutyCycle = rand() % range + min;
  if (topRow04CurTime - topRow04PrevTime > topRow04DutyCycle / 2) {
  // if (curTime - topRow04PrevTime > topRow04DutyCycle / 2) {  
    topRow04Blink();
    topRow04PrevTime = topRow04CurTime;
  }
    
  // Top Row LED 05
  unsigned long topRow05DutyCycle = rand() % range + min;
  if (topRow05CurTime - topRow05PrevTime > topRow05DutyCycle / 2) {
  // if (curTime - topRow05PrevTime > topRow05DutyCycle / 2) {
    topRow05Blink();
    topRow05PrevTime = topRow05CurTime;
  }
}

void lampTest() {
  digitalWrite(botRow00, HIGH);
    delay(500);
    digitalWrite(botRow01, HIGH);
    delay(500);
    digitalWrite(botRow02, HIGH);
    delay(500);
    digitalWrite(botRow03, HIGH);
    delay(500);
    digitalWrite(botRow04, HIGH);
    delay(500);
    digitalWrite(botRow05, HIGH);
    delay(500);
    digitalWrite(topRow00, HIGH);
    delay(500);
    digitalWrite(topRow01, HIGH);
    delay(500);
    digitalWrite(topRow02, HIGH);
    delay(500);
    digitalWrite(topRow03, HIGH);
    delay(500);
    digitalWrite(topRow04, HIGH);
    delay(500);
    digitalWrite(topRow05, HIGH);
    delay(500);
    digitalWrite(botRowSq00, HIGH);
    delay(500);
    digitalWrite(botRowSq01, HIGH);
    delay(500);
    digitalWrite(botRowSq02, HIGH);
    delay(500);
    digitalWrite(botRowSq03, HIGH);
    delay(500);
    digitalWrite(botRowSq04, HIGH);
    delay(500);
    digitalWrite(topRowSq00, HIGH);
    delay(500);
    digitalWrite(topRowSq01, HIGH);
    delay(500);
    digitalWrite(topRowSq02, HIGH);
    delay(500);
    digitalWrite(topRowSq03, HIGH);
    delay(500);
    digitalWrite(topRowSq04, HIGH);
    delay(2000);    // Adjust to user liking
    runOnce = 0;
    digitalWrite(botRow00, LOW);
    digitalWrite(botRow01, LOW);
    digitalWrite(botRow02, LOW);
    digitalWrite(botRow03, LOW);
    digitalWrite(botRow04, LOW);
    digitalWrite(botRow05, LOW);
    digitalWrite(topRow00, LOW);
    digitalWrite(topRow00, LOW);
    digitalWrite(topRow00, LOW);
    digitalWrite(topRow00, LOW);
    digitalWrite(topRow00, LOW);
    digitalWrite(topRow00, LOW);

    /*
    digitalWrite(botRowSq00, LOW);
    digitalWrite(botRowSq01, LOW);
    digitalWrite(botRowSq02, LOW);
    digitalWrite(botRowSq03, LOW);
    digitalWrite(botRowSq04, LOW);
    digitalWrite(topRowSq00, LOW);
    digitalWrite(topRowSq01, LOW);
    digitalWrite(topRowSq02, LOW);
    digitalWrite(topRowSq03, LOW);
    digitalWrite(topRowSq04, LOW);
    */
}

// Bottom row Function Indicators Blink
void botRow00Blink() {
  botRow00State = (botRow00State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow00, botRow00State);
}

void botRow01Blink() {
  botRow01State = (botRow01State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow01, botRow01State);
}

void botRow02Blink() {
  botRow02State = (botRow02State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow02, botRow02State);
}

void botRow03Blink() {
  botRow03State = (botRow03State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow03, botRow03State);
}

void botRow04Blink() {
  botRow04State = (botRow04State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow04, botRow04State);
}

void botRow05Blink() {
  botRow05State = (botRow05State == HIGH) ? LOW : HIGH;
  digitalWrite(botRow05, botRow05State);
}

// Top row Function Indicators Blink

void topRow00Blink() {
  topRow00State = (topRow00State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow00, topRow00State);
}

void topRow01Blink() {
  topRow01State = (topRow01State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow01, topRow01State);
}

void topRow02Blink() {
  topRow02State = (topRow02State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow02, topRow02State);
}

void topRow03Blink() {
  topRow03State = (topRow03State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow03, topRow03State);
}

void topRow04Blink() {
  topRow04State = (topRow04State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow04, topRow04State);
}

void topRow05Blink() {
  topRow05State = (topRow05State == HIGH) ? LOW : HIGH;
  digitalWrite(topRow05, topRow05State);
}
                


Explanation of the code

This video is best viewed in full screen mode.

RETURN TO TOP OF PAGE


BLINKING CHEST LIGHTS Rev 1.1, PROGRAM Rev 3.0

As it's name describes, this section will demonstrate my second, actually third attempt at blinking the robots chest lights; the Function Indicators, in a completely random pattern, and the Sensor Indicators either back-and-forth at a random rate or at a fixed equal time interval. In this experiment I'm using an Arduino Micro and I paralleled three of the Function Indicator LED's, in a random arrangement, off of a single Arduino output pin (See the schematic diagram). I did this to save output pins but to also check if the lights still look as if they are blinking in a random pattern. Following is a short video of this design:

This video is best viewed in full screen mode.

Schematic Diagram and Bill of Material (BOM)

Schematic Diagram Rev 3.0

Here is the schematic diagram that is using an Arduino Mega 2560. Most any Arduino board can be used. The schematic was created using Easy EDA. Click the schematic image to enlarge.

Schematic of robot chest lights using Arduino Uno and less output pins

Bill of Material (BOM)

Prices are as of March 11, 2024

Quantity Description Part Number Vendor ASIN Number Price Per Extended Price
1 Arduino Mega 2560 or similar Mega 2560 Rev3 [A000067] Amazon B0046AMGW0 $48.90 $48.90
24 LED, 5mm Defused
Pack - 5 LEDs each
in 5 colors
25-pack
4203 Adafruit.com N/A $4.95 $4.95
24 YOKIVE 100 pcs Carbon Film
Resistors, 1/4W, 300Ω 5%
Amazon B0BNHTXS1S $0.0499 $1.098
24 Male-to-Male wire jumpers
Set of 130pcs 12, 16, 20, 25cm
Only 3 wires required for this project
41383 Amazon B016KI622U $0.06 per wire $0.18

Program Code Used to Test Motor with Explanation

The code in the following window can be selected, copied and pasted directly into your IDE. It should work well on a Windows or Mac. Simply place you mouse cursor where you want to start copying and then click and drag to select the text. Then copy the selection and paste it into your Integrated Development Environment (IDE).

Program code I wrote to produce random blinking of LED's

// Blink without using delay and using a random 
// number for the duty cycle

// Programmed for an Arduino Mega or Arduino Mega 2560
// By: John G. (Skip) Todora
// Date: March 16, 2024
// Revision: 3.0
// Filename: Light_Test_with_Micro_using_4-Outputs.ino

// B9 Robot chest lights: Function Indicators and Sensor Indicators

// Two rows of six lights per row; Function Indicators
// The 12-lights are 4-groups of 3-lights/group
// Pin assignment for Function Indicators and for Sensor Indicators
#define group01 2       // D1, D5, D9 - See schematic diagram
#define group02 3       // D2, D8, D10 - See schematic diagram
#define group03 4       // D3, D6, D11 - See schematic diagram
#define group04 5       // D4, D7, D12 - See schematic diagram
#define sensorInd01 6   // Sensor indicator
#define sensorInd02 7   // Sensor indicator

// The variable: range and min form the data for creating a duty cycle for blinking
// These values will most likely need to be adjusted depending upon what processor
// board is being used.
unsigned long range = 80000;  // Max duty cycle for blink in mS
unsigned long min = 700;      // Min duty cycle for blink in mS

int runOnce = 1;              // Used for lamp test on power up

// Assign Current Time and Previous time values
unsigned long group01CurTime = 0;
unsigned long group02CurTime = 0;
unsigned long group03CurTime = 0;
unsigned long group04CurTime = 0;
unsigned long sensorInd01CurTime = 0;
unsigned long sensorInd02CurTime = 0;
unsigned long group01PrevTime = 0;
unsigned long group02PrevTime = 0;
unsigned long group03PrevTime = 0;
unsigned long group04PrevTime = 0;
unsigned long sensorInd01PrevTime = 0;
unsigned long sensorInd02PrevTime = 0;

// Initialize state of bottom row of small round lights: 
// Function Indicators
int group01State = LOW;
int group02State = LOW;
int group03State = LOW;
int group04State = LOW;
int sensorInd01State = LOW;
int sensorInd02State = LOW;

void setup() {
  Serial.begin(9600);
  
  // Declare all lamp pins as data outputs
  pinMode(group01, OUTPUT);
  pinMode(group02, OUTPUT);
  pinMode(group03, OUTPUT);
  pinMode(group04, OUTPUT);
  pinMode(sensorInd01, OUTPUT);
  pinMode(sensorInd02, OUTPUT);
}

void loop() {
  // Run once - Lamp Test
  if (runOnce == 1) {
    lampTest();   // Function that controls lamp test
  }
    
  // Assign millis() to each light
  // curTime = millis();
  group01CurTime = millis();
  group02CurTime = millis();
  group03CurTime = millis();
  group04CurTime = millis();
  sensorInd01CurTime = millis();
  sensorInd02CurTime = millis();
  
  // Control the lights
  // Group 01 - D1, D5, D9
  unsigned long group01DutyCycle = rand() % range + min; // rand() C stdlib.h (0 to 32767)
  if (group01CurTime - group01PrevTime > group01DutyCycle / 2) {
     group01Blink();
    group01PrevTime = group01CurTime;
  }
    
  // Group 02 - D3, D8, D10
  unsigned long group02DutyCycle = rand() % range + min;
  if (group02CurTime - group02PrevTime > group02DutyCycle / 2) {
    group02Blink();
    group02PrevTime = group02CurTime;
  }
   
  // Group 03 - D3, D6, D11
  unsigned long group03DutyCycle = rand() % range + min;
  if (group03CurTime - group03PrevTime > group03DutyCycle / 2) {
    group03Blink();
    group03PrevTime = group03CurTime;
  }
    
  // Group 04 - D4, D7, D12
  unsigned long group04DutyCycle = rand() % range + min;
  if (group04CurTime - group04PrevTime > group04DutyCycle / 2) {
    group04Blink();
    group04PrevTime = group04CurTime;
  }
    
  // Sensor Indicator 01
  unsigned long sensorInd01DutyCycle = rand() % range + min;
  if (sensorInd01CurTime - sensorInd01PrevTime > sensorInd01DutyCycle / 2) {
     sensorInd01Blink();
    sensorInd01PrevTime = sensorInd01CurTime;
  }
    
  // Sensor Indicator 02
  unsigned long sensorInd02DutyCycle = rand() % range + min;
  if (sensorInd02CurTime - sensorInd02PrevTime > sensorInd02DutyCycle / 2) {
     sensorInd02Blink();
    sensorInd02PrevTime = sensorInd02CurTime;
  }
}

void lampTest() {
  digitalWrite(group01, HIGH);
  delay(500);
  digitalWrite(group02, HIGH);
  delay(500);
  digitalWrite(group03, HIGH);
  delay(500);
  digitalWrite(group04, HIGH);
  delay(500);
  digitalWrite(sensorInd01, HIGH);
  delay(500);
  digitalWrite(sensorInd02, HIGH);
  delay(2000);
  runOnce = 0;
  digitalWrite(group01, LOW);
  digitalWrite(group02, LOW);
  digitalWrite(group03, LOW);
  digitalWrite(group04, LOW);
  digitalWrite(sensorInd01, LOW);
  digitalWrite(sensorInd02, LOW);
  delay(500);
}


// Change the state of Group 01 Function Indicators
void group01Blink() {
  group01State = (group01State == HIGH) ? LOW : HIGH;
  digitalWrite(group01, group01State);
}

// Change the state of Group 02 Function Indicators
void group02Blink() {
  group02State = (group02State == HIGH) ? LOW : HIGH;
  digitalWrite(group02, group02State);
}

// Change the state of Group 03 Function Indicators
void group03Blink() {
  group03State = (group03State == HIGH) ? LOW : HIGH;
  digitalWrite(group03, group03State);
}

// Change the state of Group 04 Function Indicators
void group04Blink() {
  group04State = (group04State == HIGH) ? LOW : HIGH;
  digitalWrite(group04, group04State);
}

// Change the state of Sensor Indicator 01
void sensorInd01Blink() {
  sensorInd01State = (sensorInd01State == HIGH) ? LOW : HIGH;
  digitalWrite(sensorInd01, sensorInd01State);
}

// Change the state of Sensor Indicator 02
void sensorInd02Blink() {
  sensorInd02State = (sensorInd02State == HIGH) ? LOW : HIGH;
  digitalWrite(sensorInd02, sensorInd02State);
}           
        


Explanation of the code

This video is best viewed in full screen mode.

RETURN TO TOP OF PAGE


SOUND INDICATOR - MAKING THE ROBOT MOUTH LIGHT WITH HIS VOICE PATTERN

THIS SECTION IS COMING SOON AS OF MARCH 17, 2024

RETURN TO TOP OF PAGE




Skip's Messy Workbench ⇔ All rights reserved ⇔ Copyright © 2023-2024
Skip's Messy Workbench ⇔ Last updated: March 09, 2024
Page Background Image by wirestock on Freepik

Valid HTML!
Valid CSS!