mirror of
https://github.com/okalachev/flix.git
synced 2025-07-27 17:49:33 +00:00
Enable Serial input and output in simulator, refactor
This commit is contained in:
parent
3a05403068
commit
aaa8f70166
@ -128,4 +128,5 @@ static float thrustToMotorInput(uint8_t n, float thrust)
|
|||||||
return mapff(thrust, 0, 1, motorThrust[n][i-1], motorThrust[n][i]);
|
return mapff(thrust, 0, 1, motorThrust[n][i-1], motorThrust[n][i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
150
gazebo/Arduino.h
Normal file
150
gazebo/Arduino.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
||||||
|
// Repository: https://github.com/okalachev/flix
|
||||||
|
// Distributed under the MIT License (https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
// Partial implementation of Arduino API for simulation
|
||||||
|
|
||||||
|
// https://github.com/UFABCRocketDesign/Simulator
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
#include <string>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
using std::cout;
|
||||||
|
using std::max;
|
||||||
|
using std::min;
|
||||||
|
using std::isfinite;
|
||||||
|
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||||
|
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||||
|
|
||||||
|
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||||
|
|
||||||
|
long map(long x, long in_min, long in_max, long out_min, long out_max) {
|
||||||
|
const long run = in_max - in_min;
|
||||||
|
const long rise = out_max - out_min;
|
||||||
|
const long delta = x - in_min;
|
||||||
|
return (delta * rise) / run + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
class __FlashStringHelper;
|
||||||
|
|
||||||
|
// Arduino String partial implementation
|
||||||
|
// https://www.arduino.cc/reference/en/language/variables/data-types/stringobject/
|
||||||
|
class String: public std::string {
|
||||||
|
public:
|
||||||
|
long toInt() { return atol(this->c_str()); }
|
||||||
|
float toFloat() { return atof(this->c_str()); }
|
||||||
|
bool isEmpty() { return this->empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Print;
|
||||||
|
|
||||||
|
class Printable {
|
||||||
|
public:
|
||||||
|
virtual size_t printTo(Print& p) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Print {
|
||||||
|
public:
|
||||||
|
size_t printf(const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
size_t result = vprintf(format, args);
|
||||||
|
va_end(args);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t print(float n, int digits = 2)
|
||||||
|
{
|
||||||
|
return printf("%.*f", digits, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println(float n, int digits = 2)
|
||||||
|
{
|
||||||
|
return printf("%.*f\n", digits, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t print(const char* s)
|
||||||
|
{
|
||||||
|
return printf("%s", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println()
|
||||||
|
{
|
||||||
|
return print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println(const char* s)
|
||||||
|
{
|
||||||
|
return printf("%s\n", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println(const Printable& p)
|
||||||
|
{
|
||||||
|
return p.printTo(*this) + print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t print(const String& s)
|
||||||
|
{
|
||||||
|
return printf("%s", s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println(const std::string& s)
|
||||||
|
{
|
||||||
|
return printf("%s\n", s.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t println(const String& s)
|
||||||
|
{
|
||||||
|
return printf("%s\n", s.c_str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class HardwareSerial: public Print {
|
||||||
|
public:
|
||||||
|
void begin(unsigned long baud) {
|
||||||
|
// server is running in background by default, so doesn't have access to stdin
|
||||||
|
// https://github.com/gazebosim/gazebo-classic/blob/d45feeb51f773e63960616880b0544770b8d1ad7/gazebo/gazebo_main.cc#L216
|
||||||
|
// set foreground process group to current process group to allow reading from stdin
|
||||||
|
// https://stackoverflow.com/questions/58918188/why-is-stdin-not-propagated-to-child-process-of-different-process-group
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
tcsetpgrp(STDIN_FILENO, getpgrp());
|
||||||
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
};
|
||||||
|
|
||||||
|
int available() {
|
||||||
|
// to implement for Windows, see https://stackoverflow.com/a/71992965/6850197
|
||||||
|
struct pollfd pfd = { .fd = STDIN_FILENO, .events = POLLIN };
|
||||||
|
return poll(&pfd, 1, 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read() {
|
||||||
|
if (available()) {
|
||||||
|
char c;
|
||||||
|
::read(STDIN_FILENO, &c, 1); // use raw read to avoid C++ buffering
|
||||||
|
// https://stackoverflow.com/questions/45238997/does-getchar-function-has-its-own-buffer-to-store-remaining-input
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HardwareSerial Serial, Serial2;
|
||||||
|
|
||||||
|
void delay(uint32_t ms) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long __micros;
|
||||||
|
|
||||||
|
unsigned long micros() {
|
||||||
|
return __micros;
|
||||||
|
}
|
@ -12,5 +12,7 @@ set(FLIX_SOURCE_DIR ../flix)
|
|||||||
include_directories(${FLIX_SOURCE_DIR})
|
include_directories(${FLIX_SOURCE_DIR})
|
||||||
file(GLOB_RECURSE FLIX_INO_FILES ${FLIX_SOURCE_DIR}/*.ino)
|
file(GLOB_RECURSE FLIX_INO_FILES ${FLIX_SOURCE_DIR}/*.ino)
|
||||||
|
|
||||||
|
set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||||
add_library(flix SHARED flix.cpp)
|
add_library(flix SHARED flix.cpp)
|
||||||
target_link_libraries(flix ${GAZEBO_LIBRARIES} ${SDL2_LIBRARIES})
|
target_link_libraries(flix ${GAZEBO_LIBRARIES} ${SDL2_LIBRARIES})
|
||||||
|
target_include_directories(flix PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
17
gazebo/MPU9250.h
Normal file
17
gazebo/MPU9250.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
||||||
|
// Repository: https://github.com/okalachev/flix
|
||||||
|
// Distributed under the MIT License (https://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
// Mocks of some MPU9250 library functions
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class MPU9250 {
|
||||||
|
public:
|
||||||
|
float getAccelBiasX_mss() { return 0; }
|
||||||
|
float getAccelBiasY_mss() { return 0; }
|
||||||
|
float getAccelBiasZ_mss() { return 0; }
|
||||||
|
float getGyroBiasX_rads() { return 0; }
|
||||||
|
float getGyroBiasY_rads() { return 0; }
|
||||||
|
float getGyroBiasZ_rads() { return 0; }
|
||||||
|
};
|
@ -1,86 +0,0 @@
|
|||||||
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
|
||||||
// Repository: https://github.com/okalachev/flix
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <cmath>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using std::cout;
|
|
||||||
using std::max;
|
|
||||||
using std::min;
|
|
||||||
using std::isfinite;
|
|
||||||
|
|
||||||
// #define PI 3.1415926535897932384626433832795
|
|
||||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
|
||||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
|
||||||
|
|
||||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
|
||||||
|
|
||||||
class Print;
|
|
||||||
|
|
||||||
class Printable {
|
|
||||||
public:
|
|
||||||
virtual size_t printTo(Print& p) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Print {
|
|
||||||
public:
|
|
||||||
size_t print(float n, int digits = 2)
|
|
||||||
{
|
|
||||||
cout << n;
|
|
||||||
return 0; // TODO:
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t println(float n, int digits = 2)
|
|
||||||
{
|
|
||||||
print(n, digits);
|
|
||||||
cout << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t print(const char* s)
|
|
||||||
{
|
|
||||||
cout << s;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t println(const char* s)
|
|
||||||
{
|
|
||||||
print(s);
|
|
||||||
cout << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t println(const Printable& p)
|
|
||||||
{
|
|
||||||
p.printTo(*this);
|
|
||||||
cout << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// int available()
|
|
||||||
// {
|
|
||||||
// std::string s;
|
|
||||||
// s << std::cin;
|
|
||||||
// return s.length();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// char read()
|
|
||||||
// {
|
|
||||||
// char c;
|
|
||||||
// s >> c;
|
|
||||||
// return c;
|
|
||||||
// }
|
|
||||||
};
|
|
||||||
|
|
||||||
class HardwareSerial: public Print {};
|
|
||||||
|
|
||||||
HardwareSerial Serial, Serial2;
|
|
||||||
|
|
||||||
// gazebo::common::Time curTime = this->dataPtr->model->GetWorld()->SimTime();
|
|
||||||
|
|
||||||
// unsigned long micros()
|
|
||||||
// {
|
|
||||||
// // return (unsigned long) (esp_timer_get_time());
|
|
||||||
// TODO:
|
|
||||||
// }
|
|
108
gazebo/flix.cpp
108
gazebo/flix.cpp
@ -34,12 +34,15 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "arduino.hpp"
|
#include "Arduino.h"
|
||||||
#include "flix.hpp"
|
#include "flix.hpp"
|
||||||
#include "turnigy.hpp"
|
|
||||||
#include "util.ino"
|
#include "util.ino"
|
||||||
|
#include "time.ino"
|
||||||
|
#include "turnigy.hpp"
|
||||||
#include "estimate.ino"
|
#include "estimate.ino"
|
||||||
#include "control.ino"
|
#include "control.ino"
|
||||||
|
#include "log.ino"
|
||||||
|
#include "cli.ino"
|
||||||
|
|
||||||
using ignition::math::Vector3d;
|
using ignition::math::Vector3d;
|
||||||
using ignition::math::Pose3d;
|
using ignition::math::Pose3d;
|
||||||
@ -52,13 +55,17 @@ Pose3d flu2frd(const Pose3d& p)
|
|||||||
p.Rot().W(), p.Rot().X(), -p.Rot().Y(), -p.Rot().Z());
|
p.Rot().W(), p.Rot().X(), -p.Rot().Y(), -p.Rot().Z());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector flu2frd(const Vector3d& v)
|
||||||
|
{
|
||||||
|
return Vector(v.X(), -v.Y(), -v.Z());
|
||||||
|
}
|
||||||
|
|
||||||
class ModelFlix : public ModelPlugin
|
class ModelFlix : public ModelPlugin
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
physics::ModelPtr model, estimateModel;
|
physics::ModelPtr model, estimateModel;
|
||||||
physics::LinkPtr body;
|
physics::LinkPtr body;
|
||||||
sensors::ImuSensorPtr imu;
|
sensors::ImuSensorPtr imu;
|
||||||
common::Time _stepTime;
|
|
||||||
event::ConnectionPtr updateConnection, resetConnection;
|
event::ConnectionPtr updateConnection, resetConnection;
|
||||||
transport::NodePtr nodeHandle;
|
transport::NodePtr nodeHandle;
|
||||||
transport::PublisherPtr motorPub[4];
|
transport::PublisherPtr motorPub[4];
|
||||||
@ -78,13 +85,6 @@ public:
|
|||||||
|
|
||||||
this->estimateModel = model->GetWorld()->ModelByName("flix_estimate");
|
this->estimateModel = model->GetWorld()->ModelByName("flix_estimate");
|
||||||
|
|
||||||
// auto scene = rendering::get_scene();
|
|
||||||
// motorVisual[0] = scene->GetVisual("motor0");
|
|
||||||
// motorVisual[1] = scene->GetVisual("motor1");
|
|
||||||
// motorVisual[2] = scene->GetVisual("motor2");
|
|
||||||
// motorVisual[3] = scene->GetVisual("motor3");
|
|
||||||
// motorVisual[0] = model->GetVisual("motor0");
|
|
||||||
|
|
||||||
this->updateConnection = event::Events::ConnectWorldUpdateBegin(
|
this->updateConnection = event::Events::ConnectWorldUpdateBegin(
|
||||||
std::bind(&ModelFlix::OnUpdate, this));
|
std::bind(&ModelFlix::OnUpdate, this));
|
||||||
|
|
||||||
@ -93,6 +93,8 @@ public:
|
|||||||
|
|
||||||
initNode();
|
initNode();
|
||||||
|
|
||||||
|
Serial.begin(0);
|
||||||
|
|
||||||
gzmsg << "Flix plugin loaded" << endl;
|
gzmsg << "Flix plugin loaded" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,92 +107,28 @@ public:
|
|||||||
|
|
||||||
void OnUpdate()
|
void OnUpdate()
|
||||||
{
|
{
|
||||||
// this->model->SetLinearVel(ignition::math::Vector3d(.3, 0, 0));
|
__micros = model->GetWorld()->SimTime().Double() * 1000000;
|
||||||
|
step();
|
||||||
|
|
||||||
// this->model->GetLink("body")->AddForce(ignition::math::Vector3d(0.0, 0.0, 1.96));
|
// read imu
|
||||||
// this->model->GetLink("body")->SetTorque(1.0, ignition::math::Vector3d(1.0, 0.0, 0.0);
|
rates = flu2frd(imu->AngularVelocity());
|
||||||
|
acc = flu2frd(imu->LinearAcceleration());
|
||||||
|
|
||||||
// this->model->GetLink("motor0")->AddForce(ignition::math::Vector3d(0.0, 0.0, 1.96/4));
|
// read rc
|
||||||
// this->model->GetLink("motor1")->AddForce(ignition::math::Vector3d(0.0, 0.0, 1.96/4));
|
joystickGet();
|
||||||
// this->model->GetLink("motor2")->AddForce(ignition::math::Vector3d(0.0, 0.0, 1.96/4));
|
|
||||||
// this->model->GetLink("motor3")->AddForce(ignition::math::Vector3d(0.0, 0.0, 1.96/4))
|
|
||||||
|
|
||||||
// === GROUNDTRUTH ORIENTATION ===
|
|
||||||
// auto pose = flu2frd(this->model->WorldPose());
|
|
||||||
// attitude = Quaternion(pose.Rot().W(), pose.Rot().X(), pose.Rot().Y(), pose.Rot().Z());
|
|
||||||
// auto vel = this->model->RelativeAngularVel();
|
|
||||||
// rates = Vector(vel.X(), -vel.Y(), -vel.Z()); // flu to frd
|
|
||||||
|
|
||||||
// === GROUNDTRUTH POSITION ===
|
|
||||||
// auto pose = flu2frd(this->model->WorldPose());
|
|
||||||
// position = Vector(pose.Pos().X(), pose.Pos().Y(), pose.Pos().Z());
|
|
||||||
// auto vel = this->model->RelativeLinearVel();
|
|
||||||
// velocity = Vector(vel.X(), -vel.Y(), -vel.Z());
|
|
||||||
|
|
||||||
/// == IMU ===
|
|
||||||
auto imuRates = imu->AngularVelocity();
|
|
||||||
rates = Vector(imuRates.X(), -imuRates.Y(), -imuRates.Z()); // flu to frd
|
|
||||||
auto imuAccel = imu->LinearAcceleration();
|
|
||||||
acc = Vector(imuAccel.X(), -imuAccel.Y(), -imuAccel.Z()); // flu to frd
|
|
||||||
|
|
||||||
// gazebo::common::Time curTime = this->dataPtr->model->GetWorld()->SimTime();
|
|
||||||
|
|
||||||
turnigyGet();
|
|
||||||
controls[RC_CHANNEL_MODE] = 1; // 0 acro, 1 stab
|
controls[RC_CHANNEL_MODE] = 1; // 0 acro, 1 stab
|
||||||
controls[RC_CHANNEL_AUX] = 1; // armed
|
controls[RC_CHANNEL_AUX] = 1; // armed
|
||||||
// std::cout << "yaw: " << yaw << " pitch: " << pitch << " roll: " << roll << " throttle: " << throttle << std::endl;
|
|
||||||
|
|
||||||
if (std::isnan(dt)) {
|
|
||||||
// first step
|
|
||||||
dt = 0;
|
|
||||||
} else {
|
|
||||||
dt = (this->model->GetWorld()->SimTime() - _stepTime).Double();
|
|
||||||
}
|
|
||||||
_stepTime = this->model->GetWorld()->SimTime();
|
|
||||||
stepTime = _stepTime.Double() * 1000000;
|
|
||||||
// std::cout << "dt: " << dt << std::endl;
|
|
||||||
|
|
||||||
estimate();
|
estimate();
|
||||||
|
|
||||||
// fix yaw
|
// correct yaw to the actual yaw
|
||||||
attitude.setYaw(-this->model->WorldPose().Yaw());
|
attitude.setYaw(-this->model->WorldPose().Yaw());
|
||||||
// Serial.print("attitude: "); Serial.println(attitude);
|
|
||||||
// controlMission();
|
|
||||||
// controlPosition();
|
|
||||||
|
|
||||||
// auto pose = flu2frd(this->model->WorldPose());
|
|
||||||
|
|
||||||
control();
|
control();
|
||||||
|
parseInput();
|
||||||
|
|
||||||
applyMotorsThrust();
|
applyMotorsThrust();
|
||||||
updateEstimatePose();
|
updateEstimatePose();
|
||||||
// autotune();
|
|
||||||
|
|
||||||
/*
|
|
||||||
working:
|
|
||||||
const double max_thrust = 2.2;
|
|
||||||
double thrust = max_thrust * throttle;
|
|
||||||
|
|
||||||
// rate setpoint
|
|
||||||
double rx = roll * 0.1;
|
|
||||||
double ry = -pitch * 0.1;
|
|
||||||
double rz = yaw * 0.1;
|
|
||||||
|
|
||||||
// this->model->GetLink("body")->AddForce(ignition::math::Vector3d(0.0, 0.0, 2.5 * throttle));
|
|
||||||
|
|
||||||
const double d = 0.035355;
|
|
||||||
double front_left = thrust + ry + rx;
|
|
||||||
double front_right = thrust + ry - rx;
|
|
||||||
double rear_left = thrust - ry + rx;
|
|
||||||
double rear_right = thrust - ry - rx;
|
|
||||||
|
|
||||||
if (throttle < 0.1) return;
|
|
||||||
|
|
||||||
this->body->AddLinkForce(ignition::math::Vector3d(0.0, 0.0, front_left), ignition::math::Vector3d(d, d, 0.0));
|
|
||||||
this->body->AddLinkForce(ignition::math::Vector3d(0.0, 0.0, front_right), ignition::math::Vector3d(d, -d, 0.0));
|
|
||||||
this->body->AddLinkForce(ignition::math::Vector3d(0.0, 0.0, rear_left), ignition::math::Vector3d(-d, d, 0.0));
|
|
||||||
this->body->AddLinkForce(ignition::math::Vector3d(0.0, 0.0, rear_right), ignition::math::Vector3d(-d, -d, 0.0));
|
|
||||||
*/
|
|
||||||
|
|
||||||
publishTopics();
|
publishTopics();
|
||||||
logData();
|
logData();
|
||||||
}
|
}
|
||||||
@ -221,8 +159,6 @@ public:
|
|||||||
if (motors[MOTOR_REAR_LEFT] < 0.001) mrl = 0;
|
if (motors[MOTOR_REAR_LEFT] < 0.001) mrl = 0;
|
||||||
if (motors[MOTOR_REAR_RIGHT] < 0.001) mrr = 0;
|
if (motors[MOTOR_REAR_RIGHT] < 0.001) mrr = 0;
|
||||||
|
|
||||||
// const float scale0 = 1.0, scale1 = 1.0, scale2 = 1.0, scale3 = 1.0;
|
|
||||||
|
|
||||||
// TODO: min_thrust
|
// TODO: min_thrust
|
||||||
|
|
||||||
body->AddLinkForce(Vector3d(0.0, 0.0, scale0 * maxThrust * abs(mfl)), Vector3d(d, d, 0.0));
|
body->AddLinkForce(Vector3d(0.0, 0.0, scale0 * maxThrust * abs(mfl)), Vector3d(d, d, 0.0));
|
||||||
|
@ -1,41 +1,31 @@
|
|||||||
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
// Copyright (c) 2023 Oleg Kalachev <okalachev@gmail.com>
|
||||||
// Repository: https://github.com/okalachev/flix
|
// Repository: https://github.com/okalachev/flix
|
||||||
|
|
||||||
|
// Declarations of some functions and variables in Arduino code
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "vector.hpp"
|
#include "vector.hpp"
|
||||||
#include "quaternion.hpp"
|
#include "quaternion.hpp"
|
||||||
|
|
||||||
#define ONE_G 9.807f
|
|
||||||
|
|
||||||
#define RC_CHANNELS 6
|
#define RC_CHANNELS 6
|
||||||
// #define RC_CHANNEL_THROTTLE 2
|
|
||||||
// #define RC_CHANNEL_YAW 3
|
|
||||||
// #define RC_CHANNEL_PITCH 1
|
|
||||||
// #define RC_CHANNEL_ROLL 0
|
|
||||||
// #define RC_CHANNEL_AUX 4
|
|
||||||
// #define RC_CHANNEL_MODE 5
|
|
||||||
|
|
||||||
#define MOTOR_REAR_LEFT 0
|
#define MOTOR_REAR_LEFT 0
|
||||||
#define MOTOR_FRONT_LEFT 3
|
#define MOTOR_FRONT_LEFT 3
|
||||||
#define MOTOR_FRONT_RIGHT 2
|
#define MOTOR_FRONT_RIGHT 2
|
||||||
#define MOTOR_REAR_RIGHT 1
|
#define MOTOR_REAR_RIGHT 1
|
||||||
|
|
||||||
|
uint32_t startTime;
|
||||||
|
uint32_t stepTime;
|
||||||
|
uint32_t steps;
|
||||||
|
float stepsPerSecond;
|
||||||
|
float dt;
|
||||||
|
float motors[4];
|
||||||
|
int16_t channels[16]; // raw rc channels WARNING: unsigned on hardware
|
||||||
|
float controls[RC_CHANNELS];
|
||||||
Vector acc;
|
Vector acc;
|
||||||
Vector rates;
|
Vector rates;
|
||||||
Quaternion attitude;
|
Quaternion attitude;
|
||||||
float dt = NAN;
|
bool calibrating;
|
||||||
float motors[4]; // normalized motors thrust in range [-1..1]
|
|
||||||
int16_t channels[16]; // raw rc channels WARNING: unsigned in real life
|
|
||||||
float controls[RC_CHANNELS]; // normalized controls in range [-1..1] ([0..1] for thrust)
|
|
||||||
uint32_t stepTime;
|
|
||||||
|
|
||||||
// util
|
|
||||||
float mapf(long x, long in_min, long in_max, float out_min, float out_max);
|
|
||||||
float mapff(float x, float in_min, float in_max, float out_min, float out_max);
|
|
||||||
// float hypot3(float x, float y, float z);
|
|
||||||
|
|
||||||
// rc
|
|
||||||
void normalizeRC();
|
|
||||||
|
|
||||||
// control
|
// control
|
||||||
void control();
|
void control();
|
||||||
@ -47,5 +37,12 @@ static void controlRate();
|
|||||||
void desaturate(float& a, float& b, float& c, float& d);
|
void desaturate(float& a, float& b, float& c, float& d);
|
||||||
static void indicateSaturation();
|
static void indicateSaturation();
|
||||||
|
|
||||||
|
// cli
|
||||||
|
static void showTable();
|
||||||
|
static void cliTestMotor(uint8_t n);
|
||||||
|
|
||||||
// mocks
|
// mocks
|
||||||
void setLED(bool on) {}
|
void setLED(bool on) {};
|
||||||
|
void calibrateGyro() {};
|
||||||
|
void fullMotorTest(int n) {};
|
||||||
|
void sendMotors() {};
|
||||||
|
@ -12,23 +12,25 @@ static const int16_t channelNeutralMax[] = {-1032, -258, -27348, 3353, 0, 0};
|
|||||||
|
|
||||||
static const int16_t channelMax[] = {27090, 27090, 27090, 27090, 0, 0};
|
static const int16_t channelMax[] = {27090, 27090, 27090, 27090, 0, 0};
|
||||||
|
|
||||||
|
#define RC_CHANNEL_ROLL 0
|
||||||
|
#define RC_CHANNEL_PITCH 1
|
||||||
#define RC_CHANNEL_THROTTLE 2
|
#define RC_CHANNEL_THROTTLE 2
|
||||||
#define RC_CHANNEL_YAW 3
|
#define RC_CHANNEL_YAW 3
|
||||||
#define RC_CHANNEL_PITCH 1
|
|
||||||
#define RC_CHANNEL_ROLL 0
|
|
||||||
#define RC_CHANNEL_AUX 4
|
#define RC_CHANNEL_AUX 4
|
||||||
#define RC_CHANNEL_MODE 5
|
#define RC_CHANNEL_MODE 5
|
||||||
|
|
||||||
static SDL_Joystick *joystick;
|
static SDL_Joystick *joystick;
|
||||||
|
|
||||||
bool turnigyInitialized = false, warnShown = false;
|
bool joystickInitialized = false, warnShown = false;
|
||||||
|
|
||||||
void turnigyInit()
|
void normalizeRC();
|
||||||
|
|
||||||
|
void joystickInit()
|
||||||
{
|
{
|
||||||
SDL_Init(SDL_INIT_JOYSTICK);
|
SDL_Init(SDL_INIT_JOYSTICK);
|
||||||
joystick = SDL_JoystickOpen(0);
|
joystick = SDL_JoystickOpen(0);
|
||||||
if (joystick != NULL) {
|
if (joystick != NULL) {
|
||||||
turnigyInitialized = true;
|
joystickInitialized = true;
|
||||||
gzmsg << "Joystick initialized: " << SDL_JoystickNameForIndex(0) << endl;
|
gzmsg << "Joystick initialized: " << SDL_JoystickNameForIndex(0) << endl;
|
||||||
} else if (!warnShown) {
|
} else if (!warnShown) {
|
||||||
gzwarn << "Joystick not found, begin waiting for joystick..." << endl;
|
gzwarn << "Joystick not found, begin waiting for joystick..." << endl;
|
||||||
@ -36,10 +38,10 @@ void turnigyInit()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void turnigyGet()
|
void joystickGet()
|
||||||
{
|
{
|
||||||
if (!turnigyInitialized) {
|
if (!joystickInitialized) {
|
||||||
turnigyInit();
|
joystickInit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,20 +50,16 @@ void turnigyGet()
|
|||||||
for (uint8_t i = 0; i < 4; i++) {
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
channels[i] = SDL_JoystickGetAxis(joystick, i);
|
channels[i] = SDL_JoystickGetAxis(joystick, i);
|
||||||
}
|
}
|
||||||
|
channels[RC_CHANNEL_MODE] = SDL_JoystickGetButton(joystick, 0) ? 1 : 0;
|
||||||
|
controls[RC_CHANNEL_MODE] = channels[RC_CHANNEL_MODE];
|
||||||
|
|
||||||
normalizeRC();
|
normalizeRC();
|
||||||
}
|
}
|
||||||
|
|
||||||
void normalizeRC() {
|
void normalizeRC() {
|
||||||
for (uint8_t i = 0; i < RC_CHANNELS; i++) {
|
for (uint8_t i = 0; i < 4; i++) {
|
||||||
if (channels[i] >= channelNeutralMin[i] && channels[i] <= channelNeutralMax[i]) {
|
if (channels[i] >= channelNeutralMin[i] && channels[i] <= channelNeutralMax[i]) {
|
||||||
controls[i] = 0; // make neutral position strictly equal to 0
|
controls[i] = 0;
|
||||||
// } else if (channels[i] > channelNeutralMax[i]) {
|
|
||||||
// controls[i] = mapf(channels[i], channelNeutralMax[i], channelMax[i], 0, 1);
|
|
||||||
// } else {
|
|
||||||
// float channelMin = channelNeutralMin[i] - (channelMax[i] - channelNeutralMax[i]);
|
|
||||||
// controls[i] = mapf(channels[i], channelNeutralMin[i], channelMin, -1, 0);
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
controls[i] = mapf(channels[i], (channelNeutralMin[i] + channelNeutralMax[i]) / 2, channelMax[i], 0, 1);
|
controls[i] = mapf(channels[i], (channelNeutralMin[i] + channelNeutralMax[i]) / 2, channelMax[i], 0, 1);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user