commit
582860d2ab
@ -0,0 +1,5 @@
|
|||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||||
|
// for the documentation about the extensions.json format
|
||||||
|
"recommendations": [
|
||||||
|
"platformio.platformio-ide"
|
||||||
|
],
|
||||||
|
"unwantedRecommendations": [
|
||||||
|
"ms-vscode.cpptools-extension-pack"
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include "WS2812Manager.hpp"
|
||||||
|
|
||||||
|
class HellMetServo{
|
||||||
|
private:
|
||||||
|
int _origin = 0;
|
||||||
|
int _movement = 0;
|
||||||
|
int _pin = -1;
|
||||||
|
int _start = 0;
|
||||||
|
float lastAngle = 0;
|
||||||
|
float _target = 0;
|
||||||
|
volatile float _angle = 0;
|
||||||
|
volatile int servoHandle = 0;
|
||||||
|
bool wasClosing = false;
|
||||||
|
public:
|
||||||
|
HellMetServo(int origin, int movement, int pin);
|
||||||
|
void StartToggle();
|
||||||
|
void StartOpen();
|
||||||
|
void StartClose();
|
||||||
|
bool Step();
|
||||||
|
void Disable();
|
||||||
|
void Enable();
|
||||||
|
int getCurrentAngle(){return _angle;}
|
||||||
|
int getCurrentTarget(){return _target;}
|
||||||
|
int getPin(){return _pin;}
|
||||||
|
int getHandle(){return servoHandle;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HellMetServoManager{
|
||||||
|
private:
|
||||||
|
std::vector<HellMetServo*> topServos = std::vector<HellMetServo*>();
|
||||||
|
std::vector<HellMetServo*> bottomServos = std::vector<HellMetServo*>();
|
||||||
|
std::vector<HellMetServo*> allServos = std::vector<HellMetServo*>();
|
||||||
|
int timingsArray[11] = {20,15,7,1,1,1,1,7,15,20,20};
|
||||||
|
void ToggleAll();
|
||||||
|
public:
|
||||||
|
volatile bool in_use = false;
|
||||||
|
HellMetServoManager();
|
||||||
|
static void ToggleAllWrapper(void *classInstance);
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
#include <wire.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class I2CDevice{
|
||||||
|
protected:
|
||||||
|
int _writeAddress = 0x00;
|
||||||
|
int _readAddress = 0xFF;
|
||||||
|
std::string _name = "";
|
||||||
|
public:
|
||||||
|
int getWriteAddress(){return _writeAddress;}
|
||||||
|
int getReadAddress(){return _readAddress;}
|
||||||
|
std::string getname(){return _name;}
|
||||||
|
virtual bool checkAlive(){return false;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class I2CManager{
|
||||||
|
protected:
|
||||||
|
static std::vector<I2CDevice*> _Devices;
|
||||||
|
static int _pinSCL;
|
||||||
|
static int _pinSDA;
|
||||||
|
public:
|
||||||
|
static void Setup(int pinSDA, int pinSCL);
|
||||||
|
static void I2CWrite(int address, int value);
|
||||||
|
static int I2CRead(int address, int size);
|
||||||
|
static void writeToRegister8bit(int message, int targetRegister, int i2cAddress);
|
||||||
|
static void registerNewDevice(I2CDevice* device){_Devices.push_back(device);}
|
||||||
|
static void scanAll();
|
||||||
|
};
|
@ -0,0 +1,26 @@
|
|||||||
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/task.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
|
||||||
|
extern SemaphoreHandle_t serial_mutex;
|
||||||
|
|
||||||
|
extern void THREAD_SAFE_PRINTLN(String data);
|
||||||
|
|
||||||
|
enum debugLevel{
|
||||||
|
none = 0,
|
||||||
|
error = 1,
|
||||||
|
warn = 2,
|
||||||
|
info = 3,
|
||||||
|
verbose = 4 //only use as a last resort, it makes things go real bad on the serial port
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEBUGLEVEL debugLevel::info
|
||||||
|
|
||||||
|
#define LOG_ERROR(x) do { if (DEBUGLEVEL >= debugLevel::error) { THREAD_SAFE_PRINTLN(x); } } while (0)
|
||||||
|
|
||||||
|
#define LOG_WARN(x) do { if (DEBUGLEVEL >= debugLevel::warn) { THREAD_SAFE_PRINTLN(x); } } while (0)
|
||||||
|
|
||||||
|
#define LOG_INFO(x) do { if (DEBUGLEVEL >= debugLevel::info) { THREAD_SAFE_PRINTLN(x); }} while (0)
|
||||||
|
|
||||||
|
#define LOG_VERBOSE(x) do { if (DEBUGLEVEL >= debugLevel::verbose) { THREAD_SAFE_PRINTLN(x); }} while (0)
|
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
This directory is intended for project header files.
|
||||||
|
|
||||||
|
A header file is a file containing C declarations and macro definitions
|
||||||
|
to be shared between several project source files. You request the use of a
|
||||||
|
header file in your project source file (C, C++, etc) located in `src` folder
|
||||||
|
by including it, with the C preprocessing directive `#include'.
|
||||||
|
|
||||||
|
```src/main.c
|
||||||
|
|
||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Including a header file produces the same results as copying the header file
|
||||||
|
into each source file that needs it. Such copying would be time-consuming
|
||||||
|
and error-prone. With a header file, the related declarations appear
|
||||||
|
in only one place. If they need to be changed, they can be changed in one
|
||||||
|
place, and programs that include the header file will automatically use the
|
||||||
|
new version when next recompiled. The header file eliminates the labor of
|
||||||
|
finding and changing all the copies as well as the risk that a failure to
|
||||||
|
find one copy will result in inconsistencies within a program.
|
||||||
|
|
||||||
|
In C, the usual convention is to give header files names that end with `.h'.
|
||||||
|
It is most portable to use only letters, digits, dashes, and underscores in
|
||||||
|
header file names, and at most one dot.
|
||||||
|
|
||||||
|
Read more about using header files in official GCC documentation:
|
||||||
|
|
||||||
|
* Include Syntax
|
||||||
|
* Include Operation
|
||||||
|
* Once-Only Headers
|
||||||
|
* Computed Includes
|
||||||
|
|
||||||
|
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
@ -0,0 +1,15 @@
|
|||||||
|
#include<Freenove_WS2812_Lib_for_ESP32.h>
|
||||||
|
|
||||||
|
class WS2812Manager{
|
||||||
|
private:
|
||||||
|
Freenove_ESP32_WS2812* strip;
|
||||||
|
int _ledCount;
|
||||||
|
void RGBCycleAll(int tempo);
|
||||||
|
void setAllColor(int R, int G, int B);
|
||||||
|
void BreatheOutAllColor(int R, int G, int B, int tempo);
|
||||||
|
void BreatheInAllColor(int R, int G, int B, int tempo);
|
||||||
|
void BreatheAllColor(int R, int G, int B, int tempo);
|
||||||
|
public:
|
||||||
|
WS2812Manager(int ledPin, int ledCount);
|
||||||
|
static void RunRGB(void *classInstance);
|
||||||
|
};
|
@ -0,0 +1,24 @@
|
|||||||
|
#include "I2CManagement.hpp"
|
||||||
|
#define X 0
|
||||||
|
#define Y 1
|
||||||
|
#define Z 2
|
||||||
|
|
||||||
|
class Hmc5883L : I2CDevice{
|
||||||
|
protected:
|
||||||
|
int16_t values[3] = {0,0,0};
|
||||||
|
double valuesScaled[3] = {0,0,0};
|
||||||
|
double radius = 0;
|
||||||
|
double azimuth = 0;
|
||||||
|
double elevation = 0;
|
||||||
|
double heading = 0;
|
||||||
|
void readRawValues();
|
||||||
|
public:
|
||||||
|
Hmc5883L(int readAddress, int writeAddress);
|
||||||
|
void beginUpdateTask();
|
||||||
|
void update();
|
||||||
|
static void beginUpdateTaskWrapper(void *classInstance);
|
||||||
|
bool checkAlive() override {return true;}
|
||||||
|
String getRawValuesWithSeparator();
|
||||||
|
String getHeadingValue(){return String(heading);}
|
||||||
|
String getDebugValues();
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
#include "HellMetServo.hpp"
|
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
This directory is intended for project specific (private) libraries.
|
||||||
|
PlatformIO will compile them to static libraries and link into executable file.
|
||||||
|
|
||||||
|
The source code of each library should be placed in a an own separate directory
|
||||||
|
("lib/your_library_name/[here are source files]").
|
||||||
|
|
||||||
|
For example, see a structure of the following two libraries `Foo` and `Bar`:
|
||||||
|
|
||||||
|
|--lib
|
||||||
|
| |
|
||||||
|
| |--Bar
|
||||||
|
| | |--docs
|
||||||
|
| | |--examples
|
||||||
|
| | |--src
|
||||||
|
| | |- Bar.c
|
||||||
|
| | |- Bar.h
|
||||||
|
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|
||||||
|
| |
|
||||||
|
| |--Foo
|
||||||
|
| | |- Foo.c
|
||||||
|
| | |- Foo.h
|
||||||
|
| |
|
||||||
|
| |- README --> THIS FILE
|
||||||
|
|
|
||||||
|
|- platformio.ini
|
||||||
|
|--src
|
||||||
|
|- main.c
|
||||||
|
|
||||||
|
and a contents of `src/main.c`:
|
||||||
|
```
|
||||||
|
#include <Foo.h>
|
||||||
|
#include <Bar.h>
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
PlatformIO Library Dependency Finder will find automatically dependent
|
||||||
|
libraries scanning project source files.
|
||||||
|
|
||||||
|
More information about PlatformIO Library Dependency Finder
|
||||||
|
- https://docs.platformio.org/page/librarymanager/ldf.html
|
@ -0,0 +1,25 @@
|
|||||||
|
; PlatformIO Project Configuration File
|
||||||
|
;
|
||||||
|
; Build options: build flags, source filter
|
||||||
|
; Upload options: custom upload port, speed and extra flags
|
||||||
|
; Library options: dependencies, extra library storages
|
||||||
|
; Advanced options: extra scripting
|
||||||
|
;
|
||||||
|
; Please visit documentation for the other options and examples
|
||||||
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
|
[env:esp32-c3-devkitm-1]
|
||||||
|
platform = espressif32
|
||||||
|
board = esp32-c3-devkitm-1
|
||||||
|
framework = arduino
|
||||||
|
;board_upload.flash_size=2MB
|
||||||
|
lib_deps =
|
||||||
|
khoih-prog/ESP32_C3_ISR_Servo@^1.2.0
|
||||||
|
freenove/Freenove WS2812 Lib for ESP32@^1.0.5
|
||||||
|
monitor_speed = 460800
|
||||||
|
build_flags =
|
||||||
|
-D ARDUINO_USB_MODE=1
|
||||||
|
-D ARDUINO_USB_CDC_ON_BOOT=1
|
||||||
|
-D SERIALCONS=USBSerial
|
||||||
|
;board_build.filesystem = littlefs
|
||||||
|
;board_build.partitions = minimal.csv
|
@ -0,0 +1,116 @@
|
|||||||
|
#include "HellMetServo.hpp"
|
||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
|
||||||
|
#define USE_ESP32_TIMER_NO 1
|
||||||
|
#define TIMER_INTERRUPT_DEBUG 0
|
||||||
|
#define ISR_SERVO_DEBUG 0
|
||||||
|
#define MIN_MICROS 800
|
||||||
|
#define MAX_MICROS 2450
|
||||||
|
#define ADDITIONNAL_MOVEMENT_OFFSET 25
|
||||||
|
|
||||||
|
#include <ESP32_C3_ISR_Servo.h>
|
||||||
|
|
||||||
|
HellMetServo::HellMetServo(int origin, int movement, int pin) : _origin(origin), _movement(movement), _pin(pin){
|
||||||
|
LOG_INFO("Creating servo on pin" + String(pin));
|
||||||
|
servoHandle = ESP32_ISR_Servos.setupServo(pin, MIN_MICROS, MAX_MICROS);
|
||||||
|
LOG_INFO("Servo Created with handle" + String(servoHandle));
|
||||||
|
lastAngle = origin;
|
||||||
|
_angle = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServo::StartToggle(){
|
||||||
|
wasClosing ? StartOpen() : StartClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServo::StartClose(){
|
||||||
|
_start = _origin-_movement;
|
||||||
|
_target = _origin;
|
||||||
|
_angle = _start;
|
||||||
|
wasClosing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServo::StartOpen(){
|
||||||
|
_start = _origin;
|
||||||
|
_target = _origin-_movement;
|
||||||
|
_angle = _start;
|
||||||
|
wasClosing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HellMetServo::Step(){
|
||||||
|
if(_angle == _target) return true;
|
||||||
|
float completion = abs(_target - lastAngle);
|
||||||
|
_angle += (_angle > _target) ? -1 : 1;
|
||||||
|
lastAngle = _angle;
|
||||||
|
if(_angle > 180 || _angle < 0 || !ESP32_ISR_Servos.setPosition(servoHandle, _angle)){
|
||||||
|
LOG_ERROR("Error moving servo "+String(_pin)+" to angle "+_angle);
|
||||||
|
return true; //stop
|
||||||
|
}
|
||||||
|
return _angle == _target;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServo::Disable(){
|
||||||
|
if(!ESP32_ISR_Servos.disable(servoHandle))
|
||||||
|
LOG_ERROR("Error disableing servo "+String(_pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServo::Enable(){
|
||||||
|
if(!ESP32_ISR_Servos.enable(servoHandle))
|
||||||
|
LOG_ERROR("Error enabling servo "+String(_pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
//HellMetServoManager defintions ---------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HellMetServoManager::HellMetServoManager(){
|
||||||
|
ESP32_ISR_Servos.useTimer(USE_ESP32_TIMER_NO);
|
||||||
|
|
||||||
|
allServos.push_back(new HellMetServo(90+3+ADDITIONNAL_MOVEMENT_OFFSET, (50+ADDITIONNAL_MOVEMENT_OFFSET), GPIO_NUM_3)); //Top right
|
||||||
|
allServos.push_back(new HellMetServo(78+0+6+ADDITIONNAL_MOVEMENT_OFFSET, (50+ADDITIONNAL_MOVEMENT_OFFSET), GPIO_NUM_2)); //bottom right
|
||||||
|
allServos.push_back(new HellMetServo(28+4+1-ADDITIONNAL_MOVEMENT_OFFSET, -(50+ADDITIONNAL_MOVEMENT_OFFSET), GPIO_NUM_4)); //bottom left
|
||||||
|
allServos.push_back(new HellMetServo(28+13-ADDITIONNAL_MOVEMENT_OFFSET, -(50+ADDITIONNAL_MOVEMENT_OFFSET), GPIO_NUM_5)); //top left
|
||||||
|
//vTaskDelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServoManager::ToggleAll(){
|
||||||
|
LOG_INFO("Beginning Toggle for "+String(allServos.size())+" servos");
|
||||||
|
for (HellMetServo* servo : allServos)
|
||||||
|
{
|
||||||
|
LOG_INFO("Enabling");
|
||||||
|
servo->Enable();
|
||||||
|
LOG_INFO("Toggling");
|
||||||
|
servo->StartToggle();
|
||||||
|
}
|
||||||
|
LOG_INFO("Done enabling servos");
|
||||||
|
bool finished = false;
|
||||||
|
int i = 0;
|
||||||
|
while(!finished){
|
||||||
|
finished = true;
|
||||||
|
for(HellMetServo* servo : allServos){
|
||||||
|
i++;
|
||||||
|
LOG_WARN("not finished for servo "+String(servo->getHandle())+" angle: "+String(servo->getCurrentAngle())+" target: "+String(servo->getCurrentTarget()));
|
||||||
|
if(!servo->Step()){
|
||||||
|
LOG_INFO("Servo returned false "+String(i));
|
||||||
|
finished = false;
|
||||||
|
}
|
||||||
|
LOG_INFO("Servo didn't return false "+String(i));
|
||||||
|
}
|
||||||
|
vTaskDelay(10/ portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
LOG_INFO("Done moving servos");
|
||||||
|
vTaskDelay(100/ portTICK_RATE_MS);
|
||||||
|
|
||||||
|
for (HellMetServo* servo : allServos)
|
||||||
|
{
|
||||||
|
servo->Disable();
|
||||||
|
}
|
||||||
|
LOG_INFO("Toggle done");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HellMetServoManager::ToggleAllWrapper(void *classInstance){
|
||||||
|
// Get a pointer to the object instance
|
||||||
|
HellMetServoManager *obj = static_cast<HellMetServoManager *>(classInstance);
|
||||||
|
obj->in_use = true;
|
||||||
|
// Call the object method
|
||||||
|
obj->ToggleAll();
|
||||||
|
obj->in_use = false;
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
@ -0,0 +1,54 @@
|
|||||||
|
#include "I2CManagement.hpp"
|
||||||
|
#include <arduino.h>
|
||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
|
||||||
|
std::vector<I2CDevice*> I2CManager::_Devices = std::vector<I2CDevice*>();
|
||||||
|
int I2CManager::_pinSCL;
|
||||||
|
int I2CManager::_pinSDA;
|
||||||
|
|
||||||
|
void I2CManager::Setup(int pinSDA, int pinSCL){
|
||||||
|
_pinSCL = pinSCL;
|
||||||
|
_pinSDA = pinSDA;
|
||||||
|
Wire.setPins(_pinSDA, _pinSCL);
|
||||||
|
Wire.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
int I2CManager::I2CRead(int address, int size){
|
||||||
|
return Wire.requestFrom(address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CManager::I2CWrite(int address, int value){
|
||||||
|
Wire.beginTransmission(address);
|
||||||
|
Wire.write(value);
|
||||||
|
Wire.endTransmission();
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CManager::writeToRegister8bit(int message, int targetRegister, int i2cAddress){
|
||||||
|
Wire.beginTransmission(i2cAddress); // Begins a transmission to the I2C slave
|
||||||
|
Serial.print(Wire.write(targetRegister)); // ask to write to this register
|
||||||
|
Serial.print(Wire.write(message)); // set this register's value to the message value (byte)
|
||||||
|
Wire.endTransmission(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CManager::scanAll(){
|
||||||
|
Serial.println ();
|
||||||
|
Serial.println ("I2C scanner. Scanning ...");
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 8; i < 120; i++)
|
||||||
|
{
|
||||||
|
Wire.beginTransmission (i); // Begin I2C transmission Address (i)
|
||||||
|
if (Wire.endTransmission () == 0) // Receive 0 = success (ACK response)
|
||||||
|
{
|
||||||
|
Serial.print ("Found address: ");
|
||||||
|
Serial.print (i, DEC);
|
||||||
|
Serial.print (" (0x");
|
||||||
|
Serial.print (i, HEX); // PCF8574 7 bit address
|
||||||
|
Serial.println (")");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Serial.print ("Found ");
|
||||||
|
Serial.print (count, DEC); // numbers of devices
|
||||||
|
Serial.println (" device(s).");
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
|
||||||
|
void THREAD_SAFE_PRINTLN(String data)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Wait for the mutex to be available
|
||||||
|
xSemaphoreTake(serial_mutex, 10);
|
||||||
|
|
||||||
|
// Use the Serial class to send and receive data
|
||||||
|
Serial.println(data);
|
||||||
|
|
||||||
|
// Release the mutex
|
||||||
|
xSemaphoreGive(serial_mutex);
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
#include "WS2812Manager.hpp"
|
||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
|
||||||
|
WS2812Manager::WS2812Manager(int ledPin, int ledCount){
|
||||||
|
strip = new Freenove_ESP32_WS2812(ledCount,ledPin);
|
||||||
|
_ledCount = ledCount;
|
||||||
|
if(!strip->begin())
|
||||||
|
LOG_ERROR("WS2812Manager() error");
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::RGBCycleAll(int tempo){
|
||||||
|
strip->setBrightness(255);
|
||||||
|
for (int j = 0; j < 255; j++) { //cycle to blue
|
||||||
|
for (int i = 0; i < _ledCount; i++) {
|
||||||
|
strip->setLedColorData(i, strip->Wheel((i * 256 / _ledCount + j) & 255));
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("RGBCycleAll to blue");
|
||||||
|
strip->show();
|
||||||
|
vTaskDelay(tempo/ portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
for (int j = 255; j > 0; j--) { //cycle back to red
|
||||||
|
for (int i = 0; i < _ledCount; i++) {
|
||||||
|
strip->setLedColorData(i, strip->Wheel((i * 256 / _ledCount + j) & 255));
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("RGBCycleAll to red");
|
||||||
|
strip->show();
|
||||||
|
vTaskDelay(tempo/ portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::setAllColor(int R, int G, int B){
|
||||||
|
LOG_VERBOSE(String("setAllColor ")+String(R)+String(G)+String(B));
|
||||||
|
esp_err_t error = strip->setAllLedsColor(R,G,B);
|
||||||
|
if(error != 0){
|
||||||
|
LOG_VERBOSE("setAllColor ERROR "+String(error));
|
||||||
|
}
|
||||||
|
//strip->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::BreatheInAllColor(int R, int G, int B, int tempo){
|
||||||
|
LOG_VERBOSE("BreatheInAllColor");
|
||||||
|
LOG_VERBOSE("BreatheInAllColor set color done");
|
||||||
|
setAllColor(R,G,B);
|
||||||
|
for(int i = 0; i < 255; i++){
|
||||||
|
strip->setBrightness(i);
|
||||||
|
LOG_VERBOSE("BreatheInAllColor " + String(i)
|
||||||
|
+' '+String(R) + ":" +String(G) + ":"+ String(B));
|
||||||
|
vTaskDelay(tempo/ portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::BreatheOutAllColor(int R, int G, int B, int tempo){
|
||||||
|
LOG_INFO("BreatheOutAllColor");
|
||||||
|
LOG_INFO("BreatheOutAllColor set color done");
|
||||||
|
for(int i = 254; i > 0; i--){
|
||||||
|
setAllColor(R,G,B);
|
||||||
|
strip->setBrightness(i);
|
||||||
|
LOG_INFO("BreatheOutAllColor " + String(i)
|
||||||
|
+' '+String(R) + ":" +String(G) + ":"+ String(B));
|
||||||
|
vTaskDelay(tempo/ portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::BreatheAllColor(int R, int G, int B, int tempo){
|
||||||
|
BreatheInAllColor(R,B,G,tempo);
|
||||||
|
BreatheOutAllColor(R,G,B,tempo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WS2812Manager::RunRGB(void *classInstance){
|
||||||
|
// Get a pointer to the object instance
|
||||||
|
WS2812Manager *obj = static_cast<WS2812Manager *>(classInstance);
|
||||||
|
while(true){
|
||||||
|
obj->RGBCycleAll(10);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
#include "hmc5883L.hpp"
|
||||||
|
#include <math.h>
|
||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
|
||||||
|
#define _x valuesScaled[X]
|
||||||
|
#define _y valuesScaled[Y]
|
||||||
|
#define _z valuesScaled[Z]
|
||||||
|
|
||||||
|
Hmc5883L::Hmc5883L(int readAddress = 0x1E, int writeAddress = 0x1E){
|
||||||
|
_readAddress = readAddress;
|
||||||
|
_writeAddress = writeAddress;
|
||||||
|
LOG_INFO("Setting up Hmc5883L");
|
||||||
|
I2CManager::writeToRegister8bit(0b01110000, 0x00 , writeAddress ); //Configuration Register A
|
||||||
|
I2CManager::writeToRegister8bit(0b11100000, 0x01 , writeAddress ); //Configuration Register B
|
||||||
|
I2CManager::writeToRegister8bit(0b00000000, 0x02 , writeAddress ); //Mode register continuous measurement mode
|
||||||
|
LOG_INFO("Done setting up Hmc5883L");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hmc5883L::beginUpdateTask(){
|
||||||
|
while(true){
|
||||||
|
vTaskDelay(100/ portTICK_RATE_MS);
|
||||||
|
LOG_VERBOSE("reading raw values");
|
||||||
|
readRawValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hmc5883L::beginUpdateTaskWrapper(void *classInstance){
|
||||||
|
LOG_INFO("beginUpdateTaskWrapper");
|
||||||
|
Hmc5883L *obj = static_cast<Hmc5883L *>(classInstance);
|
||||||
|
obj->beginUpdateTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hmc5883L::readRawValues(){
|
||||||
|
LOG_VERBOSE("Obtaining raw data");
|
||||||
|
Wire.beginTransmission(_readAddress);
|
||||||
|
Wire.write(0x03); // starting with register 0x03 (Data Output X MSB Register) [HMC5883L datasheet page 11]
|
||||||
|
Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. As a result, the connection is kept active.
|
||||||
|
Wire.requestFrom(_readAddress, 6, 1); // request a total of 3*2=6 registers, and send the stop message
|
||||||
|
LOG_VERBOSE("Obtained raw data");
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
values[i] = Wire.read() << 8 | Wire.read(); //we read the two registers at the same time, and concat them to get the full uint16_t (2*8)
|
||||||
|
valuesScaled[i] = ((double)values[i]);
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("Concatenated and scaled the data");
|
||||||
|
radius = sqrt(pow(valuesScaled[X],2) + pow(valuesScaled[Y],2) + pow(valuesScaled[Z],2));
|
||||||
|
azimuth = atan2(valuesScaled[Y], valuesScaled[X]);
|
||||||
|
elevation = atan2(valuesScaled[Z], sqrt(pow(valuesScaled[X], 2) + pow(valuesScaled[Y], 2)));
|
||||||
|
heading = atan2(values[Y], values[X]) * 180 / M_PI;
|
||||||
|
LOG_VERBOSE("Recovered heading: "+String(heading));
|
||||||
|
double head = 0;
|
||||||
|
if (_x > 0) {
|
||||||
|
heading = 90 - std::atan(_z/_x) * 180/M_PI;
|
||||||
|
} else if (_x < 0) {
|
||||||
|
heading = 270 - std::atan(_z/_x) * 180/M_PI;
|
||||||
|
} else {
|
||||||
|
if (_z < 0) {
|
||||||
|
heading = 180.0;
|
||||||
|
} else {
|
||||||
|
heading = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String Hmc5883L::getDebugValues(){
|
||||||
|
return "X:" + String(_x) + "\nY:" + String(_y) +"\nZ:"+ String(_z);
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
#include "main.hpp"
|
||||||
|
#include "PinDefinitions.hpp"
|
||||||
|
#include "hmc5883L.hpp"
|
||||||
|
|
||||||
|
#if !defined( ARDUINO_ESP32C3_DEV )
|
||||||
|
#error This code is intended to run on the ESP32_C3 platform! Please check your Tools->Board setting.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
HellMetServoManager* hm;
|
||||||
|
WS2812Manager* LedManager;
|
||||||
|
Hmc5883L* magnetometer;
|
||||||
|
SemaphoreHandle_t serial_mutex = NULL;
|
||||||
|
|
||||||
|
void rtosLoop(void *pvParameter){
|
||||||
|
LOG_VERBOSE("rtosloop");
|
||||||
|
|
||||||
|
if (Serial.available()){
|
||||||
|
String str = Serial.readString();
|
||||||
|
LOG_INFO(str);
|
||||||
|
switch(str[0]){
|
||||||
|
case 's': //servo
|
||||||
|
switch(str[1]){
|
||||||
|
case 't': //toggle All
|
||||||
|
if(!hm->in_use)
|
||||||
|
xTaskCreate(HellMetServoManager::ToggleAllWrapper, "Servo Thread", 4096, hm, 6, NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l': //leds
|
||||||
|
break;
|
||||||
|
case 'm' : //magnetometer
|
||||||
|
switch(str[1]){
|
||||||
|
case 'r': //read heading
|
||||||
|
Serial.println(magnetometer->getHeadingValue());
|
||||||
|
break;
|
||||||
|
case 'd': //read debug
|
||||||
|
Serial.println(magnetometer->getDebugValues());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG_INFO("rtosloop - serial present");
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
LOG_VERBOSE("rtosloop - out");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
serial_mutex = xSemaphoreCreateBinary();
|
||||||
|
Serial.begin(9600);
|
||||||
|
I2CManager::Setup(GPIO_NUM_9, GPIO_NUM_8);
|
||||||
|
Serial.println("Are you alive?");
|
||||||
|
while (!Serial.available());
|
||||||
|
I2CManager::scanAll();
|
||||||
|
magnetometer = new Hmc5883L(0x1E,0x1E);
|
||||||
|
LOG_INFO("Creating mag thread");
|
||||||
|
xTaskCreate(Hmc5883L::beginUpdateTaskWrapper, "magnetometer thread", 4096, magnetometer, 7, NULL);
|
||||||
|
LOG_INFO("Done creating mag thread");
|
||||||
|
Serial.println("Are you alive?");
|
||||||
|
LedManager = new WS2812Manager(GPIO_NUM_5,1);
|
||||||
|
xTaskCreate(WS2812Manager::RunRGB, "RGB thread", 4096, LedManager, 6, NULL);
|
||||||
|
delay(100);
|
||||||
|
hm = new HellMetServoManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
rtosLoop(NULL);
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
This directory is intended for PlatformIO Test Runner and project tests.
|
||||||
|
|
||||||
|
Unit Testing is a software testing method by which individual units of
|
||||||
|
source code, sets of one or more MCU program modules together with associated
|
||||||
|
control data, usage procedures, and operating procedures, are tested to
|
||||||
|
determine whether they are fit for use. Unit testing finds problems early
|
||||||
|
in the development cycle.
|
||||||
|
|
||||||
|
More information about PlatformIO Unit Testing:
|
||||||
|
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
|
Loading…
Reference in new issue