هوشمند سازی ربات شاسی دو چرخ- بخش دو

مقدمه

در بخش اول  آماده‌سازی مکانیکی ربات و نحوه سیم بندی و مونتاژ ربات دو چرخ ارائه شد که در  این لینک قابل مشاهده است. در ادامه کار  نحوه راه‌اندازی و بخش نرم‌افزار میکرو پایتون ربات بررسی و ارائه می شود. 

فهرست مطالب

2W_ME_34

فهرست

  • مقدمه
  • راه‌اندازی نرم‌افزاری
  • معرفی کد و توضیحات
    • برنامه اصلی main
    • زیر تابع تعیین فاصله Distance
    • زیر تابع راه‌اندازی MDrive
    • زیر تابع راه‌اندازی ULS
    • زیر تابع راه‌اندازی OLED
    • زیر تابع راه‌اندازی  RGB_LED
    • برنامه اندرویدی کنترل ربات 
    • دانلود برنامه ها
  • تست و عملکرد
  • بهبود های سخت افزاری
  • بهبودهای نرم افزاری
  • جمع‌بندی

 

راه اندازی نرم افزاری

در این پروژه از ماژول رزبری پیکو استفاده شده است که عملاٌ ماژول پردازشگر و کنترل GPIO است. یکی از مهمترین زبانهای پیشنهادی برای رزبری پیکو، میکروپایتون است که توزیعی  از پایتون3 می باشد. برای کار با میکروپایتون نرم افزارهای مختلفی قابل ارائه است اما Thonny IDE هم ساده و هم به‌طور رسمی معرفی شده است. لذا ما هم در این نوشته از این IDE استفاده می کنیم. براحتی می توانید آنرا از لینک رسمی دانلود نمائید. مجموعه برنامه های استفاده شده برای ربات در این مسیر قرار دارد و برای استفاده از آنها همگی در مسیر روت ماژول پیکو دانلود نمائید.

معرفی کد و توضیحات برنامه ها:​

حال به بررسی ساختار کدهای برنامه ربات دو چرخ می پردازیم. ساختار کد این ربات شامل 3 لایه برنامه و درایور می باشد که در لایه اول  یک برنامه اصلی قرار دارد که از همانطور که از اسمش مشخص است وظیفه کنترل و هدایت ربات را برعهده دارد و برای این کار از توابع و درایورهای لایه 2 و 3 بهره می گیرد. در لایه دوم  5 زیر برنامه با شکل تابع  با نامهای  Distance، MDrive, OLED، ULS و RGB_LED قرار دارند که در برنامه اصلی به فراخور نیاز فراخوانی می شوند. در لایه سوم برنامه های درایور قرار دارند و ماژولهای RGB LED, OLED, Ultrasonic Sensor  را کنترل می کنند.

برنامه اصلی main:

همانطور که اشاره شده برنامه اصلی main را در لایه اول قرار گرفته است و توابع لایه 2 و گاهی 3 را برای هدایت ربات فراخوانی می کند. در ادامه به بررسی خطوط مهم این برنامه می پردازیم.

  •  در خطوط 10 تا 18 ماژولها و زیر برنامه های مورد نیاز  را مشخص و وارد برنامه اصلی می کند. در مورد زیر برنامه ها بعد از برنامه اصلی توضیح می دهیم.
  • در خطوط 22 تا 26 مطابق مارکاژ برد پرومیک رزبری پیکو ، ارتباط سریال UART(برای ماژول بلوتوث)، کلید، و بازر را تعریف می کنیم.
  • در خطوط 28 تا 34 متغیرهای زیر را تعریف می کنیم که در برنامه و زیربرنامه ها استفاده می شود.
    • dist: متغیر میزان فاصله تا مانع که توسط سنسور اولتراسونیک تغییر می کند.
    • run: متغیری از جنس بولین که True بودن آن یکی از شروط  اجازه شروع حرکت ربات می باشد.
    • Ostacle: این متغیر از نوع بولین می باشد و True شدنش، نشان دهنده وجود مانع می باشد.
    • Move_State: متغیری از جنس رشته که آخرین وضعیت حرکت ربات را نگهداری می کند.
    • Control: این متغیر دارای دو مقدار Auto و Manual می باشد که بترتیب نوع حرکت ربات را در دو مد دستی(کنترل با نرم‌افزار) و اتوماتیک را معین می کند.
    • Obstacle_Counnter: شمارنده ای برای تعیین میزان موانع که در تابع مربوط  بعنوان شرط و آستانه استفاده می شود.در برنامه اولیه 200 مانع بعنوان پیش فرض در نظر گرفته شده است. شما براساس منطق و شرایط کاری آنرا تنظیم نمائید.
    • speed: در حالت کنترل اتوماتیک به‌طور ثابت مقدار 50 درصد دور نامی موتور  استفاده می شود و در حالت دستی از طریق نرم‌افزار مقدار دهی می شود و بدیهی است که مقدار بیشینه 100 دارد.
  • خطوط 38 تا 51 تابع کنترل وقفه از طریق کلید GPIO15 را برعهده دارد و عملا با فشردن این کلید ربات روشن یا متوقف می شود.
  • خطوط 55 تا 76 تابع وضعیت ربات را در نمایشگر Oled و تابع پرینت مشخص می کند.
  • خطوط 80 و 81 با استفاده از تعریف یک تایمر تابع وضعیت فرآخوانی و بروزآوری می شود.
  • خطوط 84 و 88 برای فراخوانی تابع Setup و خوانش فاصله استفاده شده است.
  • حلقه اصلی برنامه در خطوط 90 تا 139 برای دو حالت کنترل دستی و اتوماتیک نوشته شده است.
    • خطوط 92 تا 102 نوع کنترل و سرعت را با خوانش از ماژول بلوتوث و نرم‌افزار اندرویدی مشخص می کند.
    • خطوط 104 تا 124، 5 حرکت اصلی جلو، عقب، گردش راست و چپ و نهایتا توقف را از نرم‌افزار دریافت می کند.
    • خطوط 127 تا 139 در حالت اتوماتیک حرکت را  مشخص می کند و در صورت وجود مانع، تابع عبور از مانع OBST را از زیر برنامه MDrive فراخوانی می کند.
				
					# Main Function
######################################################################################################
# This Program is written by Giga Pardaz PARS
# PICO ROBOT with Mohandesika Two Wheel Robot CHasis
# CRR-PICO VER 1.5
# Universal Interface VER1.0
# MDRV DC Motor Drive VER1.1
# Esfand 1401
######################################################################################################

from machine import Pin, I2C, PWM, Timer , UART
import time
from utime import sleep
import ssd1306
from ssd1306 import SSD1306_I2C
import MDrive
import RGB_LED
import Distance
import OLED

######################################################################################################

uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
KEY = machine.Pin(15, machine.Pin.IN)
Interrupt=Pin(15,Pin.IN)   # setting GPIO15 KEY_Interrupt as input
Buzzer = PWM(Pin(11))
Buzzer.freq(2000)

dist = 0
run = False
Obstacle = True
Move_State = 'Stop'
Control = 'Auto'
Obstacle_Counnter = 0 
speed = 50

######################################################################################################

def handle_interrupt(Pin):           
    
    global run
    if Control == 'Auto':
        
        if run == False:
            run = True
            
        else:
            run = False
            
    return

Interrupt.irq(trigger=Pin.IRQ_RISING, handler=handle_interrupt)

######################################################################################################

def State_Info():
    global speed, Move_State

    if Control == 'Auto':
        if  Move_State != 'stop_motor':
            OLED.Display(0,'PICO ROBO: Auto',str(Move_State) + ' SP:'+ str(speed) )
            print('PICO ROBO: Auto',Move_State, 'Speed:',speed)
        
        else:    
            OLED.Display(0,'PICO ROBO: Auto',str(Move_State) + ' SP:'+'0')
            print('PICO ROBO: Auto',Move_State, 'Speed:',' 0')
        
    if Control == 'Manual':
        if Move_State != 'stop_motor':
            OLED.Display(0,'PICO ROBO: Manual',str(Move_State) + ' SP:'+ str(speed))
            print('PICO ROBO: Manual',Move_State, 'Speed:',speed)
        
        else:    
            OLED.Display(0,'PICO ROBO: Auto',str(Move_State) + ' SP:'+'0')
            print('PICO ROBO: Auto',Move_State, 'Speed:',' 0')
        
    return

######################################################################################################

timer1=Timer(-1)
timer1.init(period=500, mode=Timer.PERIODIC,callback=lambda t: State_Info())

######################################################################################################
MDrive.setup()
sleep(.5)
RGB_LED.fill('Stop')
[dist, Obstacle]= Distance.dist_cm()
print('setup done.','Distance:', dist, 'cm')

while(True):
    
    if uart.any() > 0:
        data = uart.read()
        print(data)
        
        if "Auto" in data:
            Control ="Auto"
            print("Auto")
                
        if "Manual" in data:
            Control ="Manual"
            print("Manual")
            
    if Control == 'Manual':
        try:
            if (int(data)29):
                speed = int(data)
        except:
             pass
            
        if "forward" in data:
            Move_State = MDrive.forward(speed)

        if "backward" in data:
            Move_State = MDrive.backward(speed)
        
        if "left" in data:
            Move_State = MDrive.turn_left()
        
        if "right" in data:
            Move_State = MDrive.turn_right()                

        if "sstop" in data:
            Move_State = MDrive.stop_motor()
                 

    if Control == 'Auto':

            if run == True:                
                [dist,Obstacle] = Distance.dist_cm()
                
                if (Obstacle == False):                    
                    Move_State = MDrive.forward(speed)
                    
                else:                    
                    [Obstacle, Obstacle_Counnter] = MDrive.OBST(Obstacle, Obstacle_Counnter)

            else:                
                Move_State = MDrive.stop_motor()





				
			

زیر تابع تعیین فاصله Distance:

این برنامه با هدف تعیین فاصله ربات تا مانع نوشته شده است و با فراخوانی درایور سنسور التراسونیک HC SR04 فاصله را به سانتیمتر محاسبه و به لایه بالاتر در برنامه اصلی و MDrive برمی گرداند.

  • 10 تا 13: ماژولها و درایور سنسور HC SR04 فرخوانی می شود
  • 15 تا 16: با توجه به سیم بندی و استفاده از کانکتور 2mm Grove با مارکاژ  J4 روی برد تعریف پایه های سنسور انجام می شود. در ادامه از LED روی  ماژول پیکو با پایه 25 استفاده شده است.
  • 20 تا 36: تابع اصلی با درایور سنسور ارتباط می گیرد و فاصله تا مانع را بررسی می کند و اگر فاصله با مانع کمتر از 15 سانتیمتر باشد با متغیر Obstacle اعلام و LED روی ماژول پیکو را روشن می کند.
				
					# Distance Function
######################################################################################################
# This Program is written by Giga Pardaz PARS
# PICO ROBOT with Mohandesika Two Wheel Robot CHasis
# CRR-PICO VER 1.5
# Universal Interface VER1.0
# MDRV DC Motor Drive VER1.1
# Esfand 1401
######################################################################################################

from machine import Pin
from hcsr04 import HCSR04
import time
from utime import sleep

sensor = HCSR04(trigger_pin=26, echo_pin=2, echo_timeout_us=10000)
LED = Pin(25,Pin.OUT)

######################################################################################################

def dist_cm():
    try:
        global dist, Obstacle
        dist = sensor.distance_cm()
       
        time.sleep_us(50)
        if dist > 15 :
            Obstacle = False
            LED.value(1)
        else:
            Obstacle = True
            LED.value(0)
            
    except OSError as ex:
        print('ERROR getting distance:', ex)

    return dist, Obstacle

######################################################################################################


				
			

زیر تابع راه اندازی MDrive:

زیر تابع مهم ربات راه انداز موتورها هست که حرکتهای جلو، عقب، گردش به راست، گردش به چپ و توقف و البته تابع عبور از مانع در  آن قرار دارد. در ادامه به بررسی دقیقتر خطوط مهم می پردازیم.

  • 10 تا 16: ماژولها و زیر تابع های مورد نیاز را فراخوانی می شود
  • 18 تا 20: باس I2C و بازر تعریف می شود. دقت نمائید که ماژول پرومیک درایور DC موتور با باس I2C و GPIO کنترل می شود
  • 23تا 37: تعاریف بایتی برای درایور موتورهای DC آرمیچر رباتها با توجه به مارکاژ های ماژول پرومیک انجام می شود. این متغیرها از طریق باس I2C برای قطعه PCA9538 ارسال می شود.
  • 39 تا 44: برای درایو سروو موتور حالتهای گردش 0، 90 و 180 درجه برای چرخش سنسور التراسونیک می باشد.
  • 48 تا 57: تابع حرکت جلو(Forward) با ارسال ثابت مربوط به PCA9538 و تنظیم میزان Duty Cycle با توجه به میزان speed انجام می شود. نهایتا RGB LED بحالت سبز دوتایی روشن می شود.
  • 61 تا 70:تابع حرکت به عقب(Backward) با ارسال ثابت مربوط به PCA9538 و تنظیم میزان Duty Cycle با توجه به میزان speed انجام می شود. نهایتا RGB LED بحالت زرد دوتایی روشن می شود.
  • 74 تا 84: تابع گردش به راست(turn_right) با ارسال ثابت مربوط به PCA9538 و تنظیم میزان Duty Cycle با توجه به میزان speed ثابت 30 درصد که چرخش نرم و کامل انجام شود. میزان تاخیر براساس سرعت گردش برای چرخش 90 درجه به سمت راست  در سطوح عادی مانند سرامیک و میز می باشد لذا اگر در محیط های دیگر نیاز است زمان تاخیر و میزان سرعت تنظیم شوند تا گردش کامل و صحیح انجام شود. نهایتا RGB LED بحالت سبز تکی RGB1 روشن می شود.
  • 88 تا 98: تابع گردش به چپ(turn_left) با ارسال ثابت مربوط به PCA9538 و تنظیم میزان Duty Cycle با توجه به میزان speed ثابت 30 درصد که چرخش نرم و کامل انجام شود.  میزان تاخیر براساس سرعت گردش برای چرخش 90 درجه به سمت چپ در سطوح عادی مانند سرامیک و میز می باشد لذا اگر در محیط های دیگر نیاز است زمان تاخیر و میزان سرعت تنظیم شوند تا گردش کامل و صحیح انجام شود.نهایتا RGB LED بحالت سبز تکی RGB2 روشن می شود.
  • 102 تا 112: تابع گردش به عقب(turn_back) با ارسال ثابت مربوط به PCA9538 و تنظیم میزان Duty Cycle با توجه به میزان speed ثابت 30 درصد که چرخش نرم و کامل انجام شود. میزان تاخیر براساس سرعت گردش برای چرخش 180 درجه به سمت عقب در سطوح عادی مانند سرامیک و میز می باشد لذا اگر در محیط های دیگر نیاز است زمان تاخیر و میزان سرعت تنظیم شوند تا گردش کامل و صحیح انجام شود. نهایتا RGB LED بحالت آبی دوتایی RGB1,2 روشن می شوند.
  • 116 تا 122:تابع توقف کامل(stop_motor) با ارسال ثابت مربوط به PCA9538  انجام می شود. نهایتا RGB LED بحالت قرمز دوتایی RGB1,2 روشن می شود.
  • 126 تا 137:تابع Setup که برای شروع کار ابتدا توقف انجام می شود و بازر لحظه ای روشن می شود و سنسور التراسونیک به حالت روبه جلو قرار می گیرد.
  • 141 تا 178: تابع عبور از مانع OBST تعریف می شود. در تابع اصلی متغیر Obstacle_Counnter تعریف شده است. براساس آستانه 200 عدد(شما براساس سناریو خودتان تنظیم نمائید) برخود با مانع، ابتدا موتورها متوقف می شوند و سنسور التراسونیک به سمت راست می چرخد دوباره فاصله سنجیده می شود اگر مانع تشخیص نشود ربات به راست می چرخد، اما اگر مانع باشد سنسور التراسونیک به سمت چپ می چرخد و مانع بررسی می شود و ربات به چپ می چرخدو حرکت رو به جلو مجدد ادامه می یابد. اگر در هر دو سوی راست و چپ مانع تشخیص داده شود ربات به‌طور کامل 180 درجه به عقب برمی گردد و دوباره مانع بررسی و اگر مانعی نبود نهایتا حرکت ادامه می یابد. فعلا محدودیت 200 مانع برای تابع درنظر گرفته شده است که در بخش بهبودهای نرم افزاری هم اشاره شده که با ترکیب الگوریتمهای مختلف می توان حالتهای جذاب و البته عملیاتی براساس موقعیت و نوع مانع تعیین نمود. 
				
					# MDrive Function
######################################################################################################
# This Program is written by Giga Pardaz PARS
# PICO ROBOT with Mohandesika Two Wheel Robot CHasis
# CRR-PICO VER 1.5
# Universal Interface VER1.0
# MDRV DC Motor Drive VER1.1
# Esfand 1401
######################################################################################################

from machine import Pin, I2C, PWM, Timer
import time
from utime import sleep
import ULS
import Distance
import OLED
import RGB_LED

i2c = I2C(0, sda=Pin(16), scl=Pin(17),freq = 300000)
Buzzer = PWM(Pin(11))
Buzzer.freq(2000)
######################################################################################################

PCA9538_I2C_ADDRESS             = 0x73
PCA9538_CMD_Output              = b'\x00'
Stop_All_Motor                  = b'\x00'      
Forward_All_Motor               = b'\x15'
Backwrad_All_Motor              = b'\x1A'
Turn_Left                      = b'\x16'
Turn_Right                       = b'\x19'
pca9538_IN_REG  = const(0x00) #Input register
pca9538_OUT_REG = const(0x01) #Output register
pca9538_POL_REG = const(0x02) #Polarity inversion register (1=data inverted)
pca9538_DIR_REG = const(0x03) #Config register (0=output, 1=input)
pwma = PWM(Pin(20))
pwmb = PWM(Pin(21))
pwma.freq(30000)
pwmb.freq(30000)

pwm_servo = PWM(Pin(5))
pwm_servo.freq(50)
ultrasonic_dir_forward = 5000
ultrasonic_dir_right = 1700
ultrasonic_dir_left = 8000
last_dir = ultrasonic_dir_forward

######################################################################################################

def forward(speed):
    
    global Move_State
    Move_State = 'Forward'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Forward_All_Motor)
    duty_16 = int((speed*60000)/100)
    pwmb.duty_u16(duty_16)
    pwma.duty_u16(duty_16)  
    RGB_LED.fill('Forward')
    return Move_State

######################################################################################################

def backward(speed):
    
    global Move_State
    Move_State = 'Backward'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Backwrad_All_Motor )
    duty_16 = int((speed*65536)/100) 
    pwmb.duty_u16(duty_16)
    pwma.duty_u16(duty_16)
    RGB_LED.fill('Backward')
    return Move_State

######################################################################################################

def turn_right():
    
    speed = 30
    global Move_State
    Move_State = 'Turn_Right'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Turn_Right )
    duty_16 = int((speed*65536)/100) 
    pwmb.duty_u16(duty_16)    
    RGB_LED.fill('Right')
    sleep(.8)
    return Move_State

######################################################################################################

def turn_left():
    
    speed = 30
    global Move_State
    Move_State = 'Turn_Left'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Turn_Left )
    duty_16 = int((speed*65536)/100) 
    pwmb.duty_u16(duty_16)
    RGB_LED.fill('Left')
    sleep(.8)
    return Move_State

######################################################################################################

def turn_back():
    
    speed = 30
    global Move_State
    Move_State = 'Turn_Back'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Turn_Left )
    duty_16 = int((speed*65536)/100) 
    pwmb.duty_u16(duty_16)  
    RGB_LED.fill('turn_back')
    sleep(1.6)
    return Move_State

######################################################################################################

def stop_motor():
    
    global Move_State
    Move_State = 'Stop'
    i2c.writeto_mem(PCA9538_I2C_ADDRESS, pca9538_OUT_REG , Stop_All_Motor )
    RGB_LED.fill('Normal')
    return Move_State

######################################################################################################

def setup():
    
    i2c.writeto_mem(PCA9538_I2C_ADDRESS , pca9538_DIR_REG , PCA9538_CMD_Output)         
    i2c.writeto_mem(PCA9538_I2C_ADDRESS , pca9538_OUT_REG , Stop_All_Motor)
    ULS.direct(ultrasonic_dir_forward)
    RGB_LED.fill('Normal'); print('Setup Done')
    Buzzer.duty_u16(60000)
    sleep(.2)
    Buzzer.duty_u16(0)
    time.sleep_us(5)
    
    return

######################################################################################################

def OBST(a,b):

    global Obstacle,Obstacle_Counnter
    Obstacle = a ;    Obstacle_Counnter = b
    
    if Obstacle_Counnter < 200:        
        Obstacle_Counnter = Obstacle_Counnter + 1
        print('Obstacle_Counnter:',Obstacle_Counnter)
        RGB_LED.fill('Stop')
        OLED.Display(0,'Obstacle','Off')
        sleep(.1)
        stop_motor()
        ULS.direct(ultrasonic_dir_right)
        [dist, Obstacle] = Distance.dist_cm()

        if (Obstacle == False):            
            Move_State = turn_right()           
            ULS.direct(ultrasonic_dir_forward)
        
        else:            
            ULS.direct(ultrasonic_dir_left)
            sleep(.1)
            [dist, Obstacle] = Distance.dist_cm()
            
            if(Obstacle== False):                
                Move_State = turn_left()
                ULS.direct(ultrasonic_dir_forward)
    
            else:                
                Move_State = turn_back()
                ULS.direct(ultrasonic_dir_forward)
                sleep(.2)
                [dist, Obstacle] = Distance.dist_cm()
                   
    else:
        Move_State = motor_off()
        
    return Obstacle, Obstacle_Counnter

######################################################################################################


				
			

زیرتابع راهاندازی ULS:

با توجه به این تابع سروو موتور SG-90 سنسور التراسونیک HC SR04 را بترتیب به سمت چپ، راست و حالت رو به جلو می چرخاند. ترتیب کار بسیار ساده است و متغیر مربوطه از تایع MDrive به این تابع ارسال می شود. در نهایت آخرین وضعیت زاویه چرخش سنسور التراسونیک به تابع وضعیت و MDrive ارسال می شود.

    				
    					# ULS Function
    ######################################################################################################
    # This Program is written by Giga Pardaz PARS
    # PICO ROBOT with Mohandesika Two Wheel Robot CHasis
    # CRR-PICO VER 1.5
    # Universal Interface VER1.0
    # MDRV DC Motor Drive VER1.1
    # Esfand 1401
    ######################################################################################################
    from machine import Pin,PWM
    from utime import sleep
    
    ######################################################################################################
    
    def direct (position):
        pwm_servo = PWM(Pin(5))
        pwm_servo.freq(50)
        global last_dir
        pwm_servo.duty_u16(position)
        sleep(0.1)
        last_dir = position
        return last_dir
    
    ######################################################################################################
    
    
    				
    			

    زیر تابع راه اندازی OLED:

    برای نمایش وضعیت ربات از یک نمایشگر OLED با سایز 132×32 استفاده می شود. در این نمایشگر 2 خط وضعیت ربات نمایش داده می شود.
    				
    					# OLED Display Function
    ######################################################################################################
    # This Program is written by Giga Pardaz PARS
    # PICO ROBOT with Mohandesika Two Wheel Robot CHasis
    # CRR-PICO VER 1.5
    # Universal Interface VER1.0
    # MDRV DC Motor Drive VER1.1
    # Esfand 1401
    ######################################################################################################
    from machine import Pin, I2C, Timer
    import ssd1306
    from ssd1306 import SSD1306_I2C
    
    i2c = I2C(0, sda=Pin(16), scl=Pin(17),freq = 300000)
    display = ssd1306.SSD1306_I2C(128, 32, i2c)
    
    ######################################################################################################
    #  OLED 32x128 Display Setting
    pix_res_x  = 128 # SSD1306 horizontal resolution
    pix_res_y = 32   # SSD1306 vertical resolution
    oled = SSD1306_I2C(pix_res_x, pix_res_y, i2c) # oled controller
    oled.fill(0) # clear the OLED
    start_x = 0 # start point for text in x-dir
    start_y = 2 # start point for text in y-dir
    lineskip = 20 # space between text in y-dir
    ######################################################################################################
    
    def Display(a,b,c):
        global Control
        
        if a == 0:
            display.fill(0)
            
        if b :
            display.text(str(b),0,10,1)
            
        if c: 
            display.text(str(c),0,24,1)
        
        display.show()
        
        return
    
    				
    			

    زیر تابع راه اندازی RGB_LED:

    این تابع با کمک درایور RGB LED های سری WS28X حالتهای مختلف Forward, Backward, Turn_Right, Turn_Left، Stop،Off, Normal و Error تعریف می شود و RGB LED ها متناظر با وضعیت حرکت ربات روشن و تغییر می کنند.

    				
    					# RGB_LED Function
    ######################################################################################################
    # This Program is written by Giga Pardaz PARS
    # PICO ROBOT with Mohandesika Two Wheel Robot CHasis
    # CRR-PICO VER 1.5
    # Universal Interface VER1.0
    # MDRV DC Motor Drive VER1.1
    # Esfand 1401
    ######################################################################################################
    from neopixel2 import Neopixel 
    from utime import sleep
    
    numpix = 2
    pixels = Neopixel(numpix, 0, 14, "GRB")
    yellow = (255, 100, 0)
    orange = (255, 50, 0)
    green = (0, 255, 0)
    blue = (0, 0, 255)
    red = (255, 0, 0)
    black = (0,0,0)
    white = (255,255,255)
    COLORS = (white,red, yellow, green, blue, white,black)
    color0 = red
    pixels.brightness(25)
    
    ######################################################################################################
    
    def fill(color):
        pixels.brightness(25)
    
        if color == 'Forward':
            pixels.set_pixel(0, green)
            pixels.set_pixel(1, green)
            pixels.show()
              
        if color == 'Right':
            pixels.set_pixel(0, green)
            pixels.set_pixel(1, black)
            pixels.show()
            
        if color == 'Left':
            pixels.set_pixel(0, black)
            pixels.set_pixel(1, green)
            pixels.show()
        
        if color == 'turn_back':
            pixels.set_pixel(0, blue)
            pixels.set_pixel(1, blue)
            pixels.show()
        
        if color == 'Backward':
            pixels.set_pixel(0, yellow)
            pixels.set_pixel(1, yellow)
            pixels.show()
        
        if color == 'Stop':
            pixels.set_pixel(0, red)
            pixels.set_pixel(1, red)
            pixels.show()
        
        if color == 'Off':
            pixels.set_pixel(0, black)
            pixels.set_pixel(1, black)
            pixels.show()
        
        if color == 'Error':
            pixels.brightness(100)
            pixels.set_pixel(0, red)
            pixels.set_pixel(1, red)
            pixels.show()
                
        if color == 'Normal':
            pixels.set_pixel(0, white)
            pixels.set_pixel(1, white)
            pixels.show()
                
        return
    
    
    				
    			

    برنامه اندرویدی کنترل ربات:

    برنامه اندرویدی برای حالت کنترل دستی ربات نوشته شده است و می توان با استفاده از موبایل و ارتباط بلوتوث ربات را کنترل کرد. روش طراحی این نرم‌افزار به‌صورت جداگانه در یک بلاگ دیگر معرفی خواهد شد. از این لینک می تواند اپلیکیشن اندرویدی را دانلود نمائید.

    در نظر داشته باشید که در حالت اتوماتیک ربات نیازی به این اپلیکشن ندارد و خودکار مانع را تشخیص و از آن عبور می کند.

    دانلود برنامه ها روی ماژول پیکو:

    برای شروع کار ابتدا تمام برنامه ها در مسیر روت ماژول پیکو دانلود نمائید. بعد از ریست ماژول برنامه main بطور پیش فرض طبق توصیف بالا اجرا می شود و با استفاده از نرم‌افزار اندرویدی و کلید KEY روی کریر بورد پرومیک ربات قابل کنترل در دو وضعیت دستی و اتوماتیک است.

    تست و عملکرد:

    در دو ویدئوی زیر حالتهای دستی ربات و اتوماتیک ربات تست شده اند. برای تست حالت اتوماتیک بهتر است که از دیوارهای به اندازه ارتفاع سنسور التراسونیک استفاده کنید. پیشنهاد می شود که ارتفاع دیوارها بیشتر از 15 سانتی‌متر باشد.

    بهبودهای سخت افزاری:

    • استفاده از ماژول پیکو W به‌جای ماژول معمولی پیکو و حذف ماژول بلوتوث، سبب کاهش سخت افزارها و سادگی ربات خواهد شد. البته تا زمان نگارش این نوشته هنوز  SDK  زبان میکروپایتون برای بخش بلوتوث ماژول PICO W ارائه نشده است. 
    • استفاده از ماژول شارژر  باتری 18650 و تغذیه کریر بورد با کابل تایپ C می تواند به سهولت و امکان شارژر ربات را ارائه نماید.
    • افزودن سنسور IR برای دنبال کردن خط
    • افزودن ماژول GPS پرومیک برای ثبت و رهگیری محل ربات

    بهبودهای نرم افزاری:

    • افزودن الگوریتم های مسیریابی و بهینه یافتن کوتاهترین مسیر
    • بهینه‌سازی الگوریتم تشخیص مانع و  ثبت محل موانع با استفاده از ماژول GPS پرومیک
    • با استفاده از ماژول GPS می توان انواع سناریوهای جذاب رهگیری را اجرا نمود و انواع مختلفی از کاربری ها را انجام داد.

    جمع بندی:

    با تکمیل ربات و بهبودهای اشاره شده بنظر داشتن رباتهای با ابعاد مناسب و گاها کوچکتر و حذف دردسرهای سیم بندی و سوراخ کاری های اضافه می توان تمرکز را بر کدنویسی و بهینه‌سازی الگوریتم های حرکتی و مسیریابی گذاشت و لذا نتایج بهتری بدست آورد و امکان آزمون و مسابقه را با یک ربات حرفه ای داشت.

    یک راه حرفه ای و مقرون به صرفه استفاده از رباتهای آماده سخت افزاری هست که نیاز به صرفا مونتاژ  ماژولها دارد و اصل موضوع برنامه نویسی و بهینه‌سازی الگوریتمهای مرتبط است. شرکت گیگا پرداز پارس با برند ProMake این محصولات را به‌صورت حرفه ای داخلی سازی کرده و در اختیار علاقه مندان قرار داده است. در نوشته های آتی به معرفی این محصولات جذاب و حرفه ای می پردازیم که با استفاده از دوربین و SBC های مشابه رزبری پای 3 یا 4 و یا برد  Jetson Nano انواع سناریوهای پردازش تصویر و AI را در ربات هوشمند قابل استفاده می کنند.