Merge branch 'feature/#5-motion' into 'release'

Feature/#5 motion

See merge request wagner/lib!2
This commit is contained in:
mulbric1
2024-05-13 10:03:02 +00:00
14 changed files with 700 additions and 17 deletions

104
README.md
View File

@ -1,7 +1,10 @@
# Dezibot4 Lib # Dezibot4 Lib
## Introduction ## Introduction
This repository contains the Library for the Dezibot4.<br> This repository contains the Library for the Dezibot4.<br>
It is ment to serve as an Arduino-Library. Therefore the rules for arduinolibrary develop apply:<br> It is ment to serve as an Arduino-Library. Therefore the rules for arduinolibrary develop apply:<br>
* [Styleguide](https://docs.arduino.cc/learn/contributions/arduino-library-style-guide) * [Styleguide](https://docs.arduino.cc/learn/contributions/arduino-library-style-guide)
* [Libraryspecification](https://arduino.github.io/arduino-cli/0.35/library-specification/) * [Libraryspecification](https://arduino.github.io/arduino-cli/0.35/library-specification/)
* [Submission-requirements](https://github.com/arduino/library-registry/blob/main/FAQ.md#submission-requirements) * [Submission-requirements](https://github.com/arduino/library-registry/blob/main/FAQ.md#submission-requirements)
@ -9,22 +12,30 @@ It is ment to serve as an Arduino-Library. Therefore the rules for arduinolibrar
In the following the most important points and custom conventions are introduced. In the following the most important points and custom conventions are introduced.
## Code Conventions ## Code Conventions
### Don't pass reference ### Don't pass reference
To allow easy usability for users not familier with C++, prevent passing around references. It is better to use accessmethods
To allow easy usability for users not familier with C++, prevent passing around references. It is better to use
accessmethods
### Naming ### Naming
* methods are named in lowerCamelCase * methods are named in lowerCamelCase
* classes are named in UpperCamelCase * classes are named in UpperCamelCase
* folders containing components are named in lowerCamelCase * folders containing components are named in lowerCamelCase
* methods are named in lowerCamelCase * methods are named in lowerCamelCase
* constants are named in ALL_CAPS_SNAKE_CASE * constants are named in ALL_CAPS_SNAKE_CASE
* Values of Enums follow the conventions of constants
### Bytestream ### Bytestream
Every class that implements Byte-Based Communication needs to implement the Arduino Streaminterface Every class that implements Byte-Based Communication needs to implement the Arduino Streaminterface
### Components ### Components
Every component has a single .h file and one or more .cpp files.<br> Every component has a single .h file and one or more .cpp files.<br>
Every component is placed in a seperate folder under src/ that is named equvivalent to the class. Every component is placed in a seperate folder under src/ that is named equvivalent to the class.
The minimal structure of any .h file is<br> The minimal structure of any .h file is<br>
```c++ ```c++
#ifndef ClassName_h #ifndef ClassName_h
#define ClassName_h #define ClassName_h
@ -35,28 +46,51 @@ class ClassName{
``` ```
## Design Paradigm ## Design Paradigm
During desgin, the Dezibot isn't describe using it's part but instead it's functionality. Under the top-level Dezibotclass, there is a class for every functionality of the robot. Each of that classes consists of two parts.
During desgin, the Dezibot isn't describe using it's part but instead it's functionality. Under the top-level
Dezibotclass, there is a class for every functionality of the robot. Each of that classes consists of two parts.
### Part Instances ### Part Instances
Each component contains instances of every Robotpart that is used in that component. For example the Motion component contains two motorinstances, one for motorEast and one for motorWest.
Using these instances, it is possible to access more specific methods that interacts directly with the component (configure it, setSpeed,...) Each component contains instances of every Robotpart that is used in that component. For example the Motion component
contains two motorinstances, one for motorEast and one for motorWest.
Using these instances, it is possible to access more specific methods that interacts directly with the component (
configure it, setSpeed,...)
### Abstractions ### Abstractions
The components constains abstractions that combines multiple partMethods to ease the usability. For example for the motioncomponent provides an abstraction for the forwardmovement, that involves two motors and even another component (MotionDetection)
The components constains abstractions that combines multiple partMethods to ease the usability. For example for the
motioncomponent provides an abstraction for the forwardmovement, that involves two motors and even another component (
MotionDetection)
## Contributing ## Contributing
When contributing to the project please follow the rules below. At first, follow all rules from this readme. Further rules apply to the usage of git
When contributing to the project please follow the rules below. At first, follow all rules from this readme. Further
rules apply to the usage of git
### Branching ### Branching
Whenever working on the project, create a new branch from the current state of Develop. Whenever working on the project, create a new branch from the current state of Develop.
Branches should be named as `prefix/#issueid-shortdescription` where prefix is from {feature,fix,refactor}.<br> Branches should be named as `prefix/#issueid-shortdescription` where prefix is from {feature,fix,refactor}.<br>
When a branch is ready to be used in production, create a mergerequest. When a branch is ready to be used in production, create a mergerequest.
### Mergerequests ### Mergerequests
The target of each Mergerequest must be the Develop-Branch. Before the merge, each request must be approved by at least one person with Owner role.<br>
The target of each Mergerequest must be the Develop-Branch. Before the merge, each request must be approved by at least
one person with Owner role.<br>
The approve process should consider especially the documentation, naming, implementation. The approve process should consider especially the documentation, naming, implementation.
When the merge is approved and no more commits are added, the last commit must increment the versionnumber in the library.properties file, following the rules of [Semantic Versioning](https://semver.org/) When the merge is approved and no more commits are added, the last commit must increment the versionnumber in the
library.properties file, following the rules of [Semantic Versioning](https://semver.org/)
### Commitmessages ### Commitmessages
Commitmessages must follow the [gitchangelog](https://github.com/vaab/gitchangelog/blob/master/src/gitchangelog/gitchangelog.rc.reference) pattern.
Commitmessages must follow
the [gitchangelog](https://github.com/vaab/gitchangelog/blob/master/src/gitchangelog/gitchangelog.rc.reference) pattern.
### Language ### Language
The language of the project is American English. That includes in particular but not exclusively: The language of the project is American English. That includes in particular but not exclusively:
* Sourcecode * Sourcecode
* Commit Messages * Commit Messages
* Documentation * Documentation
@ -64,7 +98,9 @@ The language of the project is American English. That includes in particular but
A german documentation will be provided but does not replace the english documentation. A german documentation will be provided but does not replace the english documentation.
### Documentation ### Documentation
#### .h Files #### .h Files
```C++ ```C++
/** /**
* @file Dezibot.h * @file Dezibot.h
@ -77,7 +113,12 @@ A german documentation will be provided but does not replace the english documen
*/ */
``` ```
In the library, the `.h` files should be included using a relative path.
For instance, in `src/Dezibot.h`, to include `src/motion/Motion.h`, you should write `#include "motion/Motion.h"`.
#### Methods #### Methods
```C++ ```C++
/** /**
* @brief * @brief
@ -88,4 +129,47 @@ A german documentation will be provided but does not replace the english documen
*/ */
``` ```
#### Arduino Settings
* Board: "ESP32-S3-USB-OTG"
* Upload Mode: "UART0 / Hardware CDC"
* USB Mode: "Hardware CDC and JTAG"
* Programmer: "Esptool"
Using `arduino-cli` to compile and upload:
`arduino-cli upload /Users/jo/Documents/Arduino/theSketch -p /dev/cu.usbmodem101 -b esp32:esp32:nora_w10`
`arduino-cli compile /Users/jo/Documents/Arduino/theSketch -p /dev/cu.usbmodem101 -b esp32:esp32:nora_w10`
#### Display
It is important to specify the SDA and SCL ports by using `Wire.begin(SDA, SCL)`.
```c++
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void Dezibot::begin(void) {
Wire.begin(1, 2);
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
// Serial.println("SSD1306 allocation failed");
for (;;); // Don't proceed, loop forever
}
// Draw a single pixel in white
display.drawPixel(10, 10, SSD1306_WHITE);
// Show the display buffer on the screen. You MUST call display() after
// drawing commands to make them visible on screen!
display.display();
vTaskDelay(2000);
}
```

View File

@ -0,0 +1,19 @@
#include <Dezibot.h>
Dezibot dezibot = Dezibot();
const uint8_t MYFOO = 10;
void setup() {
dezibot.begin();
}
void loop() {
dezibot.motion.move();
delay(1000);
dezibot.motion.rotateAntiClockwise();
delay(1000);
dezibot.motion.rotateClockwise();
delay(1000);
dezibot.motion.stop();
delay(1000);
}

20
example/motion/motion.ino Normal file
View File

@ -0,0 +1,20 @@
#include <Dezibot.h>
Dezibot dezibot = Dezibot();
void setup() {
dezibot.begin();
Serial.begin(9600);
}
void loop() {
Serial.println("bla");
dezibot.motion.move(1000);
dezibot.multiColorLight.setLed(BOTTOM, RED);
delay(2000);
dezibot.motion.rotateAnticlockwise(1000);
dezibot.multiColorLight.setLed(BOTTOM, GREEN);
delay(2000);
dezibot.motion.rotateClockwise(1000);
dezibot.multiColorLight.setLed(BOTTOM, BLUE);
delay(2000);
dezibot.multiColorLight.turnOffLed();
delay(2000);
}

21
src/Dezibot.cpp Normal file
View File

@ -0,0 +1,21 @@
/**
* @file Dezibot.cpp
* @author Anton Jacker, Hans Haupt, Saskia Duebener
* @brief
* @version 0.1
* @date 2023-11-26
*
* @copyright Copyright (c) 2023
*
*/
#include "Dezibot.h"
Dezibot::Dezibot():multiColorLight(){
};
void Dezibot::begin(void) {
motion.begin();
multiColorLight.begin();
};

50
src/Dezibot.h Normal file
View File

@ -0,0 +1,50 @@
/**
* @file Dezibot.h
* @author your name (you@domain.com)
* @brief
* @version 0.1
* @date 2023-11-19
*
* @copyright Copyright (c) 2023
*
*/
#ifndef Dezibot_h
#define Dezibot_h
#include "motion/Motion.h"
#include "lightDetection/LightDetection.h"
#include "colorDetection/ColorDetection.h"
#include "multiColorLight/MultiColorLight.h"
#include "motionDetection/MotionDetection.h"
class Dezibot {
protected:
public:
Dezibot();
Motion motion;
LightDetection lightDetection;
ColorDetection colorDetection;
MultiColorLight multiColorLight;
MotionDetection motionDetection;
void begin(void);
/*
Display display
IRCommuncation irCommuncation (beinhaltet Kommuniaktion / Annhärung...)
Battery battery
Extension extension
WiFi wifi //wie wird WiFi geschrieben?
//nur lesender Zugriff, in dieser Klasse sind andere Instanzen mit dem Dezibotinterface gekapselt
Friends friends
OperatingSystem operatingSystem
USBCommunication usbCommunication
Button button
//nicht unique, initzial Dezibot
String robotName
*/
};
#endif //Dezibot_h

View File

@ -0,0 +1,7 @@
#ifndef ColorDetection_h
#define ColorDetection_h
class ColorDetection{
};
#endif //ColorDetection_h

View File

@ -0,0 +1,8 @@
#ifndef LightDetection_h
#define LightDetection_h
//beinhaltet IR + Tageslicht
class LightDetection{
};
#endif //LightDetection_h

90
src/motion/Motion.cpp Normal file
View File

@ -0,0 +1,90 @@
/**
* @file Motion.cpp
* @author Jonathan Schulze, Nick Hübenthal, Hans Haupt
* @brief Implementation of the Motion class.
* @version 0.2
* @date 2023-12-13
*
* @copyright Copyright (c) 2023
*
*/
#include "Motion.h"
TaskHandle_t xMoveTaskHandle = NULL;
TaskHandle_t xClockwiseTaskHandle = NULL;
TaskHandle_t xAntiClockwiseTaskHandle = NULL;
// Initialize the movement component.
void Motion::begin(void) {
ledc_timer_config_t motor_timer = {
.speed_mode = LEDC_MODE,
.duty_resolution = DUTY_RES,
.timer_num = TIMER,
.freq_hz = FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
ledc_timer_config(&motor_timer);
Motion::left.begin();
Motion::right.begin();
};
void Motion::moveTask(void * args) {
Motion::left.setSpeed(LEFT_MOTOR_DUTY);
Motion::right.setSpeed(RIGHT_MOTOR_DUTY);
vTaskDelay((uint32_t) args / portTICK_PERIOD_MS);
Motion::left.setSpeed(0);
Motion::right.setSpeed(0);
vTaskDelete(xMoveTaskHandle);
};
// Move forward for a certain amount of time.
void Motion::move(uint32_t moveForMs) {
if (moveForMs > 0){
xTaskCreate(moveTask, "Move", 4096, (void*)moveForMs, 10, &xMoveTaskHandle);
} else{
Motion::left.setSpeed(LEFT_MOTOR_DUTY);
Motion::right.setSpeed(RIGHT_MOTOR_DUTY);
}
};
void Motion::leftMotorTask(void * args) {
Motion::left.setSpeed(LEFT_MOTOR_DUTY);
Motion::right.setSpeed(0);
vTaskDelay((uint32_t) args / portTICK_PERIOD_MS);
Motion::left.setSpeed(0);
vTaskDelete(xClockwiseTaskHandle);
};
// Rotate clockwise for a certain amount of time.
void Motion::rotateClockwise(uint32_t rotateForMs) {
if (rotateForMs > 0){
xTaskCreate(leftMotorTask, "LeftMotor", 4096, (void*)rotateForMs, 10, &xClockwiseTaskHandle);
} else {
Motion::left.setSpeed(LEFT_MOTOR_DUTY);
Motion::right.setSpeed(0);
}
};
void Motion::rightMotorTask(void * args) {
Motion::right.setSpeed(RIGHT_MOTOR_DUTY);
Motion::left.setSpeed(0);
vTaskDelay((uint32_t) args / portTICK_PERIOD_MS);
Motion::right.setSpeed(0);
vTaskDelete(xAntiClockwiseTaskHandle);
};
// Rotate anticlockwise for a certain amount of time.
void Motion::rotateAntiClockwise(uint32_t rotateForMs) {
if(rotateForMs > 0){
xTaskCreate(rightMotorTask, "RightMotor", 4096, (void*)rotateForMs, 10, &xAntiClockwiseTaskHandle);
} else {
Motion::right.setSpeed(RIGHT_MOTOR_DUTY);
Motion::left.setSpeed(0);
}
};
void Motion::stop(void){
Motion::left.setSpeed(0);
Motion::right.setSpeed(0);
}

90
src/motion/Motion.h Normal file
View File

@ -0,0 +1,90 @@
/**
* @file Motion.h
* @author Jonathan Schulze, Nick Hübenthal, Hans Haupt
* @brief This component controls the ability to rotate and change position.
* @version 0.2
* @date 2023-12-13
*
* @copyright Copyright (c) 2023
*
*/
#ifndef Motion_h
#define Motion_h
#include <stdint.h>
#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "driver/ledc.h"
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define TIMER LEDC_TIMER_2
#define CHANNEL_LEFT LEDC_CHANNEL_3
#define CHANNEL_RIGHT LEDC_CHANNEL_4
#define DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
#define FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz
class Motor{
public:
Motor(uint8_t pin, ledc_timer_t timer, ledc_channel_t channel);
void begin(void);
void setSpeed(uint16_t duty);
uint16_t getSpeed(void);
protected:
uint8_t pin;
ledc_timer_t timer;
ledc_channel_t channel;
uint16_t duty;
};
class Motion{
protected:
static const uint16_t RIGHT_MOTOR_DUTY = 4096;
static const uint16_t LEFT_MOTOR_DUTY = 4096;
static const int MOTOR_RIGHT_PIN = 11;
static const int MOTOR_LEFT_PIN = 12;
static void moveTask(void * args);
static void leftMotorTask(void * args);
static void rightMotorTask(void * args);
public:
//Shared Timer to sync movement
static inline Motor left = Motor(MOTOR_LEFT_PIN,TIMER,CHANNEL_LEFT);
static inline Motor right = Motor(MOTOR_RIGHT_PIN,TIMER,CHANNEL_RIGHT);
/**
* @brief Initialize the movement component.
*
*/
void begin(void);
/**
* @brief Move forward for a certain amount of time.
* Call with moveForMs 0 will start movement, that must be stopped explicit by call to stop().
* @param moveForMs Representing the duration of forward moving in milliseconds.
*/
static void move(uint32_t moveForMs=0);
/**
* @brief Rotate clockwise for a certain amount of time.
* Call with moveForMs 0 will start movement, that must be stopped explicit by call to stop().
* @param rotateForMs Representing the duration of rotating clockwise in milliseconds.
*/
static void rotateClockwise(uint32_t rotateForMs=0);
/**
* @brief Rotate anticlockwise for a certain amount of time.
* Call with moveForMs 0 will start movement, that must be stopped explicit by call to stop().
* @param rotateForMs Representing the duration of rotating anticlockwise in milliseconds.
*/
static void rotateAntiClockwise(uint32_t rotateForMs=0);
/**
* @brief stops any current movement, no matter if timebased or endless
*
*/
static void stop(void);
};
#endif //Motion_h

33
src/motion/Motor.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "Motion.h"
Motor::Motor(uint8_t pin, ledc_timer_t timer, ledc_channel_t channel){
this->pin = pin;
this->channel = channel;
this->timer = timer;
this->duty = 0;
};
void Motor::begin(void){
pinMode(this->pin,OUTPUT);
ledc_channel_config_t channelConfig = {
.gpio_num = this->pin,
.speed_mode = LEDC_MODE,
.channel = this->channel,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = this->timer,
.duty = 0, // Set duty to 0%
.hpoint = 0
};
ledc_channel_config(&channelConfig);
Serial.println("Motor begin done");
};
void Motor::setSpeed(uint16_t duty){
this->duty = duty;
ledc_set_duty(LEDC_MODE,this->channel,duty);
ledc_update_duty(LEDC_MODE,this->channel);
};
uint16_t Motor::getSpeed(void){
return this->duty;
};

View File

@ -0,0 +1,6 @@
#ifndef MotionDetection_h
#define MotionDetection_h
class MotionDetection{
};
#endif //MotionDetection

View File

@ -0,0 +1,9 @@
static const uint32_t RED = 0xFF0000;
static const uint32_t GREEN = 0x00FF00;
static const uint32_t BLUE = 0x0000FF;
static const uint32_t WHITE = 0xFFFFFF;
static const uint32_t ORANGE = 0x961E00;
static const uint32_t YELLOW = 0x965000;
static const uint32_t TURQUOISE = 0x005064;
static const uint32_t PURPEL = 0x320064;
static const uint32_t PINK = 0x960064;

View File

@ -0,0 +1,107 @@
#include "MultiColorLight.h"
MultiColorLight::MultiColorLight():rgbLeds(ledAmount,ledPin){
};
void MultiColorLight::begin(void){
rgbLeds.begin();
};
void MultiColorLight::setLed(uint8_t index , uint32_t color){
if (index > ledAmount-1){
//TODO: logging
}
rgbLeds.setPixelColor(index, normalizeColor(color));
rgbLeds.show();
};
void MultiColorLight::setLed(leds leds, uint32_t color){
switch (leds){
case TOP_LEFT:
MultiColorLight::setLed(1,color);break;
case TOP_RIGHT:
MultiColorLight::setLed(0,color);break;
case BOTTOM:
MultiColorLight::setLed(2,color);break;
case TOP:
for (int index = 0; index<2; index++){
MultiColorLight::setLed(index,color);
}break;
case ALL:
for (int index = 0; index<ledAmount; index++){
MultiColorLight::setLed(index,color);
}break;
default:
//TODO logging
break;
}
};
void MultiColorLight::setLed(leds leds, uint8_t red, uint8_t green, uint8_t blue){
MultiColorLight::setLed(leds, MultiColorLight::color(red,green,blue));
};
void MultiColorLight::setTopLeds(uint32_t color){
MultiColorLight::setLed(TOP,color);
};
void MultiColorLight::setTopLeds(uint8_t red, uint8_t green, uint8_t blue){
MultiColorLight::setTopLeds(MultiColorLight::color(red,green,blue));
};
void MultiColorLight::blink(uint16_t amount,uint32_t color, leds leds, uint32_t interval){
for(uint16_t index = 0; index < amount;index++){
MultiColorLight::setLed(leds, color);
vTaskDelay(interval);
MultiColorLight::turnOffLed(leds);
vTaskDelay(interval);
}
};
void MultiColorLight::turnOffLed(leds leds){
switch (leds){
case TOP_LEFT:
MultiColorLight::setLed(1,0);break;
case TOP_RIGHT:
MultiColorLight::setLed(0,0);break;
case BOTTOM:
MultiColorLight::setLed(2,0);break;
case TOP:
for (int index = 0; index<2; index++){
MultiColorLight::setLed(index,0);
}break;
case ALL:
for (int index = 0; index<3; index++){
MultiColorLight::setLed(index,0);
}break;
default:
//TODO logging
break;
}
};
uint32_t MultiColorLight::color(uint8_t r, uint8_t g, uint8_t b){
return rgbLeds.Color(r,g,b);
};
//PRIVATE
uint32_t MultiColorLight::normalizeColor(uint32_t color,uint8_t maxBrightness){
uint8_t red = (color&0x00FF0000)>>16;
uint8_t green = (color&0x0000FF00)>>8;
uint8_t blue = (color&0x000000FF);
if (red > maxBrightness){
red = maxBrightness;
}
if(green > maxBrightness-70){
green = maxBrightness-70;
}
if(blue > maxBrightness-50){
blue = maxBrightness-50;
}
return MultiColorLight::color(red,green,blue);
}

View File

@ -0,0 +1,139 @@
/**
* @file MultiColorLight.h
* @author Saskia Duebener, Hans Haupt
* @brief This component controls the ability to show multicolored light, using the RGB-LEDs
* @version 0.2
* @date 2023-11-25
*
* @copyright Copyright (c) 2023
*
*/
#ifndef MultiColorLight_h
#define MultiColorLight_h
#include <Adafruit_NeoPixel.h>
#include "ColorConstants.h"
/**
* @brief Describes combinations of leds on the Dezibot.
* With the Robot in Front of you, when the robot drives away from you, the left LED is TOP_LEFT
*
*/
enum leds{
TOP_LEFT,
TOP_RIGHT,
BOTTOM,
TOP,
ALL
};
class MultiColorLight{
protected:
static const uint16_t ledAmount = 3;
static const int16_t ledPin = 48;
static const uint8_t maxBrightness = 150;
Adafruit_NeoPixel rgbLeds;
public:
MultiColorLight();
/**
* @brief initialize the multicolor component
*
*/
void begin(void);
/**
* @brief Set the specified led to the passed color
* @param index ranging from 0-2, 0: Right, 1: Left, 2: Bottom
* @param color A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component. Each color can range between 0 to 100
*/
void setLed(uint8_t index , uint32_t color);
/**
* @brief Set the specified leds to the passed color value
*
* @param leds which leds should be updated
* @param color A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component. Each color can range between 0 to 100
*/
void setLed(leds leds, uint32_t color);
/**
* @brief Set the specified leds to the passed color value
*
* @param leds which leds should be updated
* @param red brightness of red, is normalized in the function
* @param green brightness of green, is normalized in the function
* @param blue brightness of blue, is normalized in the function
*/
void setLed(leds leds, uint8_t red, uint8_t green, uint8_t blue);
/**
* @brief sets the two leds on the top of the robot to the specified color
*
* @param color A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component. Each color can range between 0 to 100
*/
void setTopLeds(uint32_t color);
/**
* @brief sets the two leds on the top of the robot to the specified color
*
* @param red brightness of red, is normalized in the function
* @param green brightness of green, is normalized in the function
* @param blue brightness of blue, is normalized in the function
*/
void setTopLeds(uint8_t red, uint8_t green, uint8_t blue);
/**
* @brief Let LEDs blink, returns after all blinks were executed
*
* @param amount how often should the leds blink
* @param color A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component.
* Each color can range between 0 to 100
* Defaults to blue
* @param leds which LEDs should blink, default is TOP
* @param interval how many miliseconds the led is on, defaults to 1s
*/
void blink(uint16_t amount,uint32_t color = 0x00006400,leds leds=TOP, uint32_t interval=1000);
/**
* @brief turn off the given leds
*
* @param leds which leds should be turned off, defaults to ALL
*/
void turnOffLed(leds leds=ALL);
/**
* @brief wrapper to calulate the used colorformat from a rgb-value
*
* @param r red (0-100)
* @param g green (0-100)
* @param b blue (0-100)
* @return A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component.
*/
uint32_t color(uint8_t r, uint8_t g, uint8_t b);
private:
/**
* @brief normalizes every component of color to not exeed the maxBrightness
*
* @param color A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component.
* @param maxBrigthness maximal level of brightness that is allowed for each color
* @return uint32_t A 32-bit unsigned integer representing the color in the format
* 0x00RRGGBB, where RR is the red component, GG is the green
* component, and BB is the blue component. Where each component can be
* between 0 - maxBrightness
*/
uint32_t normalizeColor(uint32_t color, uint8_t maxBrigthness=maxBrightness);
};
#endif //MultiColorLight_h