Sin()

Goeiedag,

ik introduceer me zelf effe, ik ben emile ballard en ben 30 jaar en 6 jaar terug ben ik in de wondere wereld van arduino gestapt (robots maken is een kinder droom van me) dus vind het erg leuk om tedoen.

ik ben met een project begonnen om simpel (dacht ik) een soort van Sequence machine temaken, dus waarde omhoog en omlaag met timing. ik heb het “OutputValue” genoemt.

uiteindelijk is dit me ook gelukt. zie code “OutputValue.h” wat perfect werkt alleen ziet de waveform er uit als een “sawtooth” wat ook de bedoeling is, maar nu had ik dus het idee om er een “sinewave” van temaken. maar dat wilt nog niet helemaal lukken.

als ik van waarde 0 naar 255 ga dan klopt de reken som die ik in me hoofd heb. het zelfde met 0 naar 127.
maar met alle waarder er tussen klopt me reken som niet. en ik heb van alles geprobeert maar ik snap het niet :’(

dus ik hoopte dat jullie mij meschien een duwtje in de goeie (overduidelijke) richting konden geven.

sketch:

#define NUM_PLAYBACK 1
#define NUMBER_OF_OUTPUTS 3

#include "OutputValue.h"
OutputValue OV;

//amount of channel, amount of steps,
//scene time , fade time , Channel 0, value, channel 1, value, Enz....
/*uint16_t chase[] = {3, 3,
                    2000, 2000, 0, 255, 1, 235,   2, 235,
                    2000, 2000, 0, 235,   1, 255, 2, 235,
                    2000, 2000, 0, 235,  1, 235,   2, 255
                   };*/

uint16_t chase[] = {3, 3,
                    2000, 2000, 0, 20, 1, 0,   2, 0,
                    2000, 2000, 0, 0,   1, 20, 2, 0,
                    2000, 2000, 0, 0,  1, 0,   2, 20
                   };

void setup() {
  Serial.begin(250000);
  Serial1.begin(9600);
}

void loop() {
  OV.Playback(0, chase);
  OV.Refresh(micros());

  /* float test = 6.283 / 255.00;
    //test = 4.712 - (test * 192);
    test = test * 235;


    Serial.println(test);


    Serial1.print(sin((OV.Output(0) / 6.366) + 5.57) * 10 + 245);
    Serial1.print(" ");
    Serial1.print(sin((OV.Output(1) / 6.366) + 5.57) * 10 + 245);
    Serial1.print(" ");
    Serial1.println(sin((OV.Output(2) / 6.366) + 5.57) * 10 + 245);*/

  Serial1.print(sin((OV.Output(0) / 6.366) + 4.79) * 10 + 10);
  Serial1.print(" ");
  Serial1.print(sin((OV.Output(1) / 6.366) + 4.79) * 10 + 10);
  Serial1.print(" ");
  Serial1.println(sin((OV.Output(2) / 6.366) + 4.79) * 10 + 10);
  Serial1.print(" ");



  analogWrite(13, OV.Output(0));
}

OutputValue.h :

#include"Arduino.h"



class OutputValue {
  public:
    OutputValue();
    void GoTo(uint8_t Channel, uint16_t FadeTime, uint16_t Value);
    void Playback(uint8_t PlaybackNum, uint16_t *Seq);
    void Refresh(uint32_t time);
    uint16_t Output(uint16_t Channel);

  private:

    uint8_t _OV_NewValue[NUMBER_OF_OUTPUTS];
    uint8_t _OV_PrevValue[NUMBER_OF_OUTPUTS];
    double _OV_Arv[NUMBER_OF_OUTPUTS];
    int16_t _OV_Output[NUMBER_OF_OUTPUTS];
    uint16_t _OV_Speed[NUMBER_OF_OUTPUTS];

    uint8_t _OV_Step[NUM_PLAYBACK];
    uint32_t _OV_PrevMicros[NUMBER_OF_OUTPUTS];
    uint32_t _OV_PrevSeqMicros[NUM_PLAYBACK];


    uint32_t _OV_Micros;
};

OutputValue::OutputValue() {}

void OutputValue::GoTo(uint8_t Channel, uint16_t FadeTime, uint16_t Value) {
  if (Value != _OV_NewValue[Channel]) {
    _OV_PrevMicros[Channel] = _OV_Micros; // Set Micros
    _OV_PrevValue[Channel] = _OV_NewValue[Channel]; // Put newvalue into old value
    _OV_NewValue[Channel] = Value; // Get new value
    if (FadeTime != 0) { // IF fadetime != 0 run next code
      _OV_Arv[Channel] = FadeTime * 1000 / abs(_OV_NewValue[Channel] - _OV_PrevValue[Channel]);
      //Arv = fadetime * 1000 / abs (Newvalue - old value)
      //SO:
      //Newvalue = 0, Old value = 255, fadetime = 1000 or 1 sec
      //0 - 255 = -255 Abs makes it Positive so 255
      //1000 * 1000 / 255 = 3921 Because i use millis 1000000 = 1 Sec now i can use 2 byte value instead of 4 bytes.
      // 3921 will be needed for the Refresh() function.
    } else {
      _OV_Arv[Channel] = 0;
    }
  }
}

void OutputValue::Playback(uint8_t PlaybackNum, uint16_t *Seq) {
  if (_OV_Micros - _OV_PrevSeqMicros[PlaybackNum] >= (uint32_t)_OV_Speed[PlaybackNum] * 1000 /*Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 2]*/) {
    _OV_PrevSeqMicros[PlaybackNum] = _OV_Micros;

    uint16_t fade;
    _OV_Speed[PlaybackNum] = Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 2];
    fade = Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 3];

      /*Serial.print("Step : ");
      Serial.println(_OV_Step[PlaybackNum]);
      Serial.print("Amount : ");
      Serial.println(Seq[0]);*/
      

    for (uint16_t Channel = 0; Channel < Seq[0]; Channel++) {
      uint16_t OutputChannel;
      OutputChannel = Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 4 + (Channel * 2)];
      _OV_PrevMicros[OutputChannel] = _OV_Micros;
      _OV_PrevValue[OutputChannel] = _OV_NewValue[OutputChannel];
      _OV_NewValue[OutputChannel] = Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 5 + (Channel * 2)];
      if (fade != 0) {
        int16_t test = _OV_NewValue[OutputChannel] - _OV_PrevValue[OutputChannel];

        _OV_Arv[OutputChannel] = fade * 1000.00 / abs(test);
      } else {
        _OV_Arv[OutputChannel] = 0;
      }
        /*Serial.print("Channel: ");
        Serial.println(Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 4 + (Channel * 2)]); // channel
        Serial.print("Fade:    ");
        Serial.println(fade); // speed
        Serial.print("Value:   ");
        Serial.println(Seq[_OV_Step[PlaybackNum] * (Seq[0] + 1) * 2  + 5 + (Channel * 2)]); // value

        Serial.print("Prev:    ");
        Serial.println(_OV_PrevValue[OutputChannel]);
        Serial.print("New:     ");
        Serial.println(_OV_NewValue[OutputChannel]);
        Serial.print("Arv:     ");
        Serial.println(_OV_Arv[OutputChannel]);
        Serial.println();*/
    }
    if (_OV_Step[PlaybackNum] == Seq[1] - 1) { // Step++ or go back to Zero!
      _OV_Step[PlaybackNum] = 0;
    } else {
      _OV_Step[PlaybackNum]++;
    }

  }
}

void OutputValue::Refresh(uint32_t time) {
  _OV_Micros = time;// Get current time
  for (uint16_t Channel = 0; Channel < NUMBER_OF_OUTPUTS; Channel++) { // go thru all the outputs.
    if (_OV_Arv[Channel] == 0) { // when Arv == 0 go to next value, NO fade!
      _OV_Output[Channel] = _OV_NewValue[Channel]; // go to next value no fade.
    } else {
      if (_OV_NewValue[Channel] > _OV_Output[Channel]) { // Yeah value is bigger lets Increase the output
        _OV_Output[Channel] = _OV_PrevValue[Channel] + (_OV_Micros - _OV_PrevMicros[Channel]) / _OV_Arv[Channel];
        // 255 + 500000 (0.5sec) - 0 / 3921 = 127.58 output
        //prev Value + micros - prevMicros / Arv
        // As you see after 0.5 sec the output value = halve way
      } else if (_OV_NewValue[Channel] < _OV_Output[Channel]) {//Yeah value is Smaller lets Decrease the output
        _OV_Output[Channel] = _OV_PrevValue[Channel] - (_OV_Micros - _OV_PrevMicros[Channel]) / _OV_Arv[Channel];
        // Same only then to decrease value.
      }
    }
    _OV_Output[Channel] = constrain(_OV_Output[Channel], 0, 255);
  }
}


inline uint16_t OutputValue::Output(uint16_t Channel) {
  return _OV_Output[Channel];
}

in de sketch zie je 2 voorbeelden die ik heb uit gedokterd (trail and error) dus die geven een moeie sinewave maar ik snap het niet, ik zie geen verband.

Ben je er je bewust van dat sin met radialen werkt en niet met graden?
Verder weet ik niet zeker wat de huidige C/C++ compilers maken van (int16_t /float)+float.
Om zeker te zijn zorg ik altijd at alles van het eind type is
Dat wordt dan

float in=OV.Output(0);
float deler=6.366;
float toevoegen=5.57;
Serial1.print(sin(( in/ deler) + toevoegen) * 10 + 245);

Ben je er je bewust van dat sin met radialen werkt en niet met graden?

ja’ish

PI = 3 radialen en een beetje of 180 graden
PI x2 = 6 radialen en een beetje 0f 360 graden

Verder weet ik niet zeker wat de huidige C/C++ compilers maken van (int16_t /float)+float.
Om zeker te zijn zorg ik altijd at alles van het eind type is
Dat wordt dan

ja zal ik gaan proberen.

en pin 13 is niet PWM dus 3,5,6,9,10,11 wel dus andere pin kiezen, dan zul je ook zien dat het beter signaal geeft.

shooter:
en pin 13 is niet PWM dus 3,5,6,9,10,11 wel dus andere pin kiezen, dan zul je ook zien dat het beter signaal geeft.

Dat ligt aan het bord :wink: Op een Leonardo is pin 13 een PWM pin.

Of toe wel ik gebruik een mega. Zo als je in de sketch kan zien ik gebruik 2 serial ports. Port0 voor serial monitor en port1 voor de plotter. Led 13 gebruik ik gewoon omdat het kan.

een mega heeft 16 pwm outputs. ik denk dat je hier wel iets mee kunt. ik gebruik het om een sirene geluid te maken met een piezo. hiermee creëer je dus een halve sinus, het positieve deel.

for (int x=0; x<180; x++) {
//convert degrees to radians then obtain sin value
sinVal = (sin(x*(3.1412/180)));
//generate a frequency from the sin value
toneVal = 2000+(int(sinVal*1000));
tone(8, toneVal);
delay(2);

spirit:
ja'ish

PI = 3 radialen en een beetje of 180 graden
PI x2 = 6 radialen en een beetje 0f 360 graden

ja zal ik gaan proberen.

Je kan een hoek uitdrukken in radialen of in graden:

180 graden is pi radialen
360 graden is dus 2*pi radialen en 90 graden is pi/2 radialen.

pi is gewoon 3,14159.....

dus als je de sinus wilt weten van hoek alpha in graden moet je de hoek eerst vermenigvuldigen met (pi/180) om radialen te krijgen:

y = sin(alpha * pi / 180)

In Arduino.h wordt een aantal handige constanten gedefinieerd:
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105

pi/180 = DEG_TO_RAD