# I want understand the code about the interactions between instances of the Servo and PWM classes of robot\_hat with picarx

**URL:** https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004
**Category:** Robotic kit for Raspberry Pi
**Created:** [September 17, 2026, 4:01pm UTC](https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004 "2026-09-17T16:01:10Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![curiosity](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.sunfounder.com/curiosity/32/2615_2.png) [@curiosity](https://forum.sunfounder.com/u/curiosity)
#### Post date: [September 17, 2026, 4:01pm UTC](https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004/1 "2026-09-17T16:01:10Z")

</div>

I observed the traces when instantiating the Picarx class.  
To do this, I inserted “print” statements in a specific format.  
The logs are formatted as follows:

" {format } ::= {Num\_Line} {key} {level} {method name} { data} "

{Num\_Line} ::= num line off log, not num line off code Python  
{key} ::= “code” for using the Linux ‘grep’ function  
{level} ::= The length of the underlines depends on the depth of the method calls  
{method name} ::= PWM, I2C, ARR, PSC, SRVO, PICAR, etc  
{data} ::= Information Sought

Example

![image](https://canada1.discourse-cdn.com/flex029/uploads/sunfounder/original/2X/6/6a0d38b2ad0a504411794c2c82300a650cbebcb2.png)

By following the Python code for creating an instance of the Picarx class, the logs let you see what’s happening.  
I’m interested in the part where the servo motors are declared (not the motors themselves, not the ultrasonic part, etc.)

Let’s start by instantiating the Picarx class.

![image](https://canada1.discourse-cdn.com/flex029/uploads/sunfounder/original/2X/6/6a0d38b2ad0a504411794c2c82300a650cbebcb2.png)

- Line 0 to 1: Instantiation of the Picarx class for the “P0” servo motor
- Lines 2–3: Instantiation of the Servo class for the “P0” servo motor, which will instantiate the PWM class for the “P0” servo, which in turn will call its freq() method

 ![image](https://canada1.discourse-cdn.com/flex029/uploads/sunfounder/original/2X/c/cd139c613c7bae4022572fdf73fa8855bb416604.png)

- Line 4 : Creation of the “timer” class variable
- Lines 5 and … : Determining the address of the I2C port on bus 1 → 0x14 found

 ![image](https://canada1.discourse-cdn.com/flex029/uploads/sunfounder/original/2X/b/b246072ab2dc5abc5a2e429976287eb92c1e4a98.png)

- Lines 6 to 10 Call to the method self.freq( 50 )  
Calculation of the prescaler and arr values  
for the frequency self.\_freq == 50 Hz  
The freq() method calls the prescaler() method, i.e., PSC

 ![image](https://canada1.discourse-cdn.com/flex029/uploads/sunfounder/original/2X/5/54123df189f0718ac3563191ab4918dc9e8521cc.png)

- Lines 11 to 13 Call (PCS) the method self.prescaler( 1200 )
- Lines 14 to 16 For canal “P0” timer\_index === 0  
Therefore, timer[0][arr] === 1  
This will result in a rather surprising calculation for  
the variable self.\_freq
- Line 17 Frequency calculation: self.\_freq == 60000 Hz

That makes sense, since timer[0][arr] should be equal to 1200 as  
calculated previously, not one

- Line 18 … Storing the value of (prescaler - 1) = (1200 - 1) == 1199 == 0x4AF in memory location 0x40
- Line 19 to 20 End of methode prescaler()

_ **I have more data to provide, but I’m stuck because the editor won’t accept more than 5 documents linked to the text.** _

21 code\_\_\_\_\_\_\_FREQ:  
22 code\_\_\_\_\_\_\_\_\_\_\_ARR  
23 code\_\_\_\_\_\_\_\_\_\_\_ARR: -------- self.periode(arr=1200)  
24 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer\_index=0  
25 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer = [{‘arr’: 1200}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]  
26 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer[self.timer\_index][arr] = 1200  
27 code\_\_\_\_\_\_\_I2CW: \_i2c\_write(reg=0x44, value=0x4b0)  
code\_\_\_\_\_\_\_\_\_\_\_I2C-write( self, data=[68, 4, 176]==[0x44, 0x4, 0xb0,]  
28 code\_\_\_\_\_\_\_\_\_\_\_ARR: -------- self.periode( ) OUT  
29 code\_\_\_\_\_\_\_\_\_\_\_ARR  
30 code\_\_\_\_\_\_\_FREQ: -------- self.freq( ) OUT  
31 code\_\_\_\_\_\_\_FREQ  
32 code\_\_\_\_PWM: ---------- pwm. **init** OUT ( )  
33 code\_\_\_\_PWM

- Line 21 Return to the freq() method and call the period() method (ARR)
- Line 22 to 23 The calculations will be based on the value arr=1200
- Lines 24 to 26 For canal “P0” timer\_index === 0  
Therefore, timer[0][arr] === 1200  
This time, this value is consistent.
- Lines 27 … Then writes this value to memory address 0x44  
This method does not modify the variable self.\_freq
- Lines 28 to 31 Return to the freq() method, and end of the freq() method
- Lines 32 to 32 End of the PWM class instantiation for channel “P0”

\*At this point in the code, we return to the “ **init** ” method of the Servo class. The period(4095) method will be called.  
\*

34 code\_SRVO: call self.period(self.PERIOD = 4095)  
35 code\_\_\_\_\_\_\_\_\_\_\_ARR  
36 code\_\_\_\_\_\_\_\_\_\_\_ARR: -------- self.periode(arr=4095)  
37 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer\_index=0  
38 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer = [{‘arr’: 4095}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]  
39 code\_\_\_\_\_\_\_\_\_\_\_ARR: timer[self.timer\_index][arr] = 4095  
40 code\_\_\_\_\_\_\_I2CW: \_i2c\_write(reg=0x44, value=0xfff)  
code\_\_\_\_\_\_\_\_\_\_\_I2C-write( self, data=[68, 15, 255]==[0x44, 0xf, 0xff,]  
41 code\_\_\_\_\_\_\_\_\_\_\_ARR: -------- self.periode( ) OUT  
42 code\_\_\_\_\_\_\_\_\_\_\_ARR

- Lines 34 to 36 Call the “periode” method (ARR), which will update the “timer” variable of the PWM class.
- Lines 37 to 39 For canal “P0” timer\_index === 0  
Therefore, timer[0][arr] === 4095  
This time, this value is consistent.  
But all the calculations made during the instantiation phase of the PWM class will be discarded, as we will see.Surprising, isn’t it?
- Lines 40 … Then writes this value to memory address 0x44  
This method does not modify the variable self.\_freq
- Lines 41 to 42 Return to the _“ **init** ” method of the Servo class_

43 code\_SRVO: self.ClOCK=72000000.0, self.FREQ=50, self.PERIOD=4095  
44 code\_SRVO: call self.prescaler(prescaler = 351.64835164835165)  
45 code\_\_\_\_\_\_\_\_\_\_\_PSC  
46 code\_\_\_\_\_\_\_\_\_\_\_PSC: -------- self.prescaler( prescaler=351.64835164835165 )  
47 code\_\_\_\_\_\_\_\_\_\_\_PSC: self.\_prescaler = 352  
48 code\_\_\_\_\_\_\_\_\_\_\_PSC: timer\_index=0  
49 code\_\_\_\_\_\_\_\_\_\_\_PSC: timer = [{‘arr’: 4095}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}, {‘arr’: 1}]  
50 code\_\_\_\_\_\_\_\_\_\_\_PSC: timer[self.timer\_index][arr] = 4095  
51 code\_\_\_\_\_\_\_\_\_\_\_PSC: self.\_freq = 49.95004995004995 \<?\<?\<?\<?\<?\<?\<?\<?\<?\<?\<?\<? != 50  
52 code\_\_\_\_\_\_\_I2CW: \_i2c\_write(reg=0x40, value=0x15f)  
code\_\_\_\_\_\_\_\_\_\_\_I2C-write( self, data=[64, 1, 95]==[0x40, 0x1, 0x5f,]  
53 code\_\_\_\_\_\_\_\_\_\_\_PSC: -------- self.prescaler( ) OUT  
54 code\_\_\_\_\_\_\_\_\_\_\_PSC  
55 code\_SRVO:----------Servo. **init** () OUT  
56 code\_SRVO  
57 code\_\_\_\_\_PICAR: initialisation SERVO P1

- Lines 43 to 47 Using the three constants  
self.ClOCK=72000000  
self.FREQ=50,  
self.PERIOD=4095  
The prescaler calculation gives → prescaler = 351.64835164835165
- Lines 48 to 50 For canal “P0” timer\_index === 0  
Therefore, timer[0][arr] === 4095  
This time, this value is consistent.
- Line 51 Calculation of the value of the variable “\_freq” = 49.95…Hz.  
This value does not match 50 Hz, but that is normal since the value  
of the variable “\_prescaler” has been rounded.  
Everything is consistent.
- Lines 52 … Storing the value of (prescaler - 1) = (352 - 1) == 351 == 0x15F in memory location 0x40
- Lines 53 to 56 The Servo class has been instantiated for channel “P0”
- Line 57 The instantiation of the Picarx class continues by instantiating the Servo class for the “P1” channel.  
For “P1” chanel, The process will be the same as the previous one.  
There will be a new instance of the PWM class for “P1”, and everything  
that was surprising will once again be just as surprising to me.

**In summary:**

- Why does instantiating the PWM class perform calculations that will be ignored, and which, moreover, introduce an error because timer[self.timer\_index][arr] has not been initialised before the calculations of self.\_freq 50 Hz requested, 60KHz calculated.
- Why does the instantiation of the PWM class call the freq() method, rather than simply determining the active port on the I2C bus?  
Leaving it up to the Servo or Motor class instance to choose the optimal calculation methods:  
i.e self.period( ) or self.prescaler( ) or self.freq()

---

<div class="post-metadata">

### Author: ![SunFounder\_Moderator](https://avatars.discourse-cdn.com/v4/letter/s/34f0e0/32.png) [@SunFounder\_Moderator](https://forum.sunfounder.com/u/SunFounder_Moderator)
#### Post date: [September 18, 2026, 10:25am UTC](https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004/2 "2026-09-18T10:25:47Z")

</div>

We reviewed the initialization flow you described. Your observation is correct: PWM.init() calls freq(50), which temporarily calculates \_freq using the initial ARR value before period() updates it. The value is recalculated afterward, and Servo.init() subsequently replaces the PWM timer configuration with PERIOD = 4095 and the corresponding prescaler. Therefore, the temporary 60000 Hz value is not the final servo PWM frequency.

However, your point about the redundant initialization and class design is valid, and we will review whether this initialization sequence can be improved.

---

<div class="post-metadata">

### Author: ![curiosity](https://yyz1.discourse-cdn.com/flex029/user_avatar/forum.sunfounder.com/curiosity/32/2615_2.png) [@curiosity](https://forum.sunfounder.com/u/curiosity)
#### Post date: [September 18, 2026, 2:01pm UTC](https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004/3 "2026-09-18T14:01:45Z")

</div>

Thanks for your reply.  
I’m going to keep exploring the code for this little robot. I’ve learned a lot about how to use servo motors.  
I’m 72 years old, and I realize that today’s teenagers are incredibly lucky to have access to such an extraordinary “toy” for learning the basics of electronics, microcomputing, programming, and mechanics.  
For example, I saw that you programmed an “electric differential” for the rear axle to simulate a mechanical differential, based on the orientation of the front wheels. Great idea.  
Alright! I’m going back to it!

---

<div class="post-metadata">

### Author: ![SunFounder\_Moderator](https://avatars.discourse-cdn.com/v4/letter/s/34f0e0/32.png) [@SunFounder\_Moderator](https://forum.sunfounder.com/u/SunFounder_Moderator)
#### Post date: [September 20, 2026, 9:20am UTC](https://forum.sunfounder.com/t/i-want-understand-the-code-about-the-interactions-between-instances-of-the-servo-and-pwm-classes-of-robot-hat-with-picarx/5004/4 "2026-09-20T09:20:05Z")

</div>

Thank you very much for your kind words — you are remarkable too!

Diving into the code at 72 and following it all the way down to the interaction between the Servo and PWM classes is truly admirable, and your curiosity really inspires us. You are right that today’s teenagers are lucky to have such an extraordinary tool for learning the basics of electronics, microcomputing, programming, and mechanics — and someone who keeps that same enthusiasm for learning at any age is just as inspiring to us.

We are glad this little robot can keep you company on your journey of exploration, and we look forward to you discovering many more interesting details. Have fun!
