hybridgroup / cylon-gpio

Cylon drivers for GPIO devices
http://cylonjs.com
Other
19 stars 14 forks source link

Stepper Motors with Cylon #55

Open troywweber7 opened 8 years ago

troywweber7 commented 8 years ago

I would like to use the BigEasyDriver to drive a stepper motor from the Arduino.

I've chosen Cylon over Johnny-Five because, although newer, I believe Cylon has the right structure in place to make the system incredibly extensible and I believe it fits a larger scheme that I have in mind.

What I noticed with Cylon is a lack of support for stepper motors, although Arduino firmata packages exist which can support steppers, one such instance even being configurable to include only the necessary features.

Here is what I'm looking for:

  1. If someone has already driven stepper motors using Cylon, I would like to know about it.
  2. If not, I am prepared to find time to make it happen myself (I have both C/C++ knowledge as well as minor Javascript knowledge), but I will definitely need some guidance: where should I start?

Please NOTE, I can always simply use individual pins to drive the BigEasy, but handling the timing for a stepper motor on the Node.js side is NOT ideal. It is far better to handle the timing for a stepper motor on the Arduino which is why these firmata's which include stepper motor functionality exist.

troywweber7 commented 8 years ago

The first step I am taking is to teach myself how to write a driver for Cylon in general. I am using these docs and referencing other drivers to move myself along. Any tips/tricks are greatly appreciated.

One question I have (that I may well answer as I progress): how might I extend functionality of an existing driver? Does that even make sense? i.e. I will write a driver for the BigEasyDriver, but certain functions such as moveRevs(dir, revolutions) don't really make sense until you attach a stepper motor which determines the steps per revolution, so it feels like such functions should subclass the BigEasyDriver but maybe I'm wrong about that organization?

dtex commented 8 years ago

@troywweber7 I'm going to cross post my answer from cylon-firmata https://github.com/hybridgroup/cylon-firmata/issues/47 I think this is the better forum and if you have two issues open for the same project it will be hard to keep a coherent thread. You should probably close the other one and point people here.

dtex commented 8 years ago

Hi @troywweber7, I don't work a lot with Cylon (I'm a Johnny-Five contributor) but I'm following this issue because I am about to start on an update to Johnny-Five's stepper class and figured we might be able to share some info and ideas.

You won't really need any C for this (unless you are looking to make some changes to firmata). The work required is 100% JS so this is a great way to increase your knowledge. Your Cylon GPIO driver is going to be talking to firmata.js. The stepper protocol between firmata.js and firmata on the Arduino is documented here but that is abstracted away by firmata.js so you won't really need to know it. I just think it helps to understand what's happening at the next layer.

The firmata.js API for stepper is documented in the source. Fortunately it's only 74 lines of code and there are only two methods to worry about: stepperConfig() and stepperStep().

If you create this class you will want to go ahead and support the Big Easy driver, two wire and for wire stepper motors. I say this because all the heavy lifting is handled for you in firmata on the Arduino \o/. You only have to pass in some different configuration commands.

The real work here will be designing an API that exposes all the methods that Cylon users will need to control their stepper without making it too difficult. For that I recommend looking at Johnny-Five's stepper class documentation and source. It's okay to get inspiration from our code (open source FTW)... just make sure you give credit where it's due.

In Johnny-Five we expose 5 getter/setter methodsrpm(), speed(), direction(), accel(), decel(). We also expose three other commands: step(), cw() (clockwise), and ccw(). I'd argue that these are the minimum you will need in Cylon but rpm() and speed() could be combined into a single frequency() method. This might be the preferred way for Cylon.

That last statement is based on a comparison between Johnny-Five's motor and servo API's and Cylon's motor and servo API's, I think the Hybrid Group prefers to provide the basics and leave the helper methods as an exercise to the user, whereas Johnny-Five gives the users a lot of helper methods.

However you choose to move forward, I'd say the first and most important step is to design the Cylon Stepper API and get buy-in from the maintainers. Don't start anything until you have that.

deadprogram commented 8 years ago

Hi, everyone. Thanks for chiming in @dtex collaborating sounds great. A few elaborations/corrections:

The cylon-gpio drivers can use any of the cylon adaptors that support the GPIO interface. cylon-firmata cylon-raspi cylon-chip and other cylon adaptors all provide this interface. You would not need to ever call directly to firmata.js from your driver. In the case of using the cylon-firmata adaptor it uses firmata.js. In the case of other cylon drivers that support GPIO, a sysfs interface is the most common implementation.

For Cylon.js this kind of separation of concerns and interface-based programming comprise the overall design philosophy. Since there are many interfaces that we support beyond GPIO/I2C such as HMI interfaces, drone interface etc. this makes sense for what we're doing.

Regarding how complete the API is for any particular driver, we try as best we can, and rely on the community to help out. Sometimes that means for more basic implementation, sometimes more complete.

Regarding the design of a stepper API, I have not looked at what Johnny-Five is doing, but sounds like a very good place to start. There has been some discussion about the needs of such an API in Gobot but nothing implemented yet AFAIK: https://github.com/hybridgroup/gobot/issues/256

@troywweber7 regarding your question about extending drivers: yes. We already do that in the cylon-i2c module, take a look at thei2c superclass here https://github.com/hybridgroup/cylon-i2c/blob/master/lib/i2c-driver.js and here is one of the sub-classes, in this case for the BlinkM https://github.com/hybridgroup/cylon-i2c/blob/master/lib/blinkm.js

This is a great conversation, really looking forward to collaborate on some cool solutions here.

troywweber7 commented 8 years ago

Thank you for the responses. I also just want to clarify that I am a complete newb when it comes to Javascript (2 months now). I have plenty of experience driving motors and other hardware as my Mechanical Engineering concentration was Mechatronics. Before I get to the responses, I have a few new questions as well (some of which may have to do with my newb-javascript-standing/C++ background). If these merit new threads, I apologize ahead of time for posting here:

  1. I've noticed ES6 and the upcoming ES7 have support for classes and arrow functions (which I'm still getting the hang of). I think its important for me to understand prototypal-inheritance and traditional this-binding, but is there any plan for supporting ES6/ES7 class syntax in Cylon's future?
  2. My coworker (whom I learn from) heavily uses Typescript for everything: client side, server-side, etc. My use of Cylon is intended for on the server side and inevitably if my coworker ever has to interface with the code, he's going to want me to typescript-ify it if possible. Any ideas? Any experience? I may just find a way to write interfaces that make using a defined robot structure easier.

Now on to responses.

@dtex

I am about to start on an update to Johnny-Five's stepper class and figured we might be able to share some info and ideas.

Where would I follow this stepper class update?

You won't really need any C for this (unless you are looking to make some changes to firmata).

I'm not planning changes. Yet. To clarify, however, I am interested (in the near future) in using ConfigurableFirmata (or firmata builder) to take advantage of instantiating a class on the Arduino itself. This is something J5 is already capable of, and it significantly decreases the serial comms with Arduino while increasing the stepper motor speed/accuracy. The only point at which I may get to use C/C++ (sad! I love C++...) is if I decide the Arduino Stepper Motor class (or AccelStepper class) does not fill out the features of the BigEasyDriver sufficiently (I don't recall if it handles all three MS pins well/properly) then I may have to modify that class and possibly the Arduino firmata to improve it.

In Johnny-Five we expose 5 getter/setter methods rpm(), speed(), direction(), accel(), decel(). We also expose three other commands: step(), cw() (clockwise), and ccw(). I'd argue that these are the minimum you will need in Cylon but rpm() and speed() could be combined into a single frequency() method. This might be the preferred way for Cylon.

So, this is an interesting topic to discuss because I've grown to believe that code should represent the real world as closely as possible (while smoothing out the complexities). My "real-world" proposition (and the direction I am heading) involves finding a way to separate the concepts of the stepper and the stepper driver. That's why I've started with writing a driver for the BigEasyDriver. Not all drivers are created equally (some have less MS pins than others, etc.), and so I think its important to abstract out that idea. So when a stepper is instantiated, you can choose to drive it directly (by what type it is) or choose to use it via driver. It is headed in that direction already (sort of), but from what I saw, it seems limited to drivers that use MS pins (and only 1 or 2 if I saw correctly). What about drivers that use serial communication? Or some other method of activating the step? Or a driver that tries to provide even smaller step division?

For driver's (in general) I think the following methods should be exposed to be used by a stepper motor (or trickled up to stepper methods without a driver). With each of these, there is a design choice of whether to write it as a setter-getter or to separate the two into set___() and get___(). I'm currently undecided on whether this abstraction should happen on the Arduino or in Javascript.

Driver abstraction I'm currently implementing this javascript-side

Stepper abstraction not implementing this yet, thinking ahead

Further abstraction notes

However you choose to move forward, I'd say the first and most important step is to design the Cylon Stepper API and get buy-in from the maintainers. Don't start anything until you have that.

For the sake of my work, I have to move forward in some direction. Something that I do need help with though is: should this stepper-driver really exist in Cylon-GPIO, or should it exist as its own separate module (i.e. Cylon-Stepper-Driver(s))? I've currently forked Cylon-GPIO, submoduled it into my project directory, and am working as though this concept for the driver belongs in the cylon-gpio space. Any recommendations on this are appreciated. I suspect the stepper abstraction layer might reside as its own repository, but of course, I'm not certain about that yet.

@deadprogram

You would not need to ever call directly to firmata.js from your driver. In the case of using the cylon-firmata adaptor it uses firmata.js. In the case of other cylon drivers that support GPIO, a sysfs interface is the most common implementation.

This is what led me to originally believe that I may need to do some work in cylon-firmata, but I recently noticed that there are commands for sending a custom SYSEX-formatted command through firmata.js, which should allow me to work with Configurable Firmata steppers (haven't gotten there yet, that's my next step in simplifying the BigEasyDriver module/stepper module. I suppose another route I can go is to help improve the addition of steppers in configurable firmata. I currently cannot take time to wrap my head around the other cylon drivers that support GPIO through sysfs because I have a specific use case to support.

Regarding how complete the API is for any particular driver, we try as best we can, and rely on the community to help out. Sometimes that means for more basic implementation, sometimes more complete.

If I said anything to offend, do forgive that. I want to be a part of the community that helps out and strives for the "right" or "best" solution. I need help with that, of course, because the Cylon framework is brand-new to me, but I believe it is the right direction for my needs (gut reaction, no offense meant toward Johnny-Five whatsoever).

Regarding the design of a stepper API, I have not looked at what Johnny-Five is doing, but sounds like a very good place to start.

I'm not 100% on how J5 handles it yet either. My next step once I've understood all I can about writing a simple driver is to move toward using Configurable Firmata on the Arduino to simplify.

regarding your question about extending drivers: yes. We already do that in the cylon-i2c module, take a look at thei2c superclass here...

Thank you for these resources! I haven't read them yet, but I will.

I'm in agreement that this is good conversation, though I'm sure this was probably a much larger response than anyone wants to read...

dtex commented 8 years ago

@troywweber7

Where would I follow this stepper class update?

https://github.com/rwaldron/johnny-five/issues/1218#issuecomment-249092151

troywweber7 commented 8 years ago

@dtex, sorry to have gone MIA. I determined that I was getting off track at work and have shelved the changes for the time being and gone a different route involving TypeScript/firmata.js until I can justify contributing. I hope to revisit Johnny-Five/Cylon in the future. So for now, don't expect much from me. Very sorry.

However, I will say that if I was going to pick this back up right here, I would actually start with updating Cylon-Firmata to include more of the functionality that firmata.js already provides. firmata.js already has board.stepperConfig() and board.stepperStep(). They need some work and sound like they are going to get it, but I agree with the comment you linked, a rework of steppers should probably happen at the ConfigurableFirmata/firmata.js level right now.

Sorry if I got any hopes up. I hope to revisit this in the future.