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

L298N Support #7

Closed
Lothean opened this issue May 8, 2018 · 15 comments
Closed

L298N Support #7

Lothean opened this issue May 8, 2018 · 15 comments

Comments

@Lothean
Copy link
Contributor

Lothean commented May 8, 2018

Hello!
I'd like to contribute and create code for "L298N" H bridges to be compatible but there's no resources to help me... (understanding the arduino code mostly)
Do you plan on adding some ?

@Sammy1Am
Copy link
Owner

Sammy1Am commented May 8, 2018

100% yes! I will for sure be adding copious comments to the code, and maybe a little more overview on the wiki (though I tend to prefer code comments over separate documents since it involves less cross referencing). This next week is especially busy for me so I won't get a lot of time until later in the month, but I'll leave this issue open to remind me.

For the short term, a couple highlights of what's different from the previous version:

  • MoppyCore.cpp is basically just an extension of the configuration and a convenient point for swapping out e.g. Floppy Drives for a Robo-Xylophone without having to have multiple Arduino sketches. It's also where the setup() and loop() functions live
  • Anything in MoppyNetworks (for now primarily just MoppySerial.* is the part of the code that get executed in the loop() function to receive and send serial communications. MoppyNetworks are given a pointer to a systemMessage handler (for things like start/stop/reset) and a deviceMessage handler (for note on/off messages). When messages are received from the network (serial port) the MoppyNetwork class will call the appropriate handler.
  • Anything in MoppyInstruments (for now just FloppyDrives.*) implements the two handlers above (system and device), and is responsible for driving whatever instrument is connected to the Arduino (as well as any more complex logic like pitch bending or solenoid timing).

For the L298N modifications, you'll probably looking mostly at the MoppyInstruments section (from my understanding of how they work, which is, admittedly, very brief). I'd recommend basically copying FloppyDrives.* to your own class (L298N.*?) and implementing the changes there. That way it's easy to swap out the constructor in MoppyCore.cpp to switch between the default Floppy Drive implementation and the L298N implementation.

@Lothean
Copy link
Contributor Author

Lothean commented May 10, 2018

Thanks, I'll wait for the comments! I learned a lot since I made my first Moppy personal modification! You're going to see me alot here (and maybe in pull requests?) ;)

@Sammy1Am
Copy link
Owner

Great! One of my main goals for 2.0 is to make it a lot easier for me to pull contributions to the library.

I just pushed some updates to add some additional comments to the Arduino code, let me know if those help out (and what might be missing that would help you figure out what you need in order to make changes).

@Lothean
Copy link
Contributor Author

Lothean commented May 16, 2018

Comments do help a lot, but I'm still trying to figure out how to determine if a step must be done. (like, the condition, not just toggling a pin state)
btw: Holly shit, that mapper thing is EXACTLY what I was hoping for, what a good start!

@Sammy1Am
Copy link
Owner

Yeah, the mapper thing's going to solve an awful lot of requests / problems! 😄

The step thing has gotten a little complex, but I'll see if I can't provide some additional insight (some of this you'll no doubt already know, but in case it's helpful to others-- I'll probably just copy this into the documentation on the wiki):

The frequency with which the floppy drive moves its head equates to the frequency of the note you hear. So for the note A2 the head takes steps at 110Hz. Because we're using loops and counters to time the steps we need to get the inverse frequency, or period, for the note. Again for A2 this is 0.0090909 seconds or about 9091 microseconds between steps. This is the number stored in the notePeriods array in MoppyInstrument.h.

We could just do an endless loop and call micros() over and over to wait for 9091 microseconds to pass (a little bit like in startupsound). However that quickly gets confusing for playing many different note frequencies but more importantly it doesn't allow any free processor cycles for reading and writing to the serial port. So instead, we're using an interrupt function (via the TimerOne library) that will interrupt any running code periodically after a specified period and execute a function (for our case the tick() function). We need to allow ample time between interrupts for both the tick() function to complete its work and to give the processor time to read/write to the serial port, so I've picked 40 microseconds between interrupts (this is the number specified as TIMER_RESOLUTION in MoppyInstrument.h).*

Since the tick() function is only going to trigger every 40 microseconds, we don't really need to worry about anything more granular (i.e. there's no difference between 9091 and 9093 microseconds if we're only checking every 40 microseconds anyway). So to simplify things a bit further, we can start defining periods in "Ticks" instead of microseconds. So our friend the A2 can now be described as having 227 Ticks between steps instead of 9091 microseconds.

The floppy drive head takes a step on the falling edge of the signal sent to it (that is, when the voltage of the Step pin drops from 5v to 0v). In order to take a second step, the pin needs to be brought back up to 5v again before we can create another falling edge. For the best signal clarity, we want to keep these rising and falling edges as far apart as we can. Calling togglePin() generates a falling edge every other invocation, so in order to generate falling edges at our desired frequency we need to call togglePin() at twice that frequency (i.e. with half the period). The noteTicks array stores the results of all this math which boils down to (period/resolution)/2, or for A2 (9091/40)/2 = 114 Ticks between calls to togglePin().

Actually tracking the state of each drive is just normal loops and counters after the math above is done. When a NoteOn event comes in, we put the value from noteTicks into the currentPeriod array at the index representing the drive we want to play the note on. Each time tick() is called, we increment that same index in the currentTick array by one. When the value in currentTick reaches the value in currentPeriod, we call togglePin(), reset currentTick to 0, and start over.

Apologies if that was a bit verbose, but better extra documentation that not enough. :P

* The resolution affects the accuracy of the notes being played. For A2 = 110Hz, we actually end up playing 109.65Hz. It gets worse at higher frequencies; an A4 = 440Hz comes out at 446.4Hz. Still closer to A than A#, but the next step down with 40 microsecond resolution is 431Hz which is even worse. Higher resolution would improve note accuracy but runs the risk of overlapping interrupts or not enough cycles for serial processing.

@Lothean
Copy link
Contributor Author

Lothean commented May 18, 2018

Finally, I managed to understand the code! This seems very clear to me now, I'm gonna come up with a modification soon, and I'll make it in a way that does not add any library for the L298N. Thanks a lot again, it was very helpful :)

@Lothean
Copy link
Contributor Author

Lothean commented May 19, 2018

Hey,
I made the code for the L298N and pushed it to my fork : https://github.com/Lothean/Moppy2
It is supposed to work (although I don't access to my hardware at the moment..)
One problem that I've noticed is that changing the instrument does not appear simple:

  • It requires edit in a config file (which I didn't modified on Github because I'm waiting for you to tell us how we are supposed to edit it)
  • If I let both instruments in the MoppyInstruments folder, some variables are declared twice and the Arduino IDE refuses to compile the program.

Can you take a look at my (probably badly made) code and tell me if there's anything wrong that could create issues with Moppy ?
Thanks!

@Sammy1Am
Copy link
Owner

I took a quick look (I'm not super familiar with L298Ns so I'll just have to trust that those parts are fine :P ), and it looks generally good. To address your two questions first:

  1. You'll change the instrument by modifying MoppyCore.cpp to replace:
#include "src/MoppyInstruments/FloppyDrives.h"
FloppyDrives instrument = FloppyDrives();

with

#include "src/MoppyInstruments/L298N.h"
L298N instrument = L298N();

And ideally instead of replacing it outright, you could add the two L298N lines commented out below the FloppyDrive lines. Basically, the "default" for the code base will be the FloppyDrives and it'll be up to the end user to comment/uncomment the appropriate lines there to configure for their instrument.

  1. The variable clash is my fault (and my lack of C++ experience). All the variables in FloppyDrives.cpp and L298N.cpp should also be declared under their respective namespaces (e.g. FloppyDrives::currentPosition instead of just currentPosition. You're welcome to take care of that for L298N whenever, though I'll try to fix that for FloppyDrives the next time I'm working on the code since I'm also going to add a new instrument class (and would have run into the same issues you did).

  2. And one additional thing I noticed, rather than divide by 2 for the noteDoubleTicks only to have to multiply by 2 again during your ticks, we should just add a new array to MoppyInstrument named noteTicks that doesn't divide by 2 (you can just copy and paste the whole thing there and replace DOUBLE_T_RESOLUTION with RESOLUTION. It makes that file even more cumbersome, but cuts down on repetitive math that has to be executed during ticks.

Generally looks awesome though! As soon as I get around to fixing the FloppDrive namespace issue and you get a chance to test on your hardware we can merge it into mainline :)

@Lothean
Copy link
Contributor Author

Lothean commented May 19, 2018

I'll make these changes as soon as I can. Thanks for the advices! I also plan on making a completely different Floppy instrument: One Arduino per channel, and the velocity of the note would change the amount of drive that play the note. Would that be possible with the current Java code ?

@Sammy1Am
Copy link
Owner

The Java code would need to start sending velocity information along with the note information in the MoppyMessages (there'd need to be another byte). Not too hard to do, but would need to be done. I'll add an issue for it.

@Lothean
Copy link
Contributor Author

Lothean commented May 22, 2018

Hey,
Code seems to be working, but with the little time that I had, I only managed to make it work on Channel 1, no idea why nothing was playing on the others. Maybe I'm not familiar enough with the new software.
I tried during the last couple of hours to declare the variables under their namespace; but it's easier said than done for me... I was not able to do it. I uploaded the new code in case somebody needs it, but without any garantee that it's good.

I'm working on a modification of the L298N code which will reduce the amount of bridges that can be connected on the Arduino, but allows more motors to be supported;
L298N "Low Power" will allow the bridge to be completely disabled when no step is being done (and thus, remove the "stand by" current), but will use 2 more I/O pins per bridge. I might not push that one if it seems pointless to others, but it helped me a lot when I had to deal with extreme temperatures on my L298N. So if someone needs it, just ask :)

@Sammy1Am Sammy1Am changed the title No doc? L298N Support May 22, 2018
@Sammy1Am
Copy link
Owner

I meant to fix the namespace thing this weekend but got distracted by Cities: Skylines 😉
Just made a commit to mainline that fixes the issue for FloppyDrives.cpp, you should be able to follow the pattern for L298N.cpp to get it working.

Just about to see if I can't figure out what's up with the channel 1 only thing, but gotta learn a bit about the L298 (and have some food).

@Sammy1Am
Copy link
Owner

Hmm, I couldn't see anything that looked like it would cause issues for not-channel 1 so it might be an issue on the controller app side (either in the mapper configuration or with the program itself).

Also, in my experience most people are looking for ways to add more motors and more floppy drives rather than less :P Power does always end up being a problem though because no one wants to provide a separate power supply for the drives (which isn't even that hard!)

If you still can't get the channel 1 bit working after fixing the namespaces, maybe post a screenshot of the controller app configuration and I'll see if anything looks amiss.

@Lothean
Copy link
Contributor Author

Lothean commented May 22, 2018

Code is done, is working, and I submitted it!
I've declared all variables under their namespace and all channels work.
#11

@Sammy1Am
Copy link
Owner

All merged! I added a limiter to the FloppyDrives code, but those higher notes will be really helpful for anyone using stepper motors.

Congrats on being the first Moppy2 pull!

(Closing this thread as being specific to adding L298N support, but feel free to open a new one for discussion or other questions)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants