I2C Stepper Question

Please tell us which board you are using.
For CircuitPython issues, ask in the Adafruit CircuitPython forum.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

I2C Stepper Question

Post by forum_questions_1 »

Hi, I have the Adafruit Stepper + DC Motor FeatherWing. It has been fun to use so far.

I am a beginner at this, so please pardon a basic question. Instead of using I2C, can I specify digital pins for sending instructions to the motor shield? So far, I have been using I2C and the MotorKit and "onestep". I am interested in trying to replicate some other examples I have seen online which seem to assign signal output from the microcontroller to 2 or 4 digital pins.

I have the FeatherWing stacked onto a Feather ESP32-S3 so there is full connection on all pins. I am most interested in how to do the initial setup (e.g. direction = digitalio.DigitalInOut(board.D6)...etc).
Do you have any examples of circuitpython code that would do this?

Many thanks.

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

It is not possible to directly access the pins on the Motor Wing. The TB6612 H-Bridge driver chips are connected to the PCS9685 PWM controller chip on the motor wing. The pins on the PCA9685 can only be addressed via i2c.

If you want to experiment with direct control of the TB6612 H-Bridges, we do have a breakout board for that: https://www.adafruit.com/product/2448

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Thanks Bill. Knowing it is not possible saves me from spending a lot of time trying to do it. Thank you also for that idea on the other product. Is there anything I can do in code with the feather wing outside of onestep? It works pretty well with double and interleave. With microstepping, I have noticed that there is a pulsating. What happens is I can hear the motor run through the microsteps with (what sounds like) a pulse, then it does a brief pause, then it goes to another round of microsteps. It is almost like it still does 200 main steps with the 8/16/etc microsteps in between. I'd like to try to smooth it out so that it doesn't have the pausing (so that it just goes around in microsteps). I took out any sleep time delays so that is not the issue.

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

Please post the code that you are using.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Thanks Bill. Here it is.
I have a few notes about how I was trying to change steps and frequency in some of the if statements. I was not able to do it if I had more than one i2C device.

Code: Select all

#board_id -- adafruit_feather_esp32s3_4mbflash_2mbpsram

import time
import board
import adafruit_nunchuk
import digitalio
import adafruit_motor
import adafruit_motorkit
import adafruit_pca9685

#duplicative
from adafruit_motorkit import MotorKit
from adafruit_motor import stepper

#busio includes classes I2C, SPI and UART
import busio
from board import SCL, SDA

i2c_bus =  busio.I2C(SCL,SDA, frequency = 4000)
#frequency range looks like minimum is 4,000, max around 1,000,000

nc=adafruit_nunchuk.Nunchuk(i2c_bus)

#kit = MotorKit(i2c=board.I2C())
kit = MotorKit(i2c=i2c_bus, steppers_microsteps=8)

#Joystick ranges:


#x neutral 127
#x max 255
#x min 0

#y neutral 128
#y max 255
#y min 0

while True:

    x, y = nc.joystick
    ax, ay, az = nc.acceleration

    #print("joystick = {}, {}".format(x, y))
    #print("acceleration = {}, {}, {}".format(ax, ay, az))

    #move joystick right. movement will only happen if held in the x == 255 position.
    if x == 255:
        kit.stepper2.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
        time.sleep(0)

    #move joystick left. movement will only happen if held in the x == 0 position.
    elif x == 0:
        kit.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)
        time.sleep(0)

    #move joystick up. movement will only happen if held in the y == 255 position.
    elif y == 255:
        kit.stepper2.onestep(direction=stepper.FORWARD, style=stepper.MICROSTEP)
        time.sleep(0)

    #move joystick down. . movement will only happen if held in the y == 0 position.
    elif y == 0:
        kit.stepper2.onestep(direction=stepper.BACKWARD, style=stepper.MICROSTEP)
        time.sleep(0)

    #press button Z, keep repeating loop until cancelled with button c.
    elif nc.buttons.Z:

        while True:
            
            #When loop begins, if c button press detected, release motor and exit loop
            if nc.buttons.C:
                kit.stepper2.release()
                break

            #If Z is pressed and no button C press detected above, Z moves stepper forward continuously
            else:

                kit.stepper2.onestep(direction=stepper.FORWARD, style=stepper.MICROSTEP)
                time.sleep(0.05)
                
                #I would like to be able to change frequencies and steps mid-code as changing these seems to be a way to slow down/speed up the motor
                
                #this works to change the frequency and stepping mid-code but only if no other i2c device:
                #kit = MotorKit(i2c=busio.I2C(board.SCL, board.SDA, frequency=100000), steppers_microsteps=16)

                #trying to change stepping mid-code in this way makes motor vibrate but doesn't move forward
                #kit = MotorKit(i2c=i2c_bus, steppers_microsteps=4)
    
    #probably duplicative
    else:
        kit.stepper2.release()
        
#might not need this
time.sleep(0.5)


User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

I should say as well, that my goal for this is to have a couple of different speed options available via the joystick. One at a faster speed (maybe 5-10 rpm) and then one at a very slow speed (around 0.5 rpm).

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

Your inner while-loop looks pretty minimal. I don't see anything at the source code level that should cause gaps in the timing. But between the managed environment of CircuitPython and the underlying RTOS on the ESP32, you are a couple layers removed from running on the 'bare metal'.

The CircuitPython Garbace collector can pop up on occasion to clean things up. But your code does not appear to be doing anything that would trigger that. The RTOS might also suspend things at times to attend to background tasks. I'm not familiar enough with the CircuitPython internals to know what interactions with the RTOS there might be.

Do you have any other CircuitPython capable processors? It would be interesting to see if it behaves differently without the RTOS.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Thanks Bill. The only other board I have is an ESP32 V2 Feather. I was not able to get it to work with Mu, so I gave up on using it with Circuitpython.
However, just to experiment, I switched out the S3 for the V2 and used an Arduino sketch. The stepper motor performance was noticeably improved (for my particular use). I'll copy the code at the end. It is basically one of the Example sketches with slight modification. The overall noise level was a lot lower and the microstepping was much smoother. I guess I could switch over to Arduino, though I had hoped to make it work in CircuitPython since I got the wii controller set-up well in the CircuitPython code. The Accel_ConstantSpeed example sketch allows me to reduce the speed to less than 1rpm, but it seems limited at a minimum 1rpm in the sketch below (I am not sure how to change that).

I realize this is not the exact experiment you wanted me to try, but I thought it was an interesting result using Arduino.

Code: Select all

#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61);

// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M3 and M4)
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);

void setup() {
  Serial.begin(9600);           // set up Serial library at 9600 bps
  while (!Serial);
  Serial.println("Stepper test!");

  if (!AFMS.begin()) {         // create with the default frequency 1.6KHz
  // if (!AFMS.begin(1000)) {  // OR with a different frequency, say 1KHz
    Serial.println("Could not find Motor Shield. Check wiring.");
    while (1);
  }
  Serial.println("Motor Shield found.");

  myMotor->setSpeed(10);  // 10 rpm

  Serial.println("ARDUINO_TEST 10rpm");
  myMotor->step(600, FORWARD, MICROSTEP);
  myMotor->release();

//1 rpm seems like it is the minimum (in Accel_ConstantSpeed it can go lower)
  myMotor->setSpeed(1);  // 1 rpm

  Serial.println("ARDUINO_TEST 1rpm");
  myMotor->step(100, FORWARD, MICROSTEP);
  myMotor->release();

}
//No loop
void loop() {
 
}


User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

Arduino/C++ is much closer to the 'bare metal' than Python, so the timing will be more deterministic.

Your code above is not actually using the AccelStepper library. It is using the Adafruit library. Speed control in the Adafruit library is not so good. You should be able to get below 1RPM with AccelStepper.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Ok, thanks Bill. I'll check out using Accelstepper. Thanks for your help. It was interesting to test python and arduino with the motor.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Hi Bill,
I tried to mash together code from the WiiChuck examples with an Accel/Adafruit stepper motor example.
I am now getting an unhappy error when I try to run the motor by pressing a wii button and I can't figure it out.

It says, "Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled."
The it does a "Core 1 register dump:". Then it seems to auto reset.

The good news is I am getting all the data feedback from the Wii controller, which I have connected to an Adafruit adapter. I can get an almost instant serial readout of what movements I make with the controller, which I think is incredible.

I tried to add if conditions to the loop to respond to the Wii controller joystick and buttons. For starters, button Z press to move the motor, button c press to release it. When I press the buttons, the error appears and the code restarts without motor movement. The stepper is wired ok, I tried to use one of the stepper examples and it operates well.

Could you take a look at this code and see if there is anything I could fix? I'd appreciate any help. I tried to look online but didn't find examples I could refer to. If you want me to start a new topic, I can do that.

Code: Select all


//From WiiChuck "WiiAccessory" example
#include <WiiChuck.h>

//From Adafruit "Accel_ConstantSpeed" example
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

//From WiiChuck "WiiAccessory" example (Not sure why readings only work if nunchuck 1 and nunchuck 2 Accesories created)
Accessory nunchuck1;
Accessory nunchuck2;

//From Adafruit "Accel_ConstantSpeed" example
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_StepperMotor *myStepper1 = AFMS.getStepper(200, 2);

//From Adafruit "Accel_ConstantSpeed" example
void forwardstep1() {
  myStepper1->onestep(FORWARD, SINGLE);
}
void backwardstep1() {
  myStepper1->onestep(BACKWARD, SINGLE);
}

//From Adafruit "Accel_ConstantSpeed" example
AccelStepper Astepper1(forwardstep1, backwardstep1); 

void setup() {
	Serial.begin(9600);

//From WiiChuck "WiiAccessory" example (there is only 1 controller, but for some reason no readings unless nunchuck 1 and 2 are coded in)
	nunchuck1.begin();
	nunchuck2.begin();

//my addition to increase speed limit
  Astepper1.setMaxSpeed(10);

////From Adafruit "Accel_ConstantSpeed" example
  Serial.println("Motor Shield found."); 
  Astepper1.setSpeed(5);
}

void loop() {
//From WiiChuck "WiiAccessory" example
	nunchuck1.readData();    // Read inputs and update maps

//My addition, uses WiiChuck's array of values
//This maps to Joy Y
  Serial.println(nunchuck1.values[0]);

//My addition, uses WiiChuck's array of values
//This maps to JoyY
  Serial.println(nunchuck1.values[1]); 

//My addition
// PROBLEM AREA - IF BUTTONS ARE PRESSED, ERROR MESSAGE AND CODE RESTARTS - IF THESE ARE EXCLUDED OR NO BUTTONS PRESSED THEN CODE WORKS  
//Z is value[10} 255, c is value9[11] 255
  if (nunchuck1.values[10]==255) {
    Serial.println("Button Z");
    Astepper1.runSpeed();
   }

  if (nunchuck1.values[11]==255) {
    Serial.println("Button C");
    myStepper1->release();
   }

  else delay(100);

  //end of loop
}


User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

First try to isolate the problem. If you comment out the calls to the stepper functions, do you still see the error when you press the button?

Also, the core dump probably has some useful information relevant to diagnosing the problem.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Thanks Bill. I got it to work!

I took out stepper calls first, and just left the Serial println for buttons Z and C. They worked with no errors.

Next I commented out the Wii items one by one, from the bottom, to see if they were the problem. First I commented out all the Wii items in the loop, keeping Astepper1.runSpeed() in it. I wound up commenting out all of the Wii items, including the library, and I still got the same error.

I decided to go over to the Accel_ConstantSpeed example code that I knew worked to compare it (it should have been almost the same as I had commented out all the Wii references). Just to see if the motor was connected, I ran Accel_ConstantSpeed and the stepper worked.

Then I switched back to the problem sketch, ran it, and the stepper worked. I added in the Wii items one by one from the top and tested if the stepper still ran after each addition. I finally got down to the loop, added the buttons, and it worked.

The only things I have not added back in were Serial.println(nunchuck.values[0]) and Serial.println(nunchuck.values[1]), which returned a stream of x and y coordinates for the joystick in the serial monitor. I do not need these for it, they were mostly just to see if the Wii data was getting read when I first hooked it up.

User avatar
adafruit_support_bill
 
Posts: 88093
Joined: Sat Feb 07, 2009 10:11 am

Re: I2C Stepper Question

Post by adafruit_support_bill »

Good diagnostic work! The error message you were getting is typically associated with an attempt to access an invalid memory address. Maybe the nunchuck library was doing something like returning a null pointer when there was no data.

User avatar
forum_questions_1
 
Posts: 111
Joined: Tue Oct 25, 2022 4:05 pm

Re: I2C Stepper Question

Post by forum_questions_1 »

Thanks Bill. I appreciate your help with it.

Locked
Please be positive and constructive with your questions and comments.

Return to “Feather - Adafruit's lightweight platform”