Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete rewrite #13

Merged
merged 23 commits into from
Feb 27, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Code cleanup
  • Loading branch information
ashtuchkin committed Feb 21, 2017
commit f3a44beaab93969c82df93b3e136a08dc95c6322
3 changes: 3 additions & 0 deletions notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

Later:
* [ ] Create multi-sensor geometry processing unit
* [ ] Increase precision by applying geometry adjustments for base stations. 1:1 with Unity.
* [ ] Create Unity tutorial.
* [ ] Increase precision by keeping an estimate of cycle and removing uncertainty of long pulses.
* [ ] Re-check all last-success timestamps (LongTimestamp) - they don't survive the overflow.
* [ ] Remove Timestamp in favor of std::chrono::duration (http:https://en.cppreference.com/w/cpp/chrono/duration)
Expand All @@ -14,6 +16,7 @@ Later:
* [ ] Add unit testing
* [ ] Add polling mode for outputs
* [ ] DataFrame: Check CRC32.
* [ ] Avoid using double (-Wdouble-promotion). This will require killing all printf-s.
* [ ] Split PersistentSettings to Settings and Persistent<>
* [ ] Get rid of Teensy's Print. Use vsnprintf instead. debug_print, print_def, parse_def, DataChunkPrint
* [ ] (Maybe) Introduce EASTL library and all its niceties like fixed_vector. Tried it and it looks problematic (platform not supported + threading issues).
Expand Down
2 changes: 1 addition & 1 deletion src/cycle_phase_classifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ inline float CyclePhaseClassifier::expected_pulse_len(bool skip, bool data, bool
return pulse_base_len_ + (skip << 2 | data << 1 | axis) * 10.416f;
}

DataFrameBitPair CyclePhaseClassifier::get_data_bits(uint32_t cycle_idx, const TimeDelta (&pulse_lens)[num_base_stations]) {
CyclePhaseClassifier::DataFrameBitPair CyclePhaseClassifier::get_data_bits(uint32_t cycle_idx, const TimeDelta (&pulse_lens)[num_base_stations]) {
// This is almost naive algorithm that tracks/adjusts just one variable, pulse_base_len_, with the assumption that
// all pulses can be shorter/longer than ideal by the same amount.
// We might need to introduce tracking of each phase mid_len if sensors are not linear enough.
Expand Down
9 changes: 4 additions & 5 deletions src/cycle_phase_classifier.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
#pragma once
#include "common.h"
#include "messages.h"
#include "primitives/string_utils.h"
class Print;

// Reference to a pair of DataFrameBit-s
typedef DataFrameBit (&DataFrameBitPair)[num_base_stations];

// Given pairs of pulse lens from 2 base stations, this class determines the phase for current cycle
// Phases are:
Expand All @@ -24,6 +20,9 @@ class CyclePhaseClassifier {
// Get current cycle phase. -1 if phase is not known (no fix achieved).
int get_phase(uint32_t cycle_idx);

// Reference to a pair of DataFrameBit-s
typedef DataFrameBit (&DataFrameBitPair)[num_base_stations];

// Get updated data bits from the pulse lens for current cycle.
// Both bits are always returned, but caller needs to make sure they were updated this cycle by
// checking DataFrameBit.cycle_idx == cycle_idx.
Expand Down
2 changes: 1 addition & 1 deletion src/data_frame_decoder.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "common.h"
#include "messages.h"

// See data frame description here:
// https://github.com/nairol/LighthouseRedox/blob/master/docs/Light%20Emissions.md#ootx-frame
Expand Down
2 changes: 1 addition & 1 deletion src/debug_node.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include "primitives/workers.h"
#include "outputs.h"
#include "primitives/producer_consumer.h"
#include "print_helpers.h"

// This node calls debug_cmd and debug_print for all pipeline nodes periodically,
Expand Down
4 changes: 2 additions & 2 deletions src/formatters.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "common.h"
#include "messages.h"
#include "geometry.h"

enum class FormatterType {
Expand Down Expand Up @@ -44,7 +44,7 @@ class FormatterNode
FormatterDef def_;
};

// Format sensor angles in a text form.
// Format sensor angles to a text form.
class SensorAnglesTextFormatter
: public FormatterNode
, public Consumer<SensorAnglesFrame> {
Expand Down
10 changes: 5 additions & 5 deletions src/geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,17 +175,17 @@ CoordinateSystemConverter::CoordinateSystemConverter(float mat[9]) {
std::unique_ptr<CoordinateSystemConverter> CoordinateSystemConverter::create(CoordSysType type, const CoordSysDef& def) {
switch (type) {
case CoordSysType::kDefault: return nullptr; // Do nothing.
case CoordSysType::kNED: return CoordinateSystemConverter::NED(def.ned);
case CoordSysType::kNED: return CoordinateSystemConverter::NED(def);
default: throw_printf("Unknown coord sys type: %d", type);
}
}

std::unique_ptr<CoordinateSystemConverter> CoordinateSystemConverter::NED(const NEDCoordDef &def) {
float ne_angle = def.north_angle / 360.0f * (float)M_PI;
std::unique_ptr<CoordinateSystemConverter> CoordinateSystemConverter::NED(const CoordSysDef &def) {
float ne_angle = def.ned.north_angle / 360.0f * (float)M_PI;
float mat[9] = {
// Convert Y up -> Z down; then rotate XY around Z clockwise and inverse X & Y
-cosf(ne_angle), 0.0f, sinf(ne_angle),
-sinf(ne_angle), 0.0f, -cosf(ne_angle),
-arm_cos_f32(ne_angle), 0.0f, arm_sin_f32(ne_angle),
-arm_sin_f32(ne_angle), 0.0f, -arm_cos_f32(ne_angle),
0.0f, -1.0f, 0.0f,
};
return std::make_unique<CoordinateSystemConverter>(mat);
Expand Down
22 changes: 9 additions & 13 deletions src/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "primitives/vector.h"
#include "common.h"
#include "messages.h"

// Naive 3d vector type.
constexpr int vec3d_size = 3;
typedef float vec3d[vec3d_size];

class Print;
class HashedWord;

// Stored definition of Base Stations
struct BaseStationGeometryDef {
float mat[9]; // Normalized rotation matrix.
vec3d origin; // Origin point
float mat[9]; // Normalized rotation matrix.
vec3d origin; // Origin point

void print_def(uint32_t idx, Print &stream);
bool parse_def(uint32_t idx, HashedWord *input_words, Print &err_stream);
Expand Down Expand Up @@ -63,18 +61,16 @@ class PointGeometryBuilder : public GeometryBuilder {
};


// Stored type and definition for CoordinateSystemConverter.
enum class CoordSysType {
kDefault, // No conversion.
kNED, // North-East-Down.
};

struct NEDCoordDef {
// Angle between North and X axis, in radians.
float north_angle;
};

union CoordSysDef {
NEDCoordDef ned;
struct {
float north_angle; // Angle between North and X axis, in degrees.
} ned;
};

// Helper node to convert coordinates to a different coordinate system.
Expand All @@ -89,7 +85,7 @@ class CoordinateSystemConverter

// Convert from standard Vive coordinate system to NED.
// Needs angle between North and X axis, in degrees.
static std::unique_ptr<CoordinateSystemConverter> NED(const NEDCoordDef &def);
static std::unique_ptr<CoordinateSystemConverter> NED(const CoordSysDef &def);

virtual void consume(const ObjectPosition& geo);
virtual bool debug_cmd(HashedWord *input_words);
Expand Down
15 changes: 6 additions & 9 deletions src/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "primitives/circular_buffer.h"
#include "common.h"
#include "messages.h"

// We can used different Teensy modules to measure pulse timing, each with different pros and cons.
// We can use different Teensy hardware features to measure pulse timing, each with different pros and cons.
// Look into each input type's header for details.
enum class InputType {
kCMP = 0, // Comparator
Expand All @@ -13,9 +13,7 @@ enum class InputType {
};
constexpr int kInputTypeCount = 3;

class Print;
class HashedWord;

// Stored definition of an InputNode.
struct InputDef {
uint32_t pin; // Teensy PIN number
bool pulse_polarity; // true = Positive, false = Negative.
Expand All @@ -27,9 +25,7 @@ struct InputDef {
};


constexpr int pulses_buffer_len = 32;
typedef CircularBuffer<Pulse, pulses_buffer_len> PulseCircularBuffer;

// Base class for input nodes. They all produce Pulse-s.
class InputNode
: public WorkerNode
, public Producer<Pulse> {
Expand All @@ -50,6 +46,7 @@ class InputNode
uint32_t input_idx_;

// We keep the pulse buffer to move Pulse-s from irq context to main thread context.
PulseCircularBuffer pulses_buf_;
static constexpr int pulses_buffer_len = 32;
CircularBuffer<Pulse, pulses_buffer_len> pulses_buf_;
};

1 change: 0 additions & 1 deletion src/input_cmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
//
#include "input_cmp.h"
#include "settings.h"
#include "common.h"
#include <Arduino.h>

constexpr int num_comparators = 3; // Number of Comparator modules in Teensy.
Expand Down
1 change: 1 addition & 0 deletions src/input_cmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
struct ComparatorPorts;
struct ComparatorInputPin;

// Input node using Teensy's comparator modules. See description in .cpp file.
class InputCmpNode : public InputNode {
public:
InputCmpNode(uint32_t input_idx, const InputDef &def);
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern "C" int main() {
settings.initialize_from_user_input(Serial);
}

// Create worker node pipeline from settings.
// Create worker nodes pipeline from settings.
auto pipeline = create_vive_sensor_pipeline(settings);

// Register & start input nodes' interrupts.
Expand Down
21 changes: 13 additions & 8 deletions src/common.h → src/messages.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// This file contains constants, enums and structures that are used in different components.
// This file contains definitions of messages that are passed between pipeline nodes.
#pragma once
#include "primitives/timestamp.h"
#include "primitives/vector.h"
#include <stdint.h>

// Tunable
constexpr int max_num_inputs = 8; // Number of concurrent sensors we support.
// Tunable constants
constexpr int max_num_inputs = 8; // Number of concurrent sensors supported.
constexpr int max_bytes_in_data_frame = 64; // Current DataFrame length is 33. This param should be larger.
constexpr int max_bytes_in_data_chunk = 64;

// Not tunable: constant for Lighthouse system.
constexpr int num_base_stations = 2;
constexpr int num_cycle_phases = 4;

// Pulses are generated by Inputs and processed by PulseProcessor
// Pulses are generated by InputNodes and processed by PulseProcessor
struct Pulse {
uint32_t input_idx;
Timestamp start_time;
Expand All @@ -34,28 +34,32 @@ struct SensorAngles {
uint32_t updated_cycles[num_cycle_phases]; // Cycle id when this angle was last updated.
};

// SensorAnglesFrame is produced by PulseProcessor every 4 cycles and consumed by GeometryBuilders. It contains
// a snapshot of angles visible by sensors.
struct SensorAnglesFrame {
Timestamp time;
FixLevel fix_level;
uint32_t cycle_idx;
int32_t phase_id;
FixLevel fix_level; // Up to kCycleSynced
uint32_t cycle_idx; // Increasing number of cycles since last fix.
int32_t phase_id; // 0..3
Vector<SensorAngles, max_num_inputs> sensors;
};

// One data bit extracted from a long pulse from one base station. Produced by PulseProcessor and consumed by DataFrameDecoder.
struct DataFrameBit {
Timestamp time;
uint32_t base_station_idx;
uint32_t cycle_idx;
bool bit;
};

// Decoded data frame. Produced by DataFrameDecoder. 'bytes' array can be casted to DecodedDataFrame to get meaningful values.
struct DataFrame {
Timestamp time;
uint32_t base_station_idx;
Vector<uint8_t, max_bytes_in_data_frame> bytes;
};

// Position of an object.
// Position of an object. Calculated by GeometryBuilders and consumed by FormatterNodes.
struct ObjectPosition {
Timestamp time;
uint32_t object_idx; // Index of the object.
Expand All @@ -79,6 +83,7 @@ enum class OutputCommandType {
kMakeNonExclusive, // Remove exclusivity.
};

// OutputCommand is used to control OutputNodes, see OutputCommandType enum for types of commands.
struct OutputCommand {
OutputCommandType type;
uint32_t stream_idx;
Expand Down
6 changes: 4 additions & 2 deletions src/outputs.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// This file defines OutputNode-s. These are dumb IO Nodes reading and writing DataChunk-s to/from different
// hardware streams.
#pragma once
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "common.h"
#include "messages.h"

// usb serial + 3x hardware serials.
// Currently supported: usb serial + 3x hardware serials.
constexpr int num_outputs = 4;

struct OutputDef {
Expand Down
2 changes: 1 addition & 1 deletion src/platform.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

// Platform-specific constants
// Platform-specific functions and constants.

// Max stack size.
// NOTE: Stack overflow is not checked for now. We do check heap from growing into stack, though.
Expand Down
2 changes: 1 addition & 1 deletion src/primitives/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

// MurmurHash3 32 bit, derived from https://github.com/aappleby/smhasher
// Both compile-time and runtime versions provided.
// User literal version is also defined to allow "abc"_hash to return hash of "abc".
// User literal version is also defined to allow "abc"_hash to be compiled to a hash of "abc".
// One useful property of this hash is that hash("") == 0.

constexpr uint32_t rotl32(uint32_t x, int8_t r) {
Expand Down
1 change: 1 addition & 0 deletions src/primitives/string_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../primitives/hash.h"

class Stream;
class Print;
template<typename T, unsigned C> class Vector;

// Input string length constants.
Expand Down
2 changes: 0 additions & 2 deletions src/primitives/workers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#include <list>
#include <memory>

class Print;

// Simple worker node pattern.
// To create a worker node, inherit from this interface and override functions needed.
class WorkerNode {
Expand Down
5 changes: 2 additions & 3 deletions src/print_helpers.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#pragma once
#include "common.h"
#include "primitives/producer_consumer.h"
#include "primitives/timestamp.h"
#include <algorithm>
#include "messages.h"
#include <Print.h>

// Implement Print interface which sends DataChunks as a Producer.
// Implements Print interface which sends DataChunks as a Producer.
// Note, the data is buffered and the last chunk is sent either on flush(), newline (if not binary),
// or in destructor.
class DataChunkPrint : public Print {
Expand Down
2 changes: 1 addition & 1 deletion src/pulse_processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ void PulseProcessor::process_cycle_fix(Timestamp cur_time) {

// If needed, get the data bits from pulse lengths and send them down the pipeline
if (Producer<DataFrameBit>::has_consumers()) {
DataFrameBitPair bits = phase_classifier_.get_data_bits(cycle_idx_, pulse_lens);
CyclePhaseClassifier::DataFrameBitPair bits = phase_classifier_.get_data_bits(cycle_idx_, pulse_lens);
for (int b = 0; b < num_base_stations; b++)
if (bits[b].cycle_idx == cycle_idx_) {
bits[b].time = cycle_start_time_;
Expand Down
6 changes: 3 additions & 3 deletions src/pulse_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
#include "primitives/workers.h"
#include "primitives/producer_consumer.h"
#include "primitives/vector.h"
#include "common.h"
#include "messages.h"
#include "cycle_phase_classifier.h"

// This node processes pulses from several sensors, tries to match them to cycle structure and
// output matched set of angles.
// This node processes Pulses from several sensors, tries to match them to cycle structure and
// output matched set of angles (SensorAnglesFrame) and data bits (DataFrameBit).
class PulseProcessor
: public WorkerNode
, public Consumer<Pulse>
Expand Down
4 changes: 3 additions & 1 deletion src/settings.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#pragma once
#include "common.h"
#include "messages.h"
#include "input.h"
#include "geometry.h"
#include "formatters.h"
#include "outputs.h"
#include <type_traits>

// This class provides configurability to our project. It reads/writes configuration data to EEPROM and provides
// configuration command interface.
class PersistentSettings {
public:
// Data accessors
Expand Down
Loading