- ساختار حرفه ای چگونه اس و چرا به ان نیاز داریم ؟
- Module یعنی چه ؟
- Package چیست؟
__init__.pyچیست؟- Import یعنی چه؟
- Virtual Environment چیست؟
- برای پروژه ما چطور Virtual Environment بسازیم؟
- Git چیست؟
- GitHub چیست؟
- ما دقیقاً در این جلسه چه کاری انجام میدهیم؟
ساخت ساختار اولیه:
AGV_Project/
├── main.py
├── robot/
├── world/
├── sensors/
├── vision/
├── navigation/
├── control/
├── mapping/
├── ai/
├── data/
└── utils/
- مدیریت فایلها
- Module
- Package
- Import
- Virtual Environment
- Git مقدماتی
1. اصلاً چرا به این ساختار نیاز داریم؟
فرض کن تمام کدهای پروژه AGV را داخل یک فایل بنویسیم:
main.py
اول پروژه شاید اینطور باشد:
connect_to_pybullet() # تابع
create_robot() # تابع
move_robot() # تابع
read_lidar() # تابع
process_camera() # تابع
make_map() # تابع
find_path() # تابع
control_robot() # تابع
train_ai() # تابع
...
اوایل مشکلی نیست.
اما وقتی پروژه بزرگ شود، مثلاً ۱۰ هزار خط کد داشته باشیم، دیگر پیدا کردن و تغییر دادن کدها بسیار سخت میشود.
مثلاً بخواهی فقط کد مربوط به دوربین را تغییر بدهی.
باید در بین هزاران خط کد بگردی.
نکته : اینها در مثال بالا ، نه ماژول هستند و نه دستورهای واقعی Python/PyBullet. من برای توضیح ساده، اسمِ چند کار یا تابع فرضی را نوشته ام تا نشان بدهم اگر همه کارهای پروژه را در یک فایل
main.pyبریزیم چه شکلی میشود.
راهحل چیست؟
بهتر هست کد را بر اساس وظیفهاش تقسیم کنیم.
مثلاً:
AGV_Project/
│
├── main.py
│
├── robot/
│
├── world/
│
├── sensors/
│
├── vision/
│
├── navigation/
│
├── control/
│
├── mapping/
│
├── ai/
│
├── data/
│
└── utils/
یعنی به جای اینکه همه چیز را در یک فایل بریزیم، پروژه را به قسمتهای منطقی تقسیم میکنیم.
هر پوشه برای چیست؟
حالا تکتک آنها را ببینیم.
نکته مهم : ممکن هست چیزهایی که در پایین برایتان شرح میدم کمی گیج کننده باشد ، اما نگران نباشید چون همه انها را در جلسات بعد قدم به قدم یاد خواهسم گرفت . در این قسمت فقط میخوام کلیات مبحث در ذهن تان شکل بگیرد
1- main.py
این فایل را میتوانیم مرکز اجرای پروژه در نظر بگیریم.
مثلاً:
from robot.agv import create_agv
from world.environment import create_world
create_world()
agv = create_agv()
while True:
...
یعنی main.py قرار نیست تمام جزئیات پروژه را خودش انجام دهد.
وظیفهاش بیشتر این است که بگوید:
پروژه را از اینجا شروع کن و این قسمتها را به این ترتیب اجرا کن.
مثل مدیر پروژه.
2- پوشه robot/
هر چیزی که مستقیماً مربوط به خود ربات باشد اینجا قرار میگیرد.
مثلاً:
robot/
│
├── agv.urdf
├── agv.py
└── __init__.py
agv.py میتواند شامل کدهایی برای ساخت و بارگذاری ربات باشد.
مثلاً:
def create_agv():
...
بعد main.py فقط میگوید:
from robot.agv import create_agv
agv = create_agv()
یعنی جزئیات ساخت AGV را از main.py خارج کردهایم.
3- پوشه world/
هر چیزی مربوط به دنیای شبیهسازی.
مثلاً:
world/
├── warehouse.py
├── obstacles.py
├── floor.py
└── __init__.py
در آینده میتوانیم داشته باشیم:
warehouse.py
که انبار را ایجاد کند.
مثلاً:
def create_warehouse():
...
4- پوشه sensors/
اینجا سنسورهای ربات قرار میگیرند.
مثلاً:
sensors/
├── lidar.py
├── imu.py
├── camera.py
└── __init__.py
بعداً اگر بخواهیم LiDAR شبیهسازی کنیم:
from sensors.lidar import Lidar
و دوربین:
from sensors.camera import Camera
این خیلی مهم است چون پروژه ما بعداً چند نوع سنسور خواهد داشت.
5- پوشه vision/
این قسمت با sensors/ فرق دارد.
مثلاً:
sensors/camera.py
مسئول گرفتن تصویر است.
اما:
vision/processing.py
مسئول تحلیل تصویر است.
مثلاً:
Camera
↓
Image
↓
OpenCV
↓
Object Detection
پس:
sensors/
یعنی:
داده را از سنسور بگیر.
و:
vision/
یعنی:
داده تصویری را تحلیل کن.
این تفکیک در پروژههای واقعی بسیار مهم است.
6- پوشه navigation/
مغز مسیریابی ربات.
مثلاً:
navigation/
├── astar.py
├── dwa.py
├── localization.py
└── planner.py
در اینجا الگوریتمهایی مثل:
- A*
- Dijkstra
- DWA
- Localization
- Path Planning
قرار میگیرند.
مثلاً:
from navigation.astar import find_path
7- پوشه control/
این قسمت مسئول کنترل حرکت ربات است.
مثلاً:
control/
├── differential_drive.py
├── controller.py
└── pid.py
مثلاً Navigation میگوید:
باید به این نقطه بروی.
ولی Control تصمیم میگیرد:
چرخ چپ با چه سرعتی بچرخد؟
چرخ راست با چه سرعتی بچرخد؟
پس:
Navigation
↓
"به این نقطه برو"
↓
Control
↓
"چرخ چپ = 2 rad/s
چرخ راست = 3 rad/s"
8- پوشه mapping/
هر چیزی مربوط به ساخت نقشه محیط.
مثلاً:
mapping/
├── occupancy_grid.py
├── map_builder.py
└── __init__.py
LiDAR داده میدهد:
فاصله تا موانع
و این قسمت آن را تبدیل میکند به:
Occupancy Grid
یعنی نقشهای که مشخص میکند:
⬜ آزاد
⬛ مانع
9- پوشه ai/
این قسمت در پروژه ما خیلی مهم شده است.
هر چیزی که مربوط به هوش مصنوعی باشد میتواند اینجا قرار بگیرد.
مثلاً:
ai/
├── model.py
├── train.py
├── inference.py
├── rewards.py
└── __init__.py
بعداً ممکن است داشته باشیم:
ai/
machine_learning/
reinforcement_learning/
مثلاً:
Camera
↓
AI Model
↓
تشخیص مانع
↓
Navigation
یا:
AGV
↓
Reinforcement Learning
↓
یادگیری حرکت
10- پوشه data/
دادههای پروژه.
مثلاً:
data/
├── images/
├── datasets/
├── logs/
└── results/
مثلاً تصاویر دوربین:
data/images/
داده آموزشی Machine Learning:
data/datasets/
نتایج آزمایش:
data/results/
لاگها:
data/logs/
11- پوشه utils/
این یکی کمی متفاوت است.
گاهی یک سری توابع عمومی داریم که به یک قسمت خاص تعلق ندارند.
مثلاً:
utils/
├── logger.py
├── math_utils.py
├── config.py
└── __init__.py
مثلاً تابع تبدیل درجه به رادیان:
def deg_to_rad(angle):
...
چنین تابعی مخصوص Navigation یا Robot نیست.
پس میتواند در utils باشد.
2. حالا Module یعنی چه؟
این اصطلاح خیلی مهم است.
در Python، یک فایل .py میتواند یک Module باشد.
مثلاً:
lidar.py
یک Module است.
داخلش تابع اسکن رو داریم :
def scan():
...
داریم.
بعد در فایل دیگری میتوانیم بنویسیم:
from lidar import scan
یعنی:
تابع
scanرا از ماژولlidarوارد کن. به این میگن ماژول
3. Package چیست؟
Package را فعلاً خیلی ساده اینطور در نظر بگیر:
یک پوشه که چند Module مرتبط را کنار هم نگه میدارد.
مثلاً:
sensors/
│
├── lidar.py
├── camera.py
└── imu.py
اینجا:
lidar.py
camera.py
imu.py
ماژول هستند.
و:
sensors/
یک Package است.
البته در Python مدرن، جزئیات Package و __init__.py کمی پیچیدهتر است، ولی برای شروع همین تعریف کاملاً کافی است.
4. __init__.py چیست؟
ممکن است در پروژه ببینی:
sensors/
├── __init__.py
├── lidar.py
└── camera.py
این فایل برای تعریف/مدیریت Package استفاده میشود و میتواند خالی باشد.
مثلاً فعلاً داخلش میتونیم بنویسم :
# sensors package
که کافی است.
در آموزش ابتدایی لازم نیست وارد جزئیات پیشرفته __init__.py شویم.
اما تا اینجا به طور خلاصه بدونید
AGV_Project
│
├── sensors/ ← پوشه(پکیج)سنسورها
│ ├── __init__.py ← معرفی/ساخت Package
│ ├── lidar.py ← LiDAR
│ └── camera.py ← Camera
│
├── robot/
├── navigation/
├── control/
├── simulation/
├── vision/
└── main.py
سنسوریک پوشه برای نگهداری تمام کدهای مربوط به سنسورهای AGV است.که توش چند ماژول داره و برای اینکه پایتون اونو به عنوان یه پکیج بدونه از __init__.py استفاده میشه .
5. Import یعنی چه؟
فرض کن در:
sensors/lidar.py
یه تابع داریم اسکن داریم :
def scan():
print("LiDAR scanning...")
حالا در main.py میخواهیم از آن استفاده کنیم.
مینویسیم:
from sensors.lidar import scan
ینی تابع اسکن رو از ماژول لیدار وارد کن (ایمپورت کن) و بعد مینویسیم :
scan()
یعنی:
main.py
↓
sensors --> برو به پوشه سنسور
↓
lidar.py --> ماژول لیدار و پیدا کن
↓
scan() --> تابع اسکن رو پیدا کن و بیار
این همان Import کردن است.
6. Virtual Environment چیست؟
این هم بسیار مهم است.
فرض کن امروز پروژه ما نیاز دارد:
Python 3.13
PyBullet
OpenCV
NumPy
اما پروژه دیگری داری که نیاز دارد:
Python 3.11
اگر همه چیز را روی Python اصلی کامپیوتر نصب کنیم، ممکن است نسخهها با هم تداخل کنند.
راهحل:
برای هر پروژه یک محیط جدا بسازیم.
مثلاً:
AGV_Project
↓
Virtual Environment
↓
Python
PyBullet
NumPy
OpenCV
...
یعنی محیط پروژه AGV از پروژههای دیگر جدا باشد.
9. برای پروژه ما چه Virtual Environment بسازیم؟
مثلاً با Conda:
conda create -n agv_project python=3.13
بعد:
conda activate agv_project
حالا وقتی بنویسی:
python --version
نسخه Python همین محیط را میبینی.
بعد کتابخانههای پروژه را نصب میکنیم.
مثلاً:
pip install pybullet numpy opencv-python
و بعداً:
pip install matplotlib
و در مراحل Machine Learning کتابخانههای مورد نیاز خودمان را اضافه میکنیم.
نکته: لازم نیست از جلسه اول تمام کتابخانههای ۱۲۴ جلسه را نصب کنیم. هر فصل که به یک ابزار نیاز داشتیم، همان موقع نصبش میکنیم.
10. Git چیست؟
این هم برای پروژه Portfolio ما بسیار مهم است.
فرض کن امروز کد AGV خوب کار میکند.
فردا تغییرش میدهی و ناگهان همه چیز خراب میشود.
اگر Git داشته باشیم میتوانیم نسخههای قبلی پروژه را نگه داریم.
مثلاً:
Version 1
AGV حرکت میکند
↓
Version 2
LiDAR اضافه شد
↓
Version 3
Mapping اضافه شد
↓
Version 4
A* اضافه شد
و بعد اگر Version 4 خراب شد، میتوانیم به نسخه قبلی برگردیم.
12. GitHub چیست؟
Git روی کامپیوتر خودمان کار میکند.
GitHub جایی است که میتوانیم پروژه را آنلاین منتشر کنیم.
و این برای هدف Portfolio ما خیلی مهم است.
مثلاً در نهایت کارفرما میتواند وارد GitHub ما شود و ببیند:
AGV_Project
│
├── Robot
├── Sensors
├── Computer Vision
├── Navigation
├── AI
├── Mapping
└── Documentation
بعد README را بخواند و Demo Video را ببیند.
این خیلی بهتر از این است که در رزومه فقط بنویسیم:
PyBullet, Python, OpenCV, Machine Learning
13. حالا دقیقاً در این جلسه چه کاری انجام میدهیم؟
من پیشنهاد میکنم جلسه ۵ را فقط تئوری نگذاریم.
دانشجو باید در پایان جلسه واقعاً یک پروژه ساخته باشد.
*** خب حالا بیاید عملی شروع کنیم ***
اول باید کوندا را نصب کرده باشید
حالا باهم یه محیط جدید داخل کوندا ایجاد میکنیم تا پایتون مخصوص خودش رو داشته باشه و پایبالت متناسب با اونو نصب کیم
حتماً. این بار خیلی ساده و خطی میچینیم. فقط سه مفهوم را از هم جدا کن:
- Python سیستم = Pythonی که مستقل از Anaconda روی ویندوز نصب شده.
- Python Conda = Python داخل یک Conda Environment.
- Conda = خود برنامه مدیریت Environment و Packageها.
و یک نکته مهم: defaults و conda-forge مربوط به منبع دانلود Packageها هستند، نه نسخه Python و نه خود Environment.
13.1 اول وضعیت فعلی سیستم را ببینیم
در Anaconda Prompt یا PowerShell این دستورات را بزن.
Python فعال فعلی
python --version
مسیر Python فعال
where python
Pythonهای نصبشده روی ویندوز
py -0p
نسخه خود Conda
conda --version
Environmentهای Conda
conda env list
مثلاً ممکن است ببینی:
base
D:\MyProjects\pybullet
Channel فعلی Conda
conda config --show channels
13.2 الان سیستم خودت را به defaults برگردان
اگر قبلا به هر دلیل اناکوندا داشتید و و از کانال اکوندا فورج پکیج دانلود کردید ، اونو به حالت دیفالت برگردونید. اما اگه همیشه از کوندا فورج استفاده میکنید مشکلی نداره و با اون راحت هستید و میتونید از اون استفاده کنید، این مرحله رو رد کنید. برای برگشت به حالت قبلی:
conda config --remove channels conda-forge
بعد:
conda config --add channels defaults
حالا بررسی:
conda config --show channels
باید ببینی:
channels:
- defaults
تمام.
این کار Environment های شمارو حذف نمیکند.
یعنی مثلا اگه محیط زیر رو با فورج ایجاد کردید الان با برگشت به حتالت دیفالت ، مشکلی برای اون محیط به وجود نمیاد:
D:\MyProjects\pybullet
همچنان وجود دارد.
13.3 روش اول: همه چیز با defaults
فرض کنیم میخواهی یک محیط جدید بسازی دو راه داره یا از کانال اناکوندا دیفالت استفاده کنید یااز کانال اناکوندا فورج:
چون مسیر کانال اناکوندا دیفالت معمولا ارور میده بهتره از چنل فورج استفاده مینم اما من هردو روش رو گذاشتم تا شما امتحان کنین
اگه هر کدوم ارور داد از اون یکی استفاده کنین.
در این روش میتونید با فیلتر شکن و بدون هم جلو برید تا ببینین نتیجه میگیرید یا نه.
فرض کنیم اسم محیط جدید رو در مسیر زیر و به اسم پایبالت دیفالت میذارید
D:\MyProjects\pybullet_default
ومیخوای Python 3.12 داشته باشی.
شروع ساخت Environment
اوال باید از منوی استارت ویندوز دنبال anaconda prompt بگردی و اونو باز کنی یا anacoda powershell حالا در اول اون خطی شبیه این میبینی:
(base) C:\Windows\System32>
حالا دستور زیر رو کپی میکنی و تو اناکوندا پرامپ یا پاورشل اون میزنی
conda create --prefix D:\MyProjects\pybullet_default python=3.12
Conda از defaults استفاده میکند و سعی میکنه تا این محیط رو با این اسم ایجاد کنه و داره از دیفالت استفاده میکنه
بعد اگه ارور نداشت و کامل انجلم شد باید اون محیط رو فعال کنیم تا اسم اون پوشه اول اناکوندا پرامپت بیافته:
conda activate D:\MyProjects\pybullet_default
بررسی Python:
python --version
و:
where python
باید چیزی شبیه:
Python 3.12.x
و:
D:\MyProjects\pybullet_default\python.exe
ببینی.
نصب PyBullet با defaults
حالا:
conda install pybullet
اگر PyBullet در defaults برای شرایط تو موجود باشد، Conda خودش نسخه مناسب را پیدا میکند.
اگر گفت:
PackagesNotFoundError
یعنی در Channelهای فعلی، Build مناسب PyBullet پیدا نشده؛ آن موقع میرویم سراغ conda-forge.
13.4 روش دوم: یک Environment کاملاً conda-forge
این روشی است که برای پروژه PyBullet پیشنهاد میکنم.
نکته مهم:
یادت باشه که لازم نیست تنظیمات کل Conda را تغییر بدهی.ینی ممکنه شما قبلا برای نصب پکیج ها و محیط از کوندا دیفالت استفاده کردی الان با تغییر کامل اون به کوندا فورج ، ممکن است یک پروژه قدیمی داشته باشی که Packageهایش با اکوسیستم
defaultsساخته شدهاند. حالا تغییر Channel سراسری میتواند باعث شود در نصبها یا Updateهای بعدی، Conda ترکیبی از Buildهای متفاوت را وارد محیط کند و احتمال dependency conflict بیشتر شود و تداخل یا ارورهایی پیش بیاد . همینطور برعکس ممکنه مثلا کلا از کوندا فورج همیشه استفاده میکردی الان با تغییر سراسری به کوندا دیفالت باز همون مشکل پیش میاد ==> بهتره همیشه قبل ساخت محیط و پکیج ها از کد زیر استفاده کنی تا ببینی رو کانال دیفالت هستی یا فورج
conda config –show channels
اگه تو حالت دیفالت بود که از روش قبل تو شماره 3 استفاده میکنیم و اگه نصب ها کامل انجام شد که دیگه از این روش دوم ینی بخش شماره 4 که الان درحال خوندن اون هستی رد شو
وگرنه به جای دیفالت از فورج استفاده میکنیم که احتمال نصب اون به شدت بالاست
یادت باشه برای این حالت غالبا بدون فیلتر شکن میتونی کارهات رو انجام بدی
*** نکته به شدت مهم *** : کل اناکوندا روبه conda-forge تبدیل نمیکنیم فقط برای محیطی که داریم میسازیم اونو تبدیل به conda-forge میکنیم و بیرون اون محیط کوندا دیفالت هست و این باعث میشه تا برای پروژه های دیگه تون مشکل پیش نیاد
پس میتوانی فقط برای همین Environment بگویی:
همه چیز را از conda-forge بگیر.
این بهترین قسمت ماجراست.
ساخت Environment با conda-forge
مثلاً:
conda create --prefix D:\MyProjects\pybullet_forge -c conda-forge --override-channels python=3.12
این دستور یعنی:
Environment:
D:\MyProjects\pybullet_forge
Python:
3.12
Channel:
فقط conda-forge
--override-channels خیلی مهم است؛ یعنی:
Channelهای دیگری مثل defaults را برای این دستور نادیده بگیر.
فعال کردن
conda activate D:\MyProjects\pybullet_forge
بررسی:
python --version
و:
where python
نصب PyBullet در محیط conda-forge
حالا:
conda install -c conda-forge --override-channels pybullet
این یعنی:
PyBullet را فقط از conda-forge نصب کن.
Conda خودش نسخه سازگار با Python 3.12 را انتخاب میکند.
بعد تست:
python -c "import pybullet; print(pybullet.__version__)"
13.5 اگر بعداً خواستی Package جدید نصب کنی، از کجا بفهمی Environment تو forge است یا defaults؟
این قسمت خیلی مهم است. فرض کن تو محیط رو با فعال کردن کانال conda forge برای اون محیط ساختی اما بعد یه مدتی میخوای اپدیت کنی یا چیز جدید تو اون محیط نصب کنی برای اینکه تداخلی پیش نیاد باید اول بفهمی قبلا اینو با دیفالت ساختی یا با فورج تا الان ادامه نصب هاتو هم با اونانجام بدی برای همین از مسیر زیر میریم.
اول Environment که قراره باهاش کار کنی یا داخلش چیزی نصب و اضافه کنی را فعال کن:
conda activate D:\MyProjects\pybullet_forge
بعد:
conda config --show channels
اما یک نکته: این دستور Channel تنظیمشده در Conda را نشان میدهد نه الزاماً اینکه تکتک Packageهای نصبشده از کجا آمدهاند. ینی ممکنه تو برای این محیط خاص ، کوندا فورج رو فعال کردی اما برای اناکوندا سراسری ، هنوز همون دیفالت فعال هست. اما برای اینکه بفهمی مثلا پایبالت چطور دان شده از دستورات زیر برو
برای اینکه بفهمی یک Package مشخص از کجا آمده:
conda list # or --> conda list pybullet
در خروجی معمولاً ستونی مثل:
channel
میبینی.
مثلاً:
pybullet 3.25 ... conda-forge
numpy 2.x ... conda-forge
پس میتوانی بفهمی Package از کجا آمده.
13.6 پس برای اینکه هیچوقت قاطی نشود، این روش را استفاده کن
اگر Environment را با conda-forge ساختهای، برای نصبهای بعدی هم صریحاً بنویس:
conda install -c conda-forge --override-channels numpy
یا:
conda install -c conda-forge --override-channels pandas
یا:
conda install -c conda-forge --override-channels opencv
اینطوری مطمئن هستی که برای آن دستور، فقط conda-forge استفاده میشود.
13.7 حالا کل دو مسیر را کنار هم ببین
مسیر A — Defaults
1. Channel = defaults
↓
2. ساخت محیط
↓
conda create --prefix D:\MyProjects\project python=3.12
↓
3. فعال کردن
↓
conda activate D:\MyProjects\project
↓
4. نصب PyBullet
↓
conda install pybullet
مسیر B — Conda-forge
1. Channel = conda-forge
↓
2. ساخت محیط
↓
conda create --prefix D:\MyProjects\project python=3.12 -c conda-forge --override-channels
↓
3. فعال کردن
↓
conda activate D:\MyProjects\project
↓
4. نصب PyBullet
↓
conda install -c conda-forge --override-channels pybullet
13.8 یک نکته خیلی مهم برای آینده
به جای اینکه دائم تنظیمات کل Conda را اینطور عوض کنی:
defaults
↓
conda-forge
↓
defaults
↓
conda-forge
برای پروژههای مختلف بهتر است Channel را هنگام ساخت/نصب مشخص کنی.
مثلاً پروژه PyBullet:
conda create --prefix D:\MyProjects\pybullet -c conda-forge --override-channels python=3.12
و بعد همیشه:
conda install -c conda-forge --override-channels ...
این خیلی تمیزتر است.
خلاصهای که ارزش حفظ کردن دارد
| کار | دستور |
|---|---|
| Python فعال | python --version |
| مسیر Python | where python |
| Pythonهای ویندوز | py -0p |
| نسخه Conda | conda --version |
| محیطها | conda env list |
| Channel فعلی | conda config --show channels |
| ساخت محیط در D | conda create --prefix D:\MyProjects\project python=3.12 |
| فعال کردن | conda activate D:\MyProjects\project |
| ساخت با فقط conda-forge | conda create --prefix D:\MyProjects\project -c conda-forge --override-channels python=3.12 |
| نصب با defaults | conda install package |
| نصب فقط از forge | conda install -c conda-forge --override-channels package |
| برگشت تنظیمات به defaults | conda config --remove channels conda-forge سپس conda config --add channels defaults |
13.9 چطور میتونم محیطی که ساختم رو به هر دلیلی حذف کنم ؟
بله، خیلی راحت. چون محیطهای قبلی را با --prefix داخل D:\MyProjects ساختهای، بهتر است با خود Conda حذفشان کنی، نه اینکه دستی پوشه را Delete کنی.
1. اول محیطهایت را ببین
conda env list
مثلاً ممکن است ببینی:
base
D:\MyProjects\pybullet
D:\MyProjects\pybullet_default
D:\MyProjects\Anaconda_PyEnv_pybullet_forge
2. محیط آزمایشی را حذف کن
مثلاً اگر این را میخواهی حذف کنی:
D:\MyProjects\pybullet_default
بزن:
conda env remove --prefix D:\MyProjects\pybullet_default
Conda ازت تأیید میخواهد. y بزن.
3. اگر چند محیط آزمایشی داری
مثلاً:
D:\MyProjects\test1
D:\MyProjects\test2
D:\MyProjects\pybullet_old
هرکدام را جدا حذف کن:
conda env remove --prefix D:\MyProjects\test1
conda env remove --prefix D:\MyProjects\test2
conda env remove --prefix D:\MyProjects\pybullet_old
4. بعد دوباره بررسی کن
conda env list
باید فقط محیطهایی که واقعاً میخواهی نگه داری باقی بمانند.
⚠️ یک نکته مهم
اگر همین محیط فعلی فعال است:
(D:\MyProjects\Anaconda_PyEnv_pybullet_forge)
آن را حذف نکن.
برای حذف یک محیط، بهتر است اول از آن خارج شوی:
conda deactivate
بعد حذفش کنی.
و پوشه را دستی از File Explorer پاک نکن؛ روش درست برای Environmentهای Conda این است:
conda env remove --prefix مسیر_محیط
************************************
13.10 حالا که محیط جدید را ساختیم و پایبالت رو در اون نصب کردیم بریم سراغ ادامه کار یعنی ساخت پوشه پروژه AGV :
ما اول تو درایو D، محیط جدید را تو مسیر زیر ساختیم و پای بالت رو تو اون نصب کردیم
D:\MyProjects\Anaconda_PyEnv_pybullet_forge
برای همین باید یه نکته رو بدونیم .اینی که ما ساختیم یه محیط جدید بود تا کتابخانه های مخصوص پای بالت و خود اون و پکیج های لازم تو این محیط نصب بشن که با پروژه های دیگه ما که از اناکوندا استفاده میکنن تداخل پیدا نکنن.
فرض کن یه پروژه حسابداری داری با pyqt میسازی و پایتون و پکیج های خاص خودش رو داره برای همین برای اونم یه محسط مخصوص خودش رو به وسیله اناکوندا میسازی که مثلا اون از پایتون 3.9 استفاده میکنه اما پروژه رباتیک(پایبالت) تو از پایتون 3.14 استفاده میکنه ==> اینا برای اینکه تداخل نداشته باشن تو از محیط های جدا استفاده کردی
اما الان که من یه محیط برای کارهای رباتیک و شبیه سازی ایجاد کردم ، قراره چندین زیر پروژه از پای بالت داشته باشم . مثلا یه پروژه مقدماتی برای راه اندازی یه چرخ با پای بالت هست و یه پروژه برای ساخت یه ربات انسان نما و یه پروژه هم برای ساخت ربات چهار چرخ agv که قراره ما بسازیم. فرض کن ما برنامه اکسل رو نصب کردی (همون پای بالت) اما قراره باهاش ندین برنامه بسازیم تو یکی حساب کتاب های ماهانه مون رو . تو یه شیت اکسل دیگه میخوام برنامه درسی مون رو داشته باشیم و همینطور الی اخر
اینجا هم ما پای بالت رو تو محیط مون به اسم و مسیر D:\MyProjects\Anaconda_PyEnv_pybullet_forge داریم الان میخوایم با اون پروژه های مختلف انجام بدیم
الان ایا باید همه این پروژه ها تو همون محیطی که ساختیم برای پایبالت (D:\MyProjects\Anaconda_PyEnv_pybullet_forge) باید همه شون درهم تو اونجا باشن یا میتونیم باز کارمون رو حرفه ای تر پیش ببریم ؟!!
الان ما این را داریم:
D:\MyProjects\Anaconda_PyEnv_pybullet_forge
این Environment است، نه محل نگهداری پروژههای PyBullet.
داخلش فایلها و پوشههایی مثل python.exe، Lib، DLLs و … وجود دارد. داخل این پوشه پروژه AGV یا هر پروژه دیگه رو نساز.
پس در نتیجه : آیا باید داخل Environment پوشه Project بسازم؟
خیر بلکه بهتر است D:\MyProjects را اینطوری سازماندهی کنی یه پوشه برای محیط مون که پای بالت هست و پوشه های دیگه برای پروژه مون کنار این محیط نه داخل محیط. مثل زیر:
D:\MyProjects
│
├── Anaconda_PyEnv_pybullet_forge ← Environment
│ ├── python.exe
│ ├── Lib
│ ├── DLLs
│ └── ...
│
├── AGV_Project ← پروژه 1
│ ├── main.py
│ ├── robot
│ ├── world
│ ├── sensors
│ ├── navigation
│ ├── vision
│ └── ...
│
├── PickAndPlace_Project ← پروژه 2
│ ├── main.py
│ └── ...
│
└── DigitalTwin_Project ← پروژه 3
├── main.py
└── ...
یعنی:
Environment یک بار ساخته میشود، ولی چندین Project میتوانند از آن استفاده کنند.
حالا AGV چطور از PyBullet استفاده میکند؟
تو داری:
D:\MyProjects\Anaconda_PyEnv_pybullet_forge
که داخلش داری:
Python 3.12
PyBullet
NumPy
...
حالا میسازی:
D:\MyProjects\AGV_Project
داخلش مثلاً:
AGV_Project
│
├── main.py
├── robot
├── world
├── sensors
├── navigation
├── vision
└── ...
بعد وقتی میخواهی AGV را اجرا کنی، Environment را فعال میکنی:
conda activate D:\MyProjects\Anaconda_PyEnv_pybullet_forge
بعد میروی داخل پروژه:
cd D:\MyProjects\AGV_Project
و:
python main.py
Python از Environment استفاده میکند و بنابراین:
AGV_Project
↓
Python موجود در Environment
↓
PyBullet موجود در Environment
نکته خیلی مهم
این دو تا را از هم جدا کن:
Environment
Anaconda_PyEnv_pybullet_forge
یعنی:
«ابزار و کتابخانههایی که پروژهها میتوانند استفاده کنند.»
Project
AGV_Project
PickAndPlace_Project
DigitalTwin_Project
یعنی:
«کد و فایلهای مربوط به یک پروژه مشخص.»
آیا چند پروژه میتوانند از یک PyBullet استفاده کنند؟
بله، کاملاً.
مثلاً:
Anaconda_PyEnv_pybullet_forge
│
├── Python 3.12
├── PyBullet
├── NumPy
├── OpenCV
└── SciPy
↑
┌──────────────┼──────────────┐
│ │ │
↓ ↓ ↓
AGV_Project PickPlace_Project DigitalTwin
همه این پروژهها میتوانند از همان PyBullet استفاده کنند.
پس فعلا برای ایجاد پوشه ای که بتونیم پروژه مون ور توش داشته باشیم اینطوری پیش میریم
یک نکته برای پروژه AGV مون :
با توجه به اینکه قرار است بعداً پروژه AGV را جدی و نسبتاً بزرگ بسازیم، پیشنهاد من این است که بری تو پوشه ای که محیط رو ساختیم و کنار محیط ساخته شده یه پوشه جدید با اسم پروژه مون که agv هست بسازی.:
D:\MyProjects
│
├── Anaconda_PyEnv_pybullet_forge
│
└── AGV_Project
│
├── main.py
├── robot
├── world
├── sensors
├── navigation
├── mapping
├── vision
├── ai
├── control
├── data
└── utils
حالا که مثلاً در Windows در درایو D ساختیم :
D:
└── MyProjects
└── Anaconda_PyEnv_pybullet_forge
└── AGV_Project
داخلش میخواهیم اینارو بسازیم:
AGV_Project/
│
├── main.py
│
├── robot/
├── world/
├── sensors/
├── vision/
├── navigation/
├── control/
├── mapping/
├── ai/
├── data/
└── utils/
و داخل هر پوشه فعلاً یک فایل __init__.py قرار میدهیم.
13.11 ساخت محتویات داخل پوشه پروژه ( AGV پروژه)
اولین : فایل main.py
اول باید یه محیط کد نویسی داشته باشید که پیشنهاد من پایچارم و بعد وی اس کد هست اما چون قراه پروژه بزرگتر بشه:
برای این پروژه PyCharm را ترجیح میدهم، چون پروژه ما قرار است بزرگ شود و تعداد زیادی Package و Module خواهیم داشت.
Spyder را برای این پروژه انتخاب نمیکنیم.
Jupyter هم بعداً برای تحلیل داده و آزمایشهای Machine Learning میتواند مفید باشد، اما محیط اصلی توسعه پروژه ما PyCharm خواهد بود.
PyCharm را باز کن
مرحله 1 — ساخت AGV_Project
در PyCharm برو به:
File → New Project
یا اگر الان یک پروژه باز است:
File → New Project
مسیر پروژه را بگذار:
D:\MyProjects\AGV_Project
اگر PyCharm ازت Python Interpreter خواست، همان Environmentای که ساختهای را انتخاب کن:
D:\MyProjects\Anaconda_PyEnv_pybullet_forge\python.exe
یعنی:
کد پروژه در
AGV_Projectباشد، ولی Python و PyBullet از Environment قبلی استفاده شوند.
مرحله 2 — ساخت main.py
وقتی پروژه AGV_Project باز شد، در پنل سمت چپ روی:
AGV_Project
راستکلیک → New → Python File

اسم:
main
بگذار.
PyCharm خودش میسازد:
main.py
فعلاً داخلش فقط این را بنویس:
print("AGV Project Started")
دومین : ساخت پوشههای پروژه
حالا روی AGV_Project راستکلیک کن:
New → Directory

و بهترتیب اینها را بساز:
robot
world
sensors
vision
navigation
control
mapping
ai
data
utils
در نهایت باید در سمت چپ PyCharm ببینی:

AGV_Project
│
├── main.py
│
├── robot
├── world
├── sensors
├── vision
├── navigation
├── control
├── mapping
├── ai
├── data
└── utils
فعلاً داخل این پوشهها هیچ فایل Python نساز. چون هنوز داریم اسکلت پروژه را ایجاد میکنیم.
مرحله تست خیلی مهم
در PyCharm روی main.py راستکلیک کن:
Run ‘main’
باید پایین PyCharm ببینی:
AGV Project Started
بعد برای اطمینان از اینکه PyCharm واقعاً از Environment خودت استفاده میکند، داخل main.py این را بگذار:
import sys
print(sys.executable)
اجرا کن.
باید مسیر شبیه این باشد:
D:\MyProjects\Anaconda_PyEnv_pybullet_forge\python.exe

اگر این مسیر را دیدی، یعنی PyCharm → AGV_Project → Python 3.12 Environment → PyBullet درست به هم وصل شدهاند.
13.13 تکمیل فایل های داخل هریک از پوشه های AGV
بعد اینکه فایل main و پوشه های robot -world و… رو ساختیم الان باید داخل این پوشه ها (robot-world,…) رو تکمیل تر کنیم ==> یک Module واقعی میسازیم
تکمیل پوشه اول : robot
مرحله بعد: ساخت اولین Module
ساختار فعلی تو:
AGV_Project/
│
├── main.py
│
├── robot/
├── world/
├── sensors/
├── vision/
├── navigation/
├── control/
├── mapping/
├── ai/
├── data/
└── utils/
قدم 1 — داخل robot فایل بساز
در PyCharm:
robot
↓ راستکلیک
New
↓
Python File
اسمش را بگذار:
agv
پس:
robot/
└── agv.py
قدم 2 — داخل agv.py
بنویس:
def create_agv():
print("AGV created!")
فعلاً همین.
این فایل الان یک Module است.
یعنی:
agv.py
یک Module پایتون است.
قدم 3 — برو داخل main.py
بنویس:
from robot.agv import create_agv
print("AGV Project Started!")
create_agv()
قدم 4 — اجرا کن
روی main.py راستکلیک:
Run 'main'
باید ببینی:
AGV Project Started!
AGV created!
اگر این را دیدی، یعنی Import درست کار کرده.
اما دقیقاً چه اتفاقی افتاد؟
این خط:
from robot.agv import create_agv
را به سه قسمت تقسیم کن:
from robot.agv import create_agv
│ │ │
│ │ └── تابع
│ │
│ └── فایل agv.py
│
└── پوشه robot
یعنی:
برو داخل پوشه
robot، فایلagv.pyرا پیدا کن واز داخل اون، تابعcreate_agvرا در اینجا وارد کن.
بعد:
create_agv()
تابع را اجرا میکند.
یک نکته مهم درباره Package
در Python مدرن، پوشه robot میتواند بدون __init__.py هم بهعنوان namespace package کار کند؛ اما برای آموزش ساختار پروژه پیشنهاد میکنم فعلاً داخل پوشههای کدی مثل robot یک فایل خالی به نام:
__init__.py
هم بسازیم. همان کار قبل رو تکرار میکنیم روی robot در سمت چپ در پایچارم راست کلیک کن –> انتخاب اولین گزینه (NEW) –> انتخاب python file –> نوشتن __init__.py –> دیگه داخلش نمیخواد چیزی بنویسیم فعلا !
پس:
robot/
│
├── __init__.py
└── agv.py
__init__.py فعلاً میتواند کاملاً خالی باشد.
این کمک میکند مفهوم Package را هم واضح ببینی:
robot/ ← Package
│
├── __init__.py
│
└── agv.py ← Module
بنابراین:
Package = پوشه Python
Module = فایل
.py
🎯 فایل -ماژول – پکیج – init : اینا 4 تا مفهوم اساسی که شاید شمارو گیج کرده باشه رو توضیح میدم تا ساختار پروژه و فعالیتمون رو بهتر درک کنین
بیا این را بدون اصطلاحات پیچیده و با همین پروژه AGV خودمان روشن کنیم. اگر این چهار مفهوم را بفهمی، ساختار پروژه Python خیلی قابلفهم میشود.
1. اول «فایل» چیست؟
هر چیزی که با پسوند .py میسازی، یک فایل Python است.
مثلاً:
main.py
agv.py
lidar.py
camera.py
اینها همگی فایل هستند.
2. Module چیست؟
در Python، یک فایل .py که بتوانی از آن کد را در فایل دیگری استفاده کنی، یک Module محسوب میشود.
مثلاً:
robot/
└── agv.py
agv.py یک فایل است و در عین حال یک Module است.
داخلش:
class AGV:
def move(self):
print("AGV is moving")
نوشته شده . حالا در main.py میتوانی از آن استفاده کنی:
from robot.agv import AGV
یعنی:
از Module به نام
agv، کلاسAGVرا بیاور.
پس:
agv.py
│
├── یک فایل است
└── یک Module هم هست
این دو تا متناقض نیستند. ینی از نوشته های داخل فایل agv میتونی تو فایل مثلا main استفاده کنی
3. Package چیست؟
حالا فرض کن تعداد زیادی Module داری:
robot/
│
├── agv.py
├── motor.py
├── wheel.py
└── battery.py
اینها همه Module هستند.
ما آنها را داخل یک پوشه به نام robot گذاشتهایم.
این پوشه نقش Package را دارد.
پس:
robot/
│
├── agv.py ← Module
├── motor.py ← Module
├── wheel.py ← Module
└── battery.py ← Module
یعنی:
Package = یک مجموعه از Moduleهای مرتبط
در پروژه ما:
robot
برای چیزهای مربوط به خود ربات است.
4. پس main.py چیست؟
main.py هم یک فایل Python و در نتیجه یک Module است.
اما ما از آن به عنوان نقطه شروع برنامه استفاده میکنیم.
مثلاً:
from robot.agv import AGV
agv = AGV()
agv.move()
وقتی در PyCharm روی main.py میزنی:
Run
برنامه از آنجا شروع میشود.
پس:
main.pyاز نظر Python فقط یک Module است، اما از نظر ساختار برنامه ما نقش Entry Point یا نقطه شروع اجرای برنامه را دارد.
5. حالا __init__.py چیست؟
این قسمت مهم است.
فرض کن داریم:
robot/
│
├── __init__.py
├── agv.py
└── motor.py
فایل:
__init__.py
به Python میگوید:
این پوشه را به عنوان یک Package Python در نظر بگیر.
البته در Python 3، در بسیاری از شرایط Package میتواند بدون __init__.py هم کار کند؛ به آن Namespace Package میگویند.
اما برای پروژهای مثل AGV، وجود __init__.py باعث میشود ساختار Package واضحتر و قابلکنترلتر باشد.
6. آیا __init__.py باید چیزی داخلش داشته باشد؟
نه.
فعلاً میتواند کاملاً خالی باشد:
robot/
│
├── __init__.py ← خالی
└── agv.py
و هیچ مشکلی ندارد.
7. پس چرا اصلاً وجود دارد؟
کاربرد اول: مشخص کردن Package
ساختار:
robot/
├── __init__.py
└── agv.py
خیلی واضح میگوید:
robot = Package
agv = Module
کاربرد دوم: اجرای کد هنگام Import
بعداً میتوانی داخل __init__.py چیزی قرار دهی.
مثلاً:
print("Robot package loaded")
وقتی بنویسی:
import robot
کد __init__.py اجرا میشود.
اما فعلاً این کار را نکن؛ فقط مفهومش را بدان.
کاربرد سوم: کنترل چیزهایی که از Package بیرون میدهی
مثلاً بعداً میتوانیم در:
robot/__init__.py
بنویسیم:
from .agv import AGV
بعد بتوانی بنویسی:
from robot import AGV
به جای:
from robot.agv import AGV
این کاربرد را بعداً در پروژه خودمان خواهیم دید.
8. حالا کل پروژه خودت را ببین
تو داری:
AGV_Project/
│
├── main.py
│
├── robot/
│ ├── __init__.py
│ └── agv.py
│
├── sensors/
│ ├── __init__.py
│ └── lidar.py
│
├── navigation/
│ ├── __init__.py
│ └── navigator.py
│
└── vision/
├── __init__.py
└── camera.py
حالا میتوانی اینطور نگاه کنی:
AGV_Project
│
├── main.py
│ ↑
│ نقطه شروع برنامه
│
├── robot
│ ↑
│ Package
│
│ ├── __init__.py
│ └── agv.py
│ ↑
│ Module
│
├── sensors
│ ↑
│ Package
│
│ └── lidar.py
│ ↑
│ Module
│
└── vision
↑
Package
└── camera.py
↑
Module
9. یک نکته خیلی مهم: Package با Environment فرق دارد
این را حتماً از هم جدا کن:
Anaconda_PyEnv_pybullet_forge
Environment است.
اما:
robot/
sensors/
vision/
Packageهای پروژه Python هستند.
این دو هیچ ارتباط مستقیمی با هم ندارند.
ساختار تو:
D:\MyProjects
│
├── Anaconda_PyEnv_pybullet_forge ← Python + PyBullet + NumPy...
│
└── AGV_Project ← کد پروژه
│
├── main.py
├── robot/ ← Package
├── sensors/ ← Package
├── vision/ ← Package
└── ...
مرحله بعد: پوشه دوم سنسور
پوشه اول تمام شد میریم پوشه دوم
تا اینجا اینو درست کردیم
AGV_Project/
│
├── main.py
├── robot/
│ ├── __init__.py
│ └── agv.py
├── sensors/
├── vision/
.
.
یعنی فعلاً برای بقیه پوشهها __init__.py نساز.
چرا؟ چون هنوز آنها Packageهای واقعی نشدهاند و میخواهیم وقتی به هر بخش رسیدیم، همان موقع ساختار آن را ایجاد کنیم.
1. داخل sensors یک __init__.py بساز
در PyCharm:
sensors
→ Right Click
→ New
→ Python File
→ __init__
حالا:
sensors/
└── __init__.py
2. یک Module به نام lidar.py بساز
داخل sensors:
sensors
→ Right Click
→ New
→ Python File
→ lidar
ساختار:
sensors/
├── __init__.py
└── lidar.py
3. داخل lidar.py
فعلاً خیلی ساده:
class Lidar:
def read(self):
print("Lidar is reading distance...")
اینجا یک Class ساختیم به نام Lidar.
4. حالا main.py
کد قبلی AGV را نگه دار و سنسور را هم اضافه کن:
from robot.agv import create_agv
from sensors.lidar import Lidar
print("AGV Project Started!")
create_agv()
lidar = Lidar()
lidar.read()
5. اجرا کن
باید ببینی:
AGV Project Started!
AGV created!
Lidar is reading distance...
در اینجا دوباره این زنجیره را میبینی:
sensors/ ← Package
│
├── __init__.py
│
└── lidar.py ← Module
│
└── Lidar ← Class
و در main.py:
from sensors.lidar import Lidar
یعنی:
از Package
sensors، از Modulelidar، کلاسLidarرا بیاور.
55555555
26. در نهایت ساختار پروژه ما به این شکل میشود
AGV_Project/
│
├── main.py
│
├── robot/
│ ├── __init__.py
│ └── agv.py
│
├── world/
│ ├── __init__.py
│ └── warehouse.py
│
├── sensors/
│ ├── __init__.py
│ ├── lidar.py
│ ├── camera.py
│ └── imu.py
│
├── vision/
│ ├── __init__.py
│ └── processing.py
│
├── navigation/
│ ├── __init__.py
│ ├── astar.py
│ └── dwa.py
│
├── control/
│ ├── __init__.py
│ └── controller.py
│
├── mapping/
│ ├── __init__.py
│ └── occupancy_grid.py
│
├── ai/
│ ├── __init__.py
│ ├── train.py
│ └── inference.py
│
├── data/
│ ├── images/
│ ├── datasets/
│ ├── logs/
│ └── results/
│
└── utils/
├── __init__.py
└── math_utils.py
اما الان قرار نیست همه این فایلها را پر کنیم.
این فقط اسکلت ساختمان پروژه است.
مثل این است که قبل از ساخت کارخانه، ابتدا نقشه ساختمان را مشخص کنیم.
چرا این جلسه برای دوره خیلی مهم است؟
چون اگر این قسمت را حذف کنیم، احتمالاً در فصلهای بعد به یک مشکل جدی میرسیم:
یک فایل 5000 خطی
که در آن:
PyBullet
+
AGV
+
LiDAR
+
Camera
+
OpenCV
+
A*
+
AI
همه قاطی شدهاند.
اما ما از همین ابتدا به شما یاد میدهیم:
هر قسمت پروژه مسئولیت خودش را دارد.
مثلاً:
robot/
→ ربات
sensors/
→ سنسورها
vision/
→ بینایی ماشین
mapping/
→ نقشه
navigation/
→ مسیریابی
control/
→ کنترل
ai/
→ هوش مصنوعی
و این دقیقاً همان چیزی است که بعدها در یک پروژه واقعی رباتیک به آن نیاز خواهیم داشت.