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

Add DC motor controller #162

Merged
merged 10 commits into from
Feb 12, 2019
Merged

Add DC motor controller #162

merged 10 commits into from
Feb 12, 2019

Conversation

krwq
Copy link
Member

@krwq krwq commented Jan 28, 2019

No description provided.

@krwq
Copy link
Member Author

krwq commented Jan 28, 2019

Seems there is one more way to control DC motor which more correct for high amperage: use enable pin to feed PWM and IN1 and IN2 for controlling direction. Need to fix up this PR (https://www.teachmemicro.com/use-l298n-motor-driver/)


DC motors can be controlled with 1 or 2 pins:
- When 1 pin is used the speed is controlled with PWM, second pin is connected to the ground
- When 2 pins are used 1 of the pins is controlled with PWM and the second controlls the direction (PWM signal has to be inverted when direction is inverted)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo controlls -> controls

@joperezr
Copy link
Member

Instead of naming it MotorController, can we use the actual chip name/number that the binding supports? Eventually we’ll have mor motor controllers so we should be specific to which ones each binding supports.

using System.Device.Pwm;
using System.Device.Pwm.Drivers;

namespace Iot.Device
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from changing the DCMotor name to an actual device that is supported by this binding, we need to include that class name as part of the namespace since all of the drivers go into one bindings dll where we keep them apart by using namespaces.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DCMotorController works the same for all motors and the only difference is how you connect them but I'm planning to handle this in this class. With Servo I believe we can have both specific and generic version since Servo has some more params

public class DCMotorController : IDisposable
{
private const double PwmFrequency = 50; // Hz
private PwmController _pwm;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readonly? same goes for the GpioController


public void Dispose()
{
_pwm.Dispose();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a null check and set them to null after disposing so that multiple Dispose calls on this object would work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we already do that inside of the _pwm class but can add that

/// Initialize a DCMotorController class
/// </summary>
/// <param name="pin0">The GPIO pin number used for controlling the speed of the motor.</param>
/// <param name="pin1">The optional GPIO pin number used for controlling the direction of the motor.</param>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add some instruction as well mentioning what would a PinValue.High or a PinValue.Low would mean in terms of direction? Also, should we provide what is the default when null is used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll actually change this completely. It'll be more like:
int? d0, int? d1, int? enable and this basically will be basically asking the user how did they connect the motor to the H-bridge (naming matches the pins on H-bridge) and depending on how they connected we will internally change behavior to work with that


_speed = 0;
_controller = new GpioController();
_pwm = new PwmController(new SoftPwm());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we allow using hardware PWM as well?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels wasteful considering this will usually work with around 50Hz. Is there any way to detect current pin is hardware PWM? Maybe we should have some kind of AutoPWM class which will auto-pick

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be addressed already


## Summary

This is a generic class to control any DC motor.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will it really work for any DC Motor? should we provide a list of devices where we have tested the binding and ensured that it works?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any motor connected to the H-bridge yes except the stepper motors which work completely differently but uniform across all stepper motors


It is not recommended to connect any motors directly to the controller and to use H-Bridge instead (i.e. L298N)

## Sample
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR should include a Samples project that has this code and it also has a README.md file and a fzz diagram

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have that in plans

/// </summary>
public class DCMotorSettings
{
public int? Pin0 { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should Pin0 and Pin1 have more descriptive names? Like what are they connected to for example, or what should each control? In other words, how do I know if one of the pins I'm using is Pin0 or Pin1? Having doc comments on the properties would help with this.

Copy link
Member Author

@krwq krwq Feb 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapping data pins will swap the rotation direction and there is not really a good name for that (depending which way the current flows and how much electrons flow you get different direction and speed). Currently it will work regardless of how you connect it (at least that was the intention).

To give more background:

The H-bridge you connect DC motor has 3 pins per motor

  • enable where you connect PWM, this disables the output but allowing the motor to still roll without stopping which makes it suitable for controlling the speed
  • 2x data which controls the output using potentially different power source - so D0=0; D1=1 will make the motor move one way and D0=1; D1=0 will make it move the other.

optionally you can skip using enable pin (enable=1) and use 2x data pins and use one of them as PWM - that may cause the H-bridge to get a bit warm for larger engines and causes the engine to virtually stop when there is no voltage between PWM and the other pin.

I find this settings class a bit confusing as well but it is as clean as I could come up with until #204 is addressed. If this was fixed the way I proposed I could remove half of the options here and make this much more readable.

I'll make sure to document this in the sample/README but don't have ideas for better name.

Copy link
Member

@joperezr joperezr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a small question regarding property names/comments. Other than the fact that this is missing the Samples project, this LGTM once that gets added.

@krwq
Copy link
Member Author

krwq commented Feb 11, 2019

@joperezr any chance you could take another look?

_controller = controller ?? new GpioController();
}

public abstract double Speed { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add summary comments to all these public facing API? Specifically it would be nice if the comments for properties like this one had the units so we know what we the value of this double means.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment about adding comment summaries to the public API applies to the rest of your classes, like the settings, etc.

_controller = null;
}

public static DCMotor Create(DCMotorSettings settings)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason why you wanted to go with the factory method instead of using a constructor that gets the settings passed in?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are currently 2 different implementations and implementation depends on the settings (I was wondering if there should be 3 at one point but ended up joining 2 together). I'm almost sure there will be eventually IDCMotor since @Ellerbach's motor implementation abstracted over Spi is a bit similar.

In order to have a constructor I'd have to have a layer of indirection which does not seem necessary since there is very little inconvenience here but a tiny per call perf gain from less indirection

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go more for an interface for those kind of classes than code where we'll pass specific elements (GPIO, SPI, I2C, specific). One of the Reason is that in the case of the implementation I've done, the bellow classes even is thay are using SPI and I2C are specific. Calling a function to move a motor is not the same way.
Now, once we have our motors with a common interface, it is pretty easy to have higher level calsses like vehicle which can be fully standardized.
And we can Apply the exact same discussion on Sensors. What should be the interface all sensors should implement so it makes it easier for higher level integration.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's have these conversations separately, I think this is out of scope for this PR

@krwq
Copy link
Member Author

krwq commented Feb 12, 2019

@joperezr any more feedback or can I merge?

/// <summary>
/// Controller related with operations on pins
/// </summary>
protected GpioController Controller;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this protected? Do you use it anywhere? If not, this should probably be private and readonly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is used in two of the implementations.

Copy link
Member

@joperezr joperezr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add the DC motor to the bindings list on the src/devices/README.md before merging?

@krwq
Copy link
Member Author

krwq commented Feb 12, 2019

this is just rebase (merge conflict)

@krwq krwq merged commit f6867c3 into dotnet:master Feb 12, 2019
@github-actions github-actions bot locked and limited conversation to collaborators Dec 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants