Embedded system simulations using tessim

 Tessim is an in-development software project to enable scalable and efficient simulations of embedded systems. The aim of this tool is to allow  hardware engineers, embedded software engineers and systems engineers to work in the same environment while designing and developing a product. 


In this post I will give an example of how this can be used. Currently the software is in the form of a shared library file that can be used with python. The python library file, (python_cli_interface.py) acts as a way to call the functions and objects of the library, thus acting as a user interface, that can be used in the python command line. In this blog I will demonstrate how this library can be used by taking an example of a motor  being controller by an atmega328p. 


to start open the python3 cli : 

:~$ python3

Python 3.8.5 (default, May 27 2021, 13:30:53) 

[GCC 9.3.0] on linux

Type "help", "copyright", "credits" or "license" for more information.

>>> 

>>> 


now import the library :

>>>import python_cli_commands as cli


Creating a component 

Next create the required components, to start with let's create a motor : 


>>>mt = cli.dcMotor(0.05,0.05 , 0.5, 0.0015, 0.00025, 0.001)

This command will create a simple PMDC motor with the given parameters. The general syntax of the function is : 

dcMotor(kt, ke, r, l, jm, bm) 

where the parameters mean the following : 

  • kt  torque constant
  • ke electrical constant
  • r : armature resistance
  • l : motor inductance
  • jm : motor inertia
  • bm : friction coefficient. 
The above parameters are used in a mathematical model of a motor described here : modelling of a DC motor


Adding and connecting nodes

Now that we have created a motor with given parameters. We need to connect it to "nodes". These nodes can be used to provide input voltages and connect other components. 

in order to create nodes use : 

>>>nodes = cli.createNodes(2)

the above command will create two nodes and assign them to the pointer nodes (python does not have pointers but the shared library returns a pointer, it will be stored as an integer). The motor that we created earlier has two node pointers , which can be assigned to the nodes that were just created. This can be done by the following commands : 

>>>mt.setNodes(0, 1)

This will connect the motor to nodes 0 and 1. 

Simulating the Motor

In order to simulate the motor we need to apply a certain voltage to the nodes of the motor. This can achieved by : 

>>>cli.putValue(0,12)

This command will put a value of 12 V on node 0. In order to simulate the motor now we will use the following command :  

>>>cli.execAll(0.0025, 4)

The above command will simulate the entire system (right now there is only motor in the system but as we will see further, there can be multiple components) together with for 4 seconds with a time division of 2.5ms.  


In order to get the final speed of the motor use : 

>>>mt.getSpeed()

This should output 166.66666666666646 on the terminal (for the given parameters). this is the motor speed at the end of the simulation. In order to get  the time evolution of speed the object variable speeds inside the motor object can be used. In order to plot the speed as a function of time we can use the matplotlib library in python.  

   >>>plt.plot(mt.time, mt.speeds 

 >>>plt.xlabel("time (s)") 

>>>plt.ylabel("speed (rad/s)") 

>>>plt.show() 

this should plot the speed of the motor as a function of time.  

 



No to this simulation environment let's add a motor driver and a micro-controller.  


Adding a micro-controller 

In order to add a micro-controller we use the mcu object in the module. : 

atmega = cli.mcu(32, cli.architecture_family.avr, cli.avr_mcu.atmega328p, b'compiled/single_motor_control.hex')
The general syntax o this command is : 

        >>>cli.mcu(num_of_pins, architecture_family, part_num, path_to_prog)

This command will create an instance of atmega328p micro-controller (used in the Arduino board) which has 32 pins. The final argument is the path to the hex file for the controller program. In this example a simple program was used which reads the pin12 of the IC (pin PB0) and sets a PWM signal(on pin 10) if it reads high, thus driving the motor. IF the pin reads low the PWM duty cycle is made zero, stopping the motor.   

#define F_CPU 1000000UL

#include <xc.h>
#include <avr/io.h>
#include <util/delay.h>


int main(){
DDRD = 0xFF; //PWM out
DDRB = 0x00; //input port

TCCR0A = 0x83; //fast PWM mode for counter B
TCCR0B = 0x02; // OC0B is disconnected
while(1){
if(PINB & 1 << PB0){
OCR0A = 0x8F; //pwm with duty cycle 0x8f/0xff
}
else{
OCR0A = 0x00; //motor should stop if button is not pressed
}

}
return 0;
}

The above code was compiled into a hex file using the xc8 compiler. 

We'll also need two motor drivers in order to build to drive the motor. 

    >>>driver1 = cli.generic_motor_drivers(2.5, 2.5)
  >>>driver2 = cli.generic_motor_drivers(2.5, 2.5)

The two parameters of the drivers used are low threshold and high threshold. (if the input is below low threshold value the driver outputs 0v if it is above high threshold, it outputs the supply voltage. If it is in middle then it stays where it is). In this example I have put both the values to 2.5 volts. 

A motor (the motor is created in the same manner as before) 

    >>>mt = cli.dcMotor(0.05,0.05 , 0.5, 0.0015, 0.00025, 0.001)

 

Connecting the components via nodes. 

Now that we have all the required components we need to connect them. The connections are described in the figure below : 


In total we will need 36 nodes (32 for Atmega itself). How each of these nodes are connected is described in the code below : 


#the drivers are connedted as follows :
# connectNodes(Vcc, vin, Vout, gnd)
# In this example node 32 proivides 15v VCC to both the drivers
# Input signal to driver 1 and driver 2 is given by pin 10 and 9 of the
# controller respectively
# (which are OC0A and OC0B pins respectively)
# Output of each driver is connected to node 34 and 33 which are connected
#to the motor
driver1.connectNodes(32,9,34,35)
driver2.connectNodes(32, 8, 33, 35)
#connect motor to the output of the driver
mt.setNodes(34, 33)
#nodes 0 to 31 (first 32 nodes) will be connected to the
#32 pins of the controller
atmega.connectNodes(nodes)  
 

Now we assign voltages to the nodes as needed : 


#nodes are numberd from 0 to 35. The first 32 ndes will be connected to the mcu.
#Thus node 0 is connected to pin 1 of mcu node `1 to pin `
cli.putValue(32, 15) #15v power supply to drivers
cli.putValue(35, 0) #ground pin of motor drivers
cli.putValue(3,5) #5v power supply to the micro-controller
cli.putValue(11, 5) #node 11 is pin 12, to
#which the buitton is attatched

# giving a value of 5v means that the button is pressed 


In the start we have assumed that the button is pressed. we simulate This for first 0.5 seconds

    >>>cli.execAll(0.00000025, 0.5)

Now we release the input button (which means the voltage on node 11  or pin 12 will go to zero). 

    >>>cli.putValue(11,0) #button is released

    >>>cli.execAll(0.00000025, 0.5)


Now we apply the button pressed again.

   >>>cli.putValue(11, 5) #pressed again
    >>>cli.execAll(0.00000025, 0.5)

Now if we plot the the speed of the motor as a function of time we see : 



As is expected when the pin is high (simulating a button pressed condition) the speed rises and when it is released the speed drops to zero. 

Comments

Popular posts from this blog

Simulating a motor in ngspice

Counting pulses in Arduino (without interrupts or loops)