Go Down

Topic: Arduino Lightsaber (Read 156425 times) previous topic - next topic

Canobi

Found some time during midst workshop rearrange to make the first of the round PCBs (24mm dia):



These were brought to tolerance by hand using a grinder, files and sandpaper and I used a micrometer to take the measurements.

I've started formulating a build plan for a jig to cut boards out, shouldn't take long once I've finished organising my workshop.

jenga67

Hi everyone!

I have a small question regarding WT588D playlists (Equations), apologies for noobness in advance.

Up to this moment I was able to use only first 10 playlists on my WT588D (00H - 09H), referring to them in WT588D_Send_Command() as numbers from 0 to 9.
But when I try to use the next set with letters (0aH-0fH) or numbers (10H-19H) I can't get the sounds to play, WT588D is silent until I trigger one of the first 10 playlists.

If you guys could tell me what is required to use the playlists other than first 10, you would definitely save my day!


splinter182

Hi everyone!

I have a small question regarding WT588D playlists (Equations), apologies for noobness in advance.

Up to this moment I was able to use only first 10 playlists on my WT588D (00H - 09H), referring to them in WT588D_Send_Command() as numbers from 0 to 9.
But when I try to use the next set with letters (0aH-0fH) or numbers (10H-19H) I can't get the sounds to play, WT588D is silent until I trigger one of the first 10 playlists.

If you guys could tell me what is required to use the playlists other than first 10, you would definitely save my day!


What are you passing as a parameter to WT588D_Send_Command? the function takes an unsigned char which you can pretty much treat as an 1 byte integer. Have you tried passing 10 to the function? the H in 0aH denotes the number as a Hex number, when converting it to decimal, the H is no longer needed

jenga67

Hi Splinter, thanks for your reply!

I tried to pass 10, 11, 12 to WT, also letters a,b,c, 0a, 0b, 0c, but when the sound under those numbers is triggered it just gets silent.

But is it ok for you? You just upload all the sounds to playlists 0-9, a-f, 10-19 and pass the equation numbers to WT to be played? Nothing special declared in the code for the playlists?

JakeSoft

Hi Splinter, thanks for your reply!

I tried to pass 10, 11, 12 to WT, also letters a,b,c, 0a, 0b, 0c, but when the sound under those numbers is triggered it just gets silent.

But is it ok for you? You just upload all the sounds to playlists 0-9, a-f, 10-19 and pass the equation numbers to WT to be played? Nothing special declared in the code for the playlists?
If you want to skip playlist addresses for some reason, you can do so by using the WT588D programming app's "insert silence" feature to populate the addresses you don't want to use with a 10ms silence. You can't outright skip addresses, doing so will make all playlists (equations) after the gap inaccessible at runtime; they won't play even if your code is perfect.

jenga67

Hi guys!

I can say that I have finished my first build.

Have cut the hilt out of PVC tube, tried to make it look nicer, but it is still way too simple.
For next build I will order an aluminium hilt.

In the end, I have used Arduino Pro Micro 5v, WT588D-U, MPU6050, 2x CR123A 3.7v batteries for my build.
One battery with 5v stepup to Arduino and WT, another battery straight to the LED.
Used a motion manager from USaber library for MPU6050, it is great, I can recommend it 100%.
Big thanks to Jake for putting together USaber. I feel like playing with thresholds and timings a bit more, but later.

Here is a video of my build

Still have to figure out the playlist numbers usage up from 9, will do it later on, I was able to play those playlists, but they are not under the numbers i see in the software, strange.

Thanks everyone who contributed to this thread!


 

JakeSoft

Hi guys!

I can say that I have finished my first build.

Have cut the hilt out of PVC tube, tried to make it look nicer, but it is still way too simple.
For next build I will order an aluminium hilt.

In the end, I have used Arduino Pro Micro 5v, WT588D-U, MPU6050, 2x CR123A 3.7v batteries for my build.
One battery with 5v stepup to Arduino and WT, another battery straight to the LED.
Used a motion manager from USaber library for MPU6050, it is great, I can recommend it 100%.
Big thanks to Jake for putting together USaber. I feel like playing with thresholds and timings a bit more, but later.

Here is a video of my build

Still have to figure out the playlist numbers usage up from 9, will do it later on, I was able to play those playlists, but they are not under the numbers i see in the software, strange.

Thanks everyone who contributed to this thread!
Congratulations on your first build! It's looking and sounding pretty good. As far as I know, you are the first to publish a video of a saber with that particular hardware combination. I'm glad USaber has served you well.

danboe70

#1237
May 15, 2017, 06:14 pm Last Edit: May 16, 2017, 08:31 pm by danboe70
Hi everyone

First of all thanks to those who contributed to the incredible saber-library.
I have just started the project for my own saber.

I am going to use the following things:
- Arduino Nano
- MPU6050
- SD-Card Adapter
- DFPPlayer Mini
- 3W Power LED (single color)
- 10Ohm 3W Resistor
- BUK453
- XL6009E1 Boost Converter
- BRC18650 3.7V 300mAh

I have planned designing a PCB where everything is going to be mounted, plus it is optional to use the SD-Card Adapter with SPI Interface or the DFP-Player. Eighter of both can be used.
The first design is already done. And it looks like this (DFPPlayer mini is missing):


I have now some questions for all those who already have built their own one:
1. Question:
I managed to create a Software for the Arduino Nano. MPU6050 is recognized, LED works wonderfull, even the soundthing works. BUT...
Currently I am using the SD-Card Adapter with SPI (Link), but there is some pause between swing, clash and hums. It does not matter in which sequency. I have checked my audiofiles if there were any dead-spaces with silence in it, but there isn´t. What can I do? And what can I do to help you helping me?

2. Question
The PCB seems pretty bulky in my eyes. It is my first one every and I am pretty new to this, so are there any sugestions on making it perhaps a bit smaller?

3. Question
I want do build the hilt, but I haven´t the equipment for building one. I think a turning lathe and a milling machine would be something I could need in the process of construction.
Are there some cheap facilities I cand send for example dxf-Files and they produce the desired thing? I´m thinking of 10-20€ per piece.
If there are no facilities that meet those requirments, does anyone have any ideas on how I can carry on with my project?


Finally thank you all for your time in advance!


[EDIT]
4. Question
I got stuck implementing the lines for the DFPlayerSoundPlayer.
Error:
Code: [Select]

***\Arduino\ArduSaber\ArduSaber.ino: In function 'void setup()':

ArduSaber:212: error: 'DFPlayerSoundPlayer' was not declared in this scope

     DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);

     ^

ArduSaber:212: error: expected type-specifier before 'DFPlayerSoundPlayer'

     DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);

                                              ^

Multiple libraries were found for "SD.h"
 Used: ***\Arduino\libraries\SD
 Not used: C:\Program Files (x86)\Arduino\libraries\SD
exit status 1
'DFPlayerSoundPlayer' was not declared in this scope


My lines of Code where this shows up:
Code: [Select]

 #ifdef DFP_PLAYER
    memset(&gSoundMap, 0, sizeof(DFPlayerSoundMap));
    //Sound font features. Numbers here are arbitrary.
    //These values should be adjusted to match how your
    //sound module is programmed.
    gSoundMap.Features.FontIdsPerFont = 1;
    gSoundMap.Features.HumSoundsPerFont = 1;
    gSoundMap.Features.PowerUpSoundsPerFont = 1;
    gSoundMap.Features.PowerDownSoundsPerFont = 1;
    gSoundMap.Features.ClashSoundsPerFont = 8;
    gSoundMap.Features.SwingSoundsPerFont = 8;
    gSoundMap.Features.LockupSoundsPerFont = 1;
    gSoundMap.Features.BlasterSoundsPerFont = 1;
    gSoundMap.Features.ForceSoundsPerFont = 0;
    gSoundMap.Features.CustomSoundsPerFont = 0;
 
    //Sound locations
    gSoundMap.Locations.BaseAddr = 0;
    gSoundMap.Locations.BlasterBase = 21;
    gSoundMap.Locations.BootBase = 1;
    gSoundMap.Locations.ClashBase = 12;
    gSoundMap.Locations.SwingBase = 4;
    gSoundMap.Locations.LockupBase = 20;
    gSoundMap.Locations.PowerupBase = 2;
    gSoundMap.Locations.PowerdownBase = 22;
    gSoundMap.Locations.HumBase = 3;
    gSoundMap.Locations.FontIdBase = 1;
 
    DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);
 
    //Turn down the volume because 3W amp is so freak'n loud!
    // lpSoundPlayer->SetVolume(18);
    // lpSoundPlayer->Init();
  #endif

I have the following includes:
Code: [Select]

#include <Wire.h>
#include <USaber.h>
#include <TMRpcm.h>
#include <SD.h>
#include <SPI.h>

JakeSoft

4. Question
I got stuck implementing the lines for the DFPlayerSoundPlayer.
Error:
Code: [Select]

***\Arduino\ArduSaber\ArduSaber.ino: In function 'void setup()':

ArduSaber:212: error: 'DFPlayerSoundPlayer' was not declared in this scope

     DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);

     ^

ArduSaber:212: error: expected type-specifier before 'DFPlayerSoundPlayer'

     DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);

                                              ^

Multiple libraries were found for "SD.h"
 Used: ***\Arduino\libraries\SD
 Not used: C:\Program Files (x86)\Arduino\libraries\SD
exit status 1
'DFPlayerSoundPlayer' was not declared in this scope


My lines of Code where this shows up:
Code: [Select]

 #ifdef DFP_PLAYER
    memset(&gSoundMap, 0, sizeof(DFPlayerSoundMap));
    //Sound font features. Numbers here are arbitrary.
    //These values should be adjusted to match how your
    //sound module is programmed.
    gSoundMap.Features.FontIdsPerFont = 1;
    gSoundMap.Features.HumSoundsPerFont = 1;
    gSoundMap.Features.PowerUpSoundsPerFont = 1;
    gSoundMap.Features.PowerDownSoundsPerFont = 1;
    gSoundMap.Features.ClashSoundsPerFont = 8;
    gSoundMap.Features.SwingSoundsPerFont = 8;
    gSoundMap.Features.LockupSoundsPerFont = 1;
    gSoundMap.Features.BlasterSoundsPerFont = 1;
    gSoundMap.Features.ForceSoundsPerFont = 0;
    gSoundMap.Features.CustomSoundsPerFont = 0;
 
    //Sound locations
    gSoundMap.Locations.BaseAddr = 0;
    gSoundMap.Locations.BlasterBase = 21;
    gSoundMap.Locations.BootBase = 1;
    gSoundMap.Locations.ClashBase = 12;
    gSoundMap.Locations.SwingBase = 4;
    gSoundMap.Locations.LockupBase = 20;
    gSoundMap.Locations.PowerupBase = 2;
    gSoundMap.Locations.PowerdownBase = 22;
    gSoundMap.Locations.HumBase = 3;
    gSoundMap.Locations.FontIdBase = 1;
 
    DFPlayerSoundPlayer *lpSoundPlayer = new DFPlayerSoundPlayer(RX_PIN, TX_PIN, &gSoundMap);
 
    //Turn down the volume because 3W amp is so freak'n loud!
    // lpSoundPlayer->SetVolume(18);
    // lpSoundPlayer->Init();
  #endif

I have the following includes:
Code: [Select]

#include <Wire.h>
#include <USaber.h>
#include <TMRpcm.h>
#include <SD.h>
#include <SPI.h>

Try using DIYinoSoundPlayer instead. The DF version is depreciated. I really need to just remove it from the lib. You are not the first to get tripped up by it.

danboe70

Ohhh...ok...I see.

That means I just have to change the class I am creating an instance of, right?
I do not need to change the hardware for it as well, or do I?

However, thanks a lot for your help. Appreciated it a lot!

I´ll post some images from the results as soon as I am finished.

JakeSoft

Ohhh...ok...I see.

That means I just have to change the class I am creating an instance of, right?
I do not need to change the hardware for it as well, or do I?

However, thanks a lot for your help. Appreciated it a lot!

I´ll post some images from the results as soon as I am finished.
Yeah, that's right. Protonerd's DIYino boards use the same sound chip the DFPlayer sound modules, so the software is cross-compatible.

danboe70

Yeah, that's right. Protonerd's DIYino boards use the same sound chip the DFPlayer sound modules, so the software is cross-compatible.
Thank you very much. Finally got everything to run. However, I still have some troubles with my code when it comes to switch the state-machine from saberIsOn() to turnSaberOff() and saberIsOff()...

Do I realy need those delay-calls you have in your examples?
If so, why? This would just reduce responsiveness or am I thinking the wrong direction?

Code: [Select]

/**
 *      @file      ProgrammStates.ino
 *      @author  danboe90
 *      @brief    This file contains the four functions executed in each state of the state-machine.
 *                   turnSaberOn()       - state 1, entered when pButton1 is pressed
 *                   saberIsOn()          - state 2, automatically entered after leaving state 1
 *                   turnSaberOff()      - state 3, entered when pButton1 is pressed again
 *                   saberIsOff()         - state 0, automatically entered after leaving state 3
 *                                            -> this state is the initial state after booting
 */




/**
 *      @brief    This function turns the saber on.
 */

void turnSaberOn() {
  /* DEBUG Output */
  // Serial.println("turnSaberOn()");
  #ifdef SPI_PLAYER
    /* play sound */
    tmrpcm.play("lsabON.wav");
  #endif
  #ifdef DFP_PLAYER
    gpSoundPlayer->PlayFile(5);
  #endif
 
  bool lPowerupComplete = false;
  while(!lPowerupComplete) {
    apBlade->SetChannel(255, 0);
    lPowerupComplete = apBlade->PowerUp(1000);
  }
  PRG_STATE = 2;
  apBlade->On(); 
}



/**
 *      @brief    This function is executed when the saber is ON.
 */
void saberIsOn() {
  /* apply flicker to the blade */
  apBlade->ApplyFlicker(2);
  /* here goes the code from fetching data from the AMotionManager */
  apMotion->Update();

  if(apMotion->IsSwing()) {
    switch(apMotion->GetSwingMagnitude()) {
      case eeSmall:   /* play sound  */
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabSw.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(7);
                      #endif
                      break;
      case eeMedium:  /* play sound  */
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabSw.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(7);
                      #endif
                      break;
      case eeLarge:   /* play sound  */
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabSw.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(7);
                      #endif
                      break;
      default:        /* what shall we do with the drunken sailor? */
                      break;
    }
  }
  else if(apMotion->IsClash()) {
    switch(apMotion->GetClashMagnitude()) {
      case eeSmall:   /* play sound  */ 
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabCl.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(2);
                      #endif
                      break;
      case eeMedium:  /* play sound  */
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabCl.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(2);
                      #endif
                      break;
      case eeLarge:   /* play sound  */
                      #ifdef SPI_PLAYER
                        tmrpcm.play("lsabCl.wav");
                      #endif
                      #ifdef DFP_PLAYER
                        gpSoundPlayer->PlayFile(2);
                      #endif
                      break;
      default:        /* what shall we do with the drunken sailor? */
                      break;
    }
  }
  else {
    /* motion is no Swing and no clash, therefor hum the dum*/
    #ifdef SPI_PLAYER
      if(!tmrpcm.isPlaying()) {
        tmrpcm.play("lsabHu.wav");
      }
    #endif
    #ifdef DFP_PLAYER
      gpSoundPlayer->PlayFile(6);
    #endif
  }
}




/**
 *      @brief    This function is executed when the saber is turning off.
 */
void turnSaberOff() {
  // Serial.println("turnSaberOff()");
  /* play sound */
  #ifdef SPI_PLAYER
    tmrpcm.play("lsabOff.wav");
  #endif
  #ifdef DFP_PLAYER
    gpSoundPlayer->PlayFile(4);
  #endif
 
  bool lPowerdownComplete = false;
  PRG_STATE = 0;

  while(!lPowerdownComplete) {
    lPowerdownComplete = apBlade->PowerDown(1000);
  } 
}




/**
 *      @brief    This function is executed when the saber is OFF.
 *                No sound and no light is emitted
 */
void saberIsOff() {
  /* IDEA: execute here a blink or fade on the LED in the turn-on-Button */
}


JakeSoft

Thank you very much. Finally got everything to run. However, I still have some troubles with my code when it comes to switch the state-machine from saberIsOn() to turnSaberOff() and saberIsOff()...

Do I realy need those delay-calls you have in your examples?
If so, why? This would just reduce responsiveness or am I thinking the wrong direction?

You need some kind of time buffer after you send a play request to the sound module before you try to send another request. The sound chip can only respond to a play request at about once per 100ms to be safe. Bombarding the chip with rapid-fire requests will give strange behavior or ignored requests.

While I complement you on well structured code, I can see a few problems with it.
1) Why do you have so many switch statements where each case executes the same code? You could get rid of that entirely and condense your sketch.
2) While in the On state, you don't want to pummel a hum sound over and over when no motion is happening every cycle as your code seems to do. It the sound will sputter if you do that unless you have controls elsewhere in your code that you are not showing.
3) You'll want some kind of delay after clash detection to prevent swing sounds from interrupting your clash. As you have it written right now, it'll work OK on a breadboard, but as soon as you put it in a swinging saber you'll have swing sounds interrupting your clash more often than not.

danboe70

You need some kind of time buffer after you send a play request to the sound module before you try to send another request. The sound chip can only respond to a play request at about once per 100ms to be safe. Bombarding the chip with rapid-fire requests will give strange behavior or ignored requests.

While I complement you on well structured code, I can see a few problems with it.
1) Why do you have so many switch statements where each case executes the same code? You could get rid of that entirely and condense your sketch.
2) While in the On state, you don't want to pummel a hum sound over and over when no motion is happening every cycle as your code seems to do. It the sound will sputter if you do that unless you have controls elsewhere in your code that you are not showing.
3) You'll want some kind of delay after clash detection to prevent swing sounds from interrupting your clash. As you have it written right now, it'll work OK on a breadboard, but as soon as you put it in a swinging saber you'll have swing sounds interrupting your clash more often than not.
Thank you for your quick reply and your compliment.

1) there are so many case statements, because I´d like to use different sounds for the "hardness" of a swing or clash. FOr the moment I just used the same file, because it had no sense up to now.

2) I just changed my code after taking a look at my audiofiles and using a delay after the hum sound of aproximatly 290 ms. Thats just the duration of my hum-sound. This would result in the following lines of code:
Code: [Select]

    #ifdef DFP_PLAYER
      gpSoundPlayer->PlayFile(6);
      delay(280);
    #endif



3) Well, I have it on the breadboard for now. Unfortunatly I was not capable of getting clash or swing on the breadboard with my MPU6050. However, once connected with some wires to the breadboard, everything is fine again.

You guessed it correctly, there is some more code. But it is only the main routine and an ISR- handling the on-off-button and some debouncing.

Again many thanks for your help and advices.

jbkuma

Put the MPU on some jumper wires.


(this board is set up for pixel, rgb, and string blade development)

Go Up