Using Moteino with encoder and stepper

Hey guys.
I'm trying to adapt a code I've written for the Uno and XBee and import it to the Moteino.
In case you don't know what it is, here's a link http://lowpowerlab.com/moteino/:.
The sending unit has an optical encoder that sends either "up" or "down" signals.
The receiving unit translates this into "encoder ++" or "encoder --" and than uses the AccelStepper lib to move the stepper in the right direction.

Now something is wrong there, and I can't for the life if me figure it out.
What happens is that the encoder values do change, but the motor seems to vibrate but not rotate.
I have checked the motor, the Easydriver, and the optical encoder.
I even began by simply doing a fresh start and writing a new code to test a Moteino unit with encoder and stepper attached to it.
It worked just fine.

I'd really appreciate if someone could have a look at this code and tell me what's wrong.
Thank you.

////////////////////////
//Moteino FF Receiver///
////////////////////////

#include <RFM12B.h>
#include <AccelStepper.h>
#include <avr/sleep.h>

//int for radio data
int a;
int sum;

//encoder/motor/driver setup
int easyDriverMicroSteps = 4;
int rotaryEncoderSteps = 75;
int motorStepsPerRev = 200;

int MinPulseWidth = 50; //too low and the motor will stall, too high and it will slow it down

int easyDriverStepPin = 8;
int easyDriverDirPin = 9;
int enablePin = 10;

volatile long encoderValue = 0;
byte dataReceive = 0;
long lastencoderValue = 0;

//ON LED
#define onLed 12

AccelStepper stepper(1, easyDriverStepPin, easyDriverDirPin);

//Sleep Function - to diable ED when not active
long previousMillis = 0;
int sleepTimer = 5000;

// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID 1 //network ID used for this unit
#define NETWORKID 99 //the network ID we are on
#define GATEWAYID 2 //the node ID we're sending to
#define SERIAL_BAUD 115200

//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";

// Need an instance of the Radio Module
RFM12B radio;
byte sendSize=0;
char payload[] = "1234567890";
bool requestACK=false;

void setup()
{
radio.Initialize(NODEID, RF12_433MHZ, NETWORKID);
radio.Encrypt(KEY); //comment this out to disable encryption
Serial.begin(SERIAL_BAUD);
Serial.println("Listening...");

stepper.setMinPulseWidth(MinPulseWidth);
stepper.setMaxSpeed(50000); //variable to later determine speed play/rewind
stepper.setAcceleration(1000000000);
stepper.setSpeed(50000);

pinMode(enablePin, OUTPUT);
}

void loop()
{

if(encoderValue != lastencoderValue)
{
digitalWrite (enablePin, LOW);
stepper.run();
int stepsPerRotaryStep = (motorStepsPerRev * easyDriverMicroSteps) / rotaryEncoderSteps;
stepper.moveTo(encoderValue * stepsPerRotaryStep);
lastencoderValue = encoderValue;
previousMillis = millis();
}
else
{
//Stepper sleep after 5sec of no data
unsigned long currentMillis = millis ();
if (currentMillis - previousMillis>sleepTimer)
digitalWrite (enablePin, HIGH);
}

if (radio.ReceiveComplete())
{
if (radio.CRCPass())
{
sum = 0;
for (byte i = 0; i < radio.GetDataLen(); i++) //can also use radio.GetDataLen() if you don't like pointers
{
a = (radio.Data*);*

  • sum+=a;*
  • }*
    _ Serial.println(sum);_
  • if (sum == 49)*
  • {*
  • encoderValue++;*
    _ Serial.println(encoderValue);_
  • }*
  • else if (sum == 99)*
  • {*
  • encoderValue--;*
    _ Serial.println(encoderValue);_
  • }*
  • }*
  • }*
    }
    [/quote]

Now something is wrong there, and I can't for the life if me figure it out.

A simple sketch to test that the motor driver part works BY ITSELF is what is missing.

Hi PaulS, thanks - here's the simple sketch. Works:

//////////////////////////////////////////////////////////////////
//Moteino + Optical Encoder + Stepper
/////////////////////////////////////////////////////////////////
#include <RFM12B.h>
#include <avr/sleep.h>
#include <AccelStepper.h>

//encoder/motor/driver setup
int easyDriverMicroSteps = 4; //I think this is 4 or 8
int rotaryEncoderSteps = 75; //setps per rev on your encoder
int motorStepsPerRev = 200; //this is right - steps per rev on the motor

int MinPulseWidth = 50; //too low and the motor will stall, too high and it will slow it down

// You will need to initialize the radio by telling it what ID it has and what network it's on
// The NodeID takes values from 1-127, 0 is reserved for sending broadcast messages (send to all nodes)
// The Network ID takes values from 0-255
// By default the SPI-SS line used is D10 on Atmega328. You can change it by calling .SetCS(pin) where pin can be {8,9,10}
#define NODEID 2 //network ID used for this unit
#define NETWORKID 99 //the network ID we are on
#define GATEWAYID 1 //the node ID we're sending to
//#define ACK_TIME 50 // # of ms to wait for an ack

//encryption is OPTIONAL
//to enable encryption you will need to:
// - provide a 16-byte encryption KEY (same on all nodes that talk encrypted)
// - to call .Encrypt(KEY) to start encrypting
// - to stop encrypting call .Encrypt(NULL)
uint8_t KEY[] = "ABCDABCDABCDABCD";

//int interPacketDelay = 1000; //wait this many ms between sending packets
//char input = 0;
int data = 0;

// Need an instance of the Radio Module
RFM12B radio;
byte sendSize=0;
char payload[] = "1234567890";
bool requestACK=false;

int easyDriverDirPin = 8;
int easyDriverStepPin = 9;
int enablePin = 10;

//Sleep Function - to diable ED when not active
long previousMillis = 0;
int sleepTimer = 5000;

int val;
int encoder0PinA = 3;
int encoder0PinB = 4;
int encoderValue = 0;
long lastencoderValue = 0;

int encoder0PinALast = LOW;
int n = LOW;
AccelStepper stepper(1, easyDriverStepPin, easyDriverDirPin);

void setup() {
pinMode (encoder0PinA,INPUT);
pinMode (encoder0PinB,INPUT);
pinMode(enablePin, OUTPUT);

Serial.begin (115200);

radio.Initialize(NODEID, RF12_433MHZ, NETWORKID);
radio.Encrypt(KEY);
radio.Sleep(); //sleep right away to save power

stepper.setMinPulseWidth(MinPulseWidth); //may need to play with this, but I think this is good.
stepper.setMaxSpeed(50000);
stepper.setAcceleration(1000000000); //try 100, or 1000 and see if it works
stepper.setSpeed(50000); //play with this to see if it makes a diff (1 to 1000)

}

void loop() {
int stepsPerRotaryStep = (motorStepsPerRev * easyDriverMicroSteps) / rotaryEncoderSteps;
stepper.moveTo(encoderValue * stepsPerRotaryStep);
stepper.run();
if(encoderValue != lastencoderValue)
{
lastencoderValue = encoderValue;
digitalWrite (enablePin, LOW);
previousMillis = millis();
}
else
{
//Stepper sleep after 5sec of no data
unsigned long currentMillis = millis ();
if (currentMillis - previousMillis>sleepTimer)
digitalWrite (enablePin, HIGH);
}
n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoderValue--;
//Transmit(1);
Serial.println (encoderValue);

}
else {
encoderValue++;
//Transmit(2);
Serial.println (encoderValue);

}

}
encoder0PinALast = n;
}

int Transmit (int data)
{
radio.Wakeup();
radio.Send(GATEWAYID, payload, sendSize+(data));
Serial.println (encoderValue);
Serial.println (sendSize+(data));
radio.Sleep();
}

Any thoughts? :relaxed:

Any thoughts?

What does the second code do? Do the motors move smoothly using that code?

What does the first code do? What is the radio stuff all about? You need to describe your project/problem in more detail.

What does the second code do? Do the motors move smoothly using that code?

The second code simply moves the stepper according to the encoder. Everything is attached to the same moteino.
Works like a charm.

What does the first code do? What is the radio stuff all about? You need to describe your project/problem in more detail.

Once the encoder is on one end (Sending unit) and the stepper is on the other (Receiving unit), I'm using the Moteino's radio
to send data - either up or down.
The data reaches the receiver just fine. I'm serial printing to make sure.
But something in the translation from the data to the actual movement is wrong.

Something isn't right here:

if (radio.CRCPass())
    {
      sum = 0;
      for (byte i = 0; i < radio.GetDataLen(); i++) 
      {
        a = (radio.Data[i]);
        sum+=a;
      }
      Serial.print("sum: ");
      Serial.println(sum);
      if (sum == 49)
      {
        encoderValue++;

The way I'm trying to sum up the data isn't right but I don't really know what it is I'm messing up there.

Or maybe it's something to do with the pins? Something here I don't get?

bumping and hoping

I'm probably just being lazy, but I can't easily figure out what's different between the working and non-working code. Perhaps you could identify the differences.

This is the first example I've come across where someone is using a Moteino so I'm interested.

Edit to add ...

I took the trouble to line up the two versions of your code side by side and there are so many detail differences that I gave up. I suggest you take the non-working version as a base and change it as little as possible (by commenting out lines or inserting new stuff) to get a working value. And add a comment for each of these changes so it is clear that they are part of this test.

I presume the Moteino dedicates some "pins" to the built-in radio and I wonder if you are accidentally trying to use them for some other purpose.

There is also a possibility that the library used for the radio isn't compatible with some other library you are using.

...R

Hey Robin2 - thanks. Your curiosity is my gain :slight_smile:

The working code is using just one Moteino with encoder and stepper attached to it.
The changes in the encoder are translated to stepper movements.

stepper.moveTo(encoderValue * stepsPerRotaryStep);
stepper.run();

Obviously it works.

The 2nd code separates the encoder from the stepper.
"Sending moteino" has encoder attached to it, and it sends "up" or "down" via radio.
This is the "sending" code - reading the encoder:

n = digitalRead(encoder0PinA);
if ((encoder0PinALast == LOW) && (n == HIGH)) {
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos--;
Serial.println ("Encoder --");
Transmit(1);
}
else {
encoder0Pos++;
Serial.println ("Encoder ++");
Transmit(2);
}
}
encoder0PinALast = n;

This is the "sending" code - the transmission part:

int Transmit (int data)
{

radio.Wakeup();
radio.Send(GATEWAYID, payload, sendSize+(data));
//Serial.println (encoder0Pos);
Serial.println (payload[sendSize+(data)]);
radio.Sleep();
}

And finally, the "receiving" unit - Moteino connected to stepper, supposed to translate radio to stepper movement:

void loop()
{

if(encoderValue != lastencoderValue)
{
digitalWrite (enablePin, LOW);
stepper.run();
int stepsPerRotaryStep = (motorStepsPerRev * easyDriverMicroSteps) / rotaryEncoderSteps;
stepper.moveTo(encoderValue * stepsPerRotaryStep);
int z = encoderValue * stepsPerRotaryStep;
Serial.print ("encoderValue * stepsPerRotaryStep: ");
Serial.println (z);
Serial.print ("Stepper Pos: ");
Serial.println (stepper.currentPosition());
lastencoderValue = encoderValue;
previousMillis = millis();
}
else
{
//Stepper sleep after 5sec of no data
unsigned long currentMillis = millis ();
if (currentMillis - previousMillis>sleepTimer)
digitalWrite (enablePin, HIGH);
}

if (radio.ReceiveComplete())
{
if (radio.CRCPass())
{
sum = 0;
for (byte i = 0; i < radio.GetDataLen(); i++) //can also use radio.GetDataLen() if you don't like pointers
{
a = (radio.Data*);*

  • }*
  • sum+=a;*
    _ Serial.print("sum: ");_
    _ Serial.println(sum);_
  • if (sum == 49)*
  • {*
  • encoderValue++;*
    _ Serial.print("encoderValue: ");_
    _ Serial.println(encoderValue);_
  • }*
  • else if (sum == 50)*
  • {*
  • encoderValue--;*
    _ Serial.print("encoderValue: ");_
    _ Serial.println(encoderValue);_
  • }*
  • }*
  • }*
    }
    [/quote]
    The result? The stepper hums and vibrates, and seems to be confused...
    The strange behavior is also evident in these 2 facts:
    1. once the encoderValue gets negative - Moteino LED shuts down...
    2. Serial printing for debugging indicates that once encoderValue is negative, the stepperMoveTo() function is erratic.
    This is very strange because the sum int is what it should be at all times...
    Did I manage to explain the issue?

First thing's first: D10 should not be used when radio is in use.
Since I used it for the ED's enable pin, it messed everything up...

Actually, the first thing would be to stop using the Copy to Forum function and surround your code with code tags as this helpful thread suggests.

The first problem here is that you don't know what the problem is.

In my earlier post I suggested a way to make it easier to find the problem. I don't know any better way to do that - diagnosing problems can only be done by small steps if you don't have a flash of inspiration. Strangely the small steps often throw up flashes of inspiration.

...R