In the last log I said that I was going to work on transferring the coder over to Zerynth, so here's the documentation of that process! (And the issues I ran into along the way).
Porting main_PWM.py to Zerynth
See the screenshot below of the ESP32 parsing the inputs sent over BLE in the same manner as the main_PWM.py code.

Now that I have the motor direction and range stored in the right variables, the next step is using these values to perform PWM activation of the motors!
Zerynth PWM
There are some similarities when moving the code over to Zerynth because Zerynth is designed to use a mix of Python and C code. However, Zerynth implements its own PWM module, so I had to convert the code to be compatible with their implementation of PWM. See the code below of the Zerynth implementation of PWM.
# Set up pins as PWM
forward_pin = D18.PWM
left_pin = D19.PWM
back_pin = D22.PWM
right_pin = D23.PWM
# Set pins as output
pinMode(forward_pin, OUTPUT)
pinMode(left_pin, OUTPUT)
pinMode(back_pin, OUTPUT)
pinMode(right_pin, OUTPUT)
# Set all to 0 (disabled until activated)
pwm.write(forward_pin, 0, 0)
pwm.write(left_pin, 0, 0)
pwm.write(back_pin, 0, 0)
pwm.write(right_pin, 0, 0)
The code below is the Zerynth implementation of the PWM activation via the equivalent sub_cb() function from main_PWM.py:
forward = 0
left = 0
back = 0
right = 0
# MICROS so every sec is 1000000 of micros, 1000 = 1kHz
frequency = 1000
period = 1000000//frequency
def set_PWM(status,value):
# Check incoming commands and write PWM
global duty
global forward
global left
global back
global right
# Get values for PWM
motor_direction = value[0]
range = value[1]
if range == 0: # Set duty to 0
duty = 0
else: # Set duty to period/3, period/2, or 1, backwards from original
duty = period//range
if motor_direction == 1: # Forward
forward = duty
left = 0
back = 0
right = 0
elif motor_direction == 2: # Left
forward = 0
left = duty
back = 0
right = 0
elif motor_direction == 3: # Back
forward = 0
left = 0
back = duty
right = 0
elif motor_direction == 4: # Right
forward = 0
left = 0
back = 0
right = duty
else: # Set all to 0
forward = 0
left = 0
back = 0
right = 0
pwm.write(forward_pin, period, forward, MICROS)
pwm.write(left_pin, period, left, MICROS)
pwm.write(back_pin, period, back, MICROS)
pwm.write(right_pin, period, right, MICROS)
To see the similarities/differences more clearly, here is a side-by-side comparison of the bodies of the functions. On the left is the Zerynth implementation and on the right is the main_PWM.py implementation:

Issues with Zerynth PWM
I was having some very strange issues with PWM activation when using Zerynth. I was running the same code as above, however it was activating more than one motor at once. When testing main_PWM.py, it was only activating multiple motors at once.
To get a better understanding of the issue, here is what was happening. For example, when I activate Motor 1, I can confirm via print statements that only the duty for one motor is being set at a time, and all others are 0. When I first set only the duty for Motor 1, this is the case. However, if I then set the duty for Motor 2, Motor 1 continues working and Motor 2 is activated, even though the duty for Motor 1 should be set to 0 (and I can confirm that it is being set to 0). When I set all motors to 0, they turn off in unison as expected. However, when I try to activate Motor 2 again, Motor 2 and Motor 1 turn on together again. It seems they are somehow tied together even though I can confirm that this portion of the code works in the original main_PWM.py file.
I concluded that the issue is derived from this portion of the code:
if motor_direction == 1: # Forward
forward = duty
left = 0
back = 0
right = 0
elif motor_direction == 2: # Left
# ... other options removed for brevity
pwm.write(forward_pin, period, forward, MICROS)
pwm.write(left_pin, period, left, MICROS)
pwm.write(back_pin, period, back, MICROS)
pwm.write(right_pin, period, right, MICROS)
When the PWM module is writing to the motors, they somehow get tied together in what I suspect to be some form of an overflow. I think this is due to the way that Zerynth abstracts the programming out a layer, so you are not directly interfacing with the board like in uPyCraft IDE. Something must get tied up or stored within this layer of abstraction that causes previously activated motors to turn on. I'm not sure what this "something" is, so this is just a hypothesis.
Determined to figure out this issue, I spent countless hours debugging the code to no avail. I posted on the Zerynth Community support page and a Zerynth team member was unable to help me as well. The Zerynth team member noted that they will be testing this bug and pushing bux fixes in future updates. So, I explored other options!
I returned back to uPyCraft IDE, so I will be documenting that in the next update!
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.