00 CANopen nedir ve OSI katmanlarındaki yeri
CANopen, CAN bus üzerine inşa edilmiş üst katman protokolüdür. CiA (CAN in Automation) tarafından yönetilen CiA 301 standardı, haberleşme profili tanımlar; uygulama profilleri ise sektöre özel nesne tanımları sağlar.
Uygulama alanları
OSI katmanı modeli
Katman 7 (Uygulama): CANopen uygulama profili (CiA 402, 401, 404...)
──────────────────────────────────────────────────────
Katman 7 (Haberleşme): CANopen CiA 301
PDO, SDO, NMT, SYNC, EMCY, TIME, HEARTBEAT
──────────────────────────────────────────────────────
Katman 2 (Veri bağlantısı): ISO 11898-1 CAN Data Link
Frame format, arbitration, error detection, ACK
──────────────────────────────────────────────────────
Katman 1 (Fiziksel): ISO 11898-2/5 CAN PHY
Diferansiyel sinyal, terminasyon, kablo
CANopen ağ yapısı
CANopen ağında bir NMT Master ve en fazla 127 Slave node bulunur. Her node'un 1-127 arasında benzersiz bir Node-ID değeri vardır.
CANopen'da her mesaj türü için CAN ID alanı COB-ID (Communication Object Identifier) olarak adlandırılır. Çoğu COB-ID, fonksiyon kodu (4-bit) + Node-ID (7-bit) = 11-bit şeklinde hesaplanır. Örnek: TPDO1 COB-ID = 0x180 + Node-ID.
01 Object Dictionary (OD)
Object Dictionary (Nesne Sözlüğü), CANopen node'unun tüm yapılandırma ve süreç verilerini tutan sanal bir veritabanıdır. Her giriş 16-bit index ve 8-bit subindex ile adreslenir.
OD yapısı
Index İçerik
──────────────────────────────────────────────
0x0000 Kullanılmıyor
0x0001–0x001F Temel veri tipleri (CiA tanımlı)
0x0020–0x003F Karmaşık veri tipleri
0x1000–0x1FFF İletişim profil alanı (CiA 301)
0x2000–0x5FFF Üretici tanımlı alan
0x6000–0x9FFF Standart uygulama profili nesneleri (CiA 40x)
0xA000–0xFFFF Rezerv
Önemli standart objeler (1000h-1FFFh)
| Index | Sub | Nesne Adı | Açıklama |
|---|---|---|---|
| 0x1000 | 00 | Device Type | Cihaz profil numarası (örn. 0x00040192 = servo sürücü) |
| 0x1001 | 00 | Error Register | Aktif hata bayrakları (8 bit) |
| 0x1008 | 00 | Manufacturer Device Name | Cihaz ismi (string) |
| 0x1017 | 00 | Producer Heartbeat Time | Heartbeat periyodu (ms), 0=devre dışı |
| 0x1018 | 01-04 | Identity Object | Vendor ID, Product Code, Revision, Serial Number |
| 0x1200–0x127F | SDO Server Parameters | SDO sunucu COB-ID'leri | |
| 0x1400–0x15FF | RPDO Communication | RPDO COB-ID, transmission type | |
| 0x1600–0x17FF | RPDO Mapping | RPDO'nun hangi OD nesnelerine eşlendiği | |
| 0x1800–0x19FF | TPDO Communication | TPDO COB-ID, transmission type | |
| 0x1A00–0x1BFF | TPDO Mapping | TPDO'nun hangi OD nesnelerini taşıdığı |
EDS ve DCF dosyaları
EDS (Electronic Data Sheet), bir CANopen cihazının OD yapısını tanımlayan INI formatındaki text dosyasıdır. Üretici tarafından sağlanır. DCF (Device Configuration File) ise EDS'in belirli bir node yapılandırmasıyla özelleştirilmiş halidir.
[FileInfo]
FileName=MyDevice.eds
FileVersion=1
FileRevision=1
EDSVersion=4.0
CreationTime=09:00AM
CreationDate=04-12-2026
Description=My CANopen Device
[DeviceInfo]
VendorName=Example Corp
VendorNumber=0x12345678
ProductName=ExampleNode
ProductNumber=0x00000001
RevisionNumber=0x00010000
BaudRate_500=1
[DummyUsage]
Dummy0002=0
[Comments]
Lines=0
[1000]
ParameterName=Device Type
ObjectType=0x7
DataType=0x0007
AccessType=ro
DefaultValue=0x00040192
PDOMapping=0
[1017]
ParameterName=Producer Heartbeat Time
ObjectType=0x7
DataType=0x0006
AccessType=rw
DefaultValue=1000
PDOMapping=0
02 PDO — Process Data Object
PDO, gerçek zamanlı proses verisi taşıyan yüksek öncelikli mesajlardır. SDO'nun aksine SDO handshake mekanizması yoktur; veri doğrudan CAN frame payload'ında iletilir.
TPDO ve RPDO
PDO COB-ID tablosu
| PDO | COB-ID | Yön |
|---|---|---|
| TPDO1 | 0x180 + Node-ID | Node → Master/diğerleri |
| RPDO1 | 0x200 + Node-ID | Master → Node |
| TPDO2 | 0x280 + Node-ID | Node → Master/diğerleri |
| RPDO2 | 0x300 + Node-ID | Master → Node |
| TPDO3 | 0x380 + Node-ID | Node → Master/diğerleri |
| RPDO3 | 0x400 + Node-ID | Master → Node |
| TPDO4 | 0x480 + Node-ID | Node → Master/diğerleri |
| RPDO4 | 0x500 + Node-ID | Master → Node |
PDO Mapping
PDO'nun taşıdığı veriler OD nesneleriyle eşlenir. Mapping OD'de 0x1600-0x1BFF aralığında tanımlanır:
/* TPDO1 Mapping (OD 0x1A00) örneği:
sub00: kaç nesne maplı (örn. 2)
sub01: 0x60640020 = OD[0x6064][0x00], 32-bit (pozisyon değeri)
sub02: 0x60410010 = OD[0x6041][0x00], 16-bit (statusword)
Format: 0xIIIISSLL
IIII = OD index (16-bit)
SS = subindex (8-bit)
LL = uzunluk (bit cinsinden: 08=1byte, 10=2byte, 20=4byte)
*/
// TPDO1 içeriği: [pozisyon(4B)][statusword(2B)] = 6 byte CAN payload
// CAN frame: ID=0x180+NodeID, DLC=6, data=[pos0,pos1,pos2,pos3,stat0,stat1]
Transmission type (iletim tipi)
| Değer | Tip | Açıklama |
|---|---|---|
| 0 | Synchronous/Acyclic | SYNC sonrası yalnızca değişmişse gönderir |
| 1–240 | Synchronous/Cyclic | Her N. SYNC'te gönderir (N = değer) |
| 252 | Synchronous RTR | RTR isteğinden sonraki SYNC'te gönderir |
| 253 | Asynchronous RTR | RTR isteğinde hemen gönderir |
| 254 | Event-driven (mfr) | Üretici tanımlı olayda gönderir |
| 255 | Event-driven (profile) | Değer değişimi veya timer dolumunda |
03 SDO — Service Data Object
SDO, OD nesnelerine erişmek için kullanılan istek-yanıt mekanizmasıdır. Yapılandırma, parametre okuma/yazma ve büyük veri aktarımı için PDO yerine SDO kullanılır.
SDO COB-ID
| Mesaj | COB-ID | Açıklama |
|---|---|---|
| SDO Request (Client → Server) | 0x600 + Node-ID | Master, node'a istek gönderir |
| SDO Response (Server → Client) | 0x580 + Node-ID | Node, master'a yanıt gönderir |
Expedited transfer (≤4 byte)
/* SDO Write Request (Expedited) — 8 byte CAN payload */
/* Byte 0: Command Specifier
Bits 7-5: 001 = Initiate Download (write) request
Bit 4: e=1 expedited (≤4 byte)
Bit 3: s=1 size belirtildi
Bits 2-1: n = (4 - veri_uzunluğu) → boş byte sayısı
Bit 0: 0 */
// Örnek: OD[0x6040][0x00] = 0x000F (controlword) yaz
// 2 byte yazma: n=2, e=1, s=1 → cs = 0b00101111 = 0x2F
// Byte: [0x2F][0x40][0x60][0x00][0x0F][0x00][0x00][0x00]
// cs idx_lo idx_hi sub data0 data1 pad pad
/* SDO Write Response (başarılı) */
// Byte: [0x60][0x40][0x60][0x00][0x00][0x00][0x00][0x00]
// cs=ACK idx_lo idx_hi sub
Segmented transfer (>4 byte)
Veri 4 byte'ı aşıyorsa segmented transfer kullanılır. İlk frame Initiate, ardından segment frame'leri, son olarak End mesajı gönderilir. Her segment 7 byte veri taşır.
Block transfer
Block transfer, büyük veri bloklarını (firmware, EDS dosyası) verimli aktarmak için optimize edilmiş SDO modudur. Her blok 127 segment içerebilir; her segment CRC denetlenir.
SDO Abort codes
| Abort Code | Anlam |
|---|---|
| 0x05030000 | Toggle bit uyuşmazlığı |
| 0x05040000 | SDO protokol zaman aşımı |
| 0x06010000 | Nesneye erişim desteklenmiyor |
| 0x06010001 | Nesne write-only (okuma yapılamaz) |
| 0x06010002 | Nesne read-only (yazma yapılamaz) |
| 0x06020000 | OD'de nesne bulunamadı |
| 0x06040041 | Nesne PDO'ya mappenemez |
| 0x06090011 | Subindex bulunamadı |
| 0x08000022 | Veri aygıt durumu nedeniyle yazılamadı |
04 NMT — Network Management
NMT, CANopen ağındaki node'ların yaşam döngüsünü yönetir. Durum makinesi beş durumdan oluşur; NMT master, node'lara komut göndererek durum geçişlerini tetikler.
NMT durum makinesi
Boot-up
↓
┌──────────── Initialisation ────────────┐
│ (reset, init tamamlanıyor) │
└────────────────────↓────────────────────┘
Pre-Operational
↗ (SDO aktif, PDO kapalı) ↘
Start Node ──→ Operational ←── Stop Node
(PDO + SDO aktif)
↓ Stop Node
Stopped
(sadece NMT mesajı alır)
NMT Reset: Reset Node → Initialization'a gönder
NMT komut frame'leri
| COB-ID | Komut byte | Hedef | İşlev |
|---|---|---|---|
| 0x000 | 0x01 | Node-ID veya 0 (tüm) | Start Node → Operational |
| 0x000 | 0x02 | Node-ID veya 0 | Stop Node → Stopped |
| 0x000 | 0x80 | Node-ID veya 0 | Pre-Operational'a al |
| 0x000 | 0x81 | Node-ID veya 0 | Reset Node (uygulama reset) |
| 0x000 | 0x82 | Node-ID veya 0 | Reset Communication |
Heartbeat vs Node Guarding
/* Heartbeat frame:
COB-ID = 0x700 + Node-ID
DLC = 1
Data[0]= NMT durumu:
0x00 = Boot-up (sadece bir kez, init sonrası)
0x04 = Stopped
0x05 = Operational
0x7F = Pre-Operational
*/
/* Örnek: Node 5, Operational durumunda heartbeat */
/* CAN ID=0x705, DLC=1, Data=[0x05] */
05 SYNC ve TIME
SYNC mesajı, ağdaki tüm node'ların aynı anda ölçüm yapmasını veya çıkış güncellemesini sağlayan senkronizasyon sinyalidir.
SYNC üretici ve tüketicisi
SYNC Üretici (Producer):
COB-ID = 0x080 (varsayılan)
DLC = 0 veya 1 (sayaçla birlikte)
Periyot: OD 0x1006 (SYNC Communication Period, µs cinsinden)
SYNC Tüketici (Consumer):
Her node SYNC alınca:
1. Sensör okur / aktuatör günceller (sync PDO için)
2. Transmission type 1-240 arası PDO'lar: N. SYNC'te gönderir
SYNC sayacı
CiA 301 v4'ten itibaren SYNC frame'i 1 byte sayaç taşıyabilir (1-240 arası döngüsel). Bu sayaç, farklı dönemlere sahip PDO'ların zamanlamasını koordine etmek için kullanılır.
import canopen
network = canopen.Network()
network.connect(channel='can0', bustype='socketcan')
# SYNC üretici başlat (10 ms periyot = 10000 µs)
network.sync.start(0.01) # saniye cinsinden
# Manuel SYNC gönderme
network.sync.transmit()
# SYNC durdur
network.sync.stop()
TIME objesi
TIME mesajı (COB-ID 0x100), ağa UTC zamanı yayınlar. 6 byte veri: 4 byte gün sayısı (1984-01-01'den itibaren ms), 2 byte gün içindeki milisaniye. Zaman senkronizasyonu gereken uygulamalarda (örn. log kaydı) kullanılır.
06 EMCY — Emergency
EMCY mesajı, bir node'da hata oluştuğunda otomatik gönderilir. Hızlı hata bildirimi için tasarlanmıştır; event-driven ve yüksek önceliklidir.
EMCY frame yapısı
COB-ID = 0x080 + Node-ID
DLC = 8
Byte 0-1: Emergency Error Code (2 byte, little-endian)
Byte 2: Error Register (OD 0x1001 ile aynı)
Byte 3-7: Manufacturer Specific Error Field (5 byte, üretici tanımlı)
Standart emergency error codes
| Error Code | Kategori | Açıklama |
|---|---|---|
| 0x0000 | — | Hata temizlendi (reset) |
| 0x1000 | Generic | Genel hata |
| 0x2000–0x23FF | Current | Aşırı akım |
| 0x3000–0x33FF | Voltage | Aşırı/düşük gerilim |
| 0x4000–0x43FF | Temperature | Aşırı sıcaklık |
| 0x5000–0x53FF | Device Hardware | Donanım arızası |
| 0x6000–0x63FF | Device Software | Yazılım hatası |
| 0x7000–0x73FF | Additional Modules | Ek modül hatası |
| 0x8000–0x83FF | Monitoring | İzleme hatası (heartbeat, NMT) |
| 0x9000–0x93FF | External Error | Harici hata girişi |
| 0xFF00–0xFFFF | Device Specific | Üretici tanımlı |
Error Register bitleri (OD 0x1001)
/* OD 0x1001 — Error Register (8-bit):
Bit 0: Generic error
Bit 1: Current
Bit 2: Voltage
Bit 3: Temperature
Bit 4: Communication error (overflow vb.)
Bit 5: Device profile specific
Bit 6: Rezerv
Bit 7: Manufacturer specific
*/
/* Örnek: sıcaklık hatası */
/* Error Code = 0x4210 (Motor winding over-temperature) */
/* Error Register bit 3 = 1 → 0x08 */
/* Frame: ID=0x080+5=0x085, Data=[0x10,0x42,0x08,mfr,mfr,mfr,mfr,mfr] */
07 Linux CANopen kütüphaneleri
Linux'ta CANopen için birçok seçenek mevcuttur. Hızlı prototipleme için python-canopen, gömülü sistemler için CANopenNode, üretim düzeyi C++ projeler için liblely önerilir.
python-canopen
pip install canopen python-can
import canopen
# Ağ oluştur ve bağlan
network = canopen.Network()
network.connect(channel='can0', bustype='socketcan', bitrate=500000)
# EDS dosyasıyla node ekle (Node-ID=5)
node = network.add_node(5, 'motor_drive.eds')
# NMT: Pre-Operational → Operational
node.nmt.state = 'OPERATIONAL'
# SDO ile OD nesnesi oku
device_type = node.sdo[0x1000].raw
print(ff"Device Type: 0x{device_type:08X}")
vendor_id = node.sdo[0x1018][1].raw
print(ff"Vendor ID: 0x{vendor_id:08X}")
# SDO ile yazma
node.sdo[0x1017].raw = 1000 # Heartbeat 1000 ms
# PDO okuma (Operational modda TPDO alınır)
import time
time.sleep(0.1)
position = node.tpdo[1]['Position actual value'].phys
print(ff"Pozisyon: {position} rpm")
network.disconnect()
PDO mapping Python ile
import canopen, time
network = canopen.Network()
network.connect(channel='can0', bustype='socketcan')
node = network.add_node(5, 'drive.eds')
# Pre-Operational gerekli (PDO yapılandırması sadece Pre-Op'ta)
node.nmt.state = 'PRE-OPERATIONAL'
time.sleep(0.1)
# TPDO1 mapping: pozisyon (0x6064) + statusword (0x6041) oku
node.tpdo.read() # mevcut mapping oku
node.tpdo[1].clear() # mapping temizle
node.tpdo[1].add_variable('Position actual value') # 0x6064
node.tpdo[1].add_variable('Statusword') # 0x6041
node.tpdo[1].trans_type = 255 # event-driven
node.tpdo[1].event_timer = 10 # 10 ms periyot
node.tpdo[1].enabled = True
node.tpdo.save() # SDO ile OD'ye yaz
# RPDO1: controlword + target velocity gönder
node.rpdo.read()
node.rpdo[1].clear()
node.rpdo[1].add_variable('Controlword') # 0x6040
node.rpdo[1].add_variable('Target velocity') # 0x60FF
node.rpdo[1].enabled = True
node.rpdo.save()
# Operational moda al
node.nmt.state = 'OPERATIONAL'
time.sleep(0.1)
# RPDO1 ile hedef hız gönder
node.rpdo[1]['Controlword'].raw = 0x000F # enable
node.rpdo[1]['Target velocity'].phys = 1000 # 1000 rpm
node.rpdo[1].transmit()
# TPDO callback ile gerçek zamanlı pozisyon
def on_tpdo1(message):
pos = node.tpdo[1]['Position actual value'].phys
print(ff"Pozisyon: {pos}")
node.tpdo[1].add_callback(on_tpdo1)
time.sleep(5)
network.disconnect()
liblely ve CANopenNode
sudo apt install liblely-coapp-dev08 Pratik: python-canopen ile motor sürücü kontrolü
CiA 402 uygulama profili, servo motor sürücüler için standart OD nesnelerini tanımlar. Maxon EPOS4 ve Faulhaber MC gibi yaygın sürücüler bu profili destekler.
CiA 402 durum makinesi
Power disabled → Switch On Disabled → Ready to Switch On
→ Switched On → Operation Enabled → Running
Controlword (0x6040) ile geçişler:
0x0006 → Ready to Switch On
0x0007 → Switched On
0x000F → Operation Enabled
0x0000 → Disable
Statusword (0x6041) ile durum okunur.
Maxon EPOS4 / Faulhaber ile hız kontrolü
import canopen, time
def cia402_enable(node):
"""CiA 402 sürücüyü Operation Enabled durumuna getir"""
# Fault reset (varsa)
node.sdo[0x6040].raw = 0x0080
time.sleep(0.05)
# Shutdown → Ready to Switch On
node.sdo[0x6040].raw = 0x0006
time.sleep(0.05)
# Switch On
node.sdo[0x6040].raw = 0x0007
time.sleep(0.05)
# Enable Operation
node.sdo[0x6040].raw = 0x000F
time.sleep(0.1)
status = node.sdo[0x6041].raw
print(ff"Statusword: 0x{status:04X}")
return (status & 0x006F) == 0x0027 # Operation Enabled check
network = canopen.Network()
network.connect(channel='can0', bustype='socketcan', bitrate=500000)
node = network.add_node(1, 'epos4.eds')
node.nmt.state = 'OPERATIONAL'
time.sleep(0.2)
if cia402_enable(node):
print("Sürücü aktif!")
# Profile Velocity Mode seç (Modes of Operation = 3)
node.sdo[0x6060].raw = 3
time.sleep(0.1)
# Hedef hız: 500 rpm
node.sdo[0x60FF].raw = 500
print("Hedef hız: 500 rpm")
# 3 saniye çalıştır
time.sleep(3)
# Dur
node.sdo[0x60FF].raw = 0
time.sleep(0.5)
node.sdo[0x6040].raw = 0x0007 # Switched On
print("Motor durduruldu")
network.disconnect()
EDS dosyası oluşturma
import canopen
# Boş OD oluştur
node = canopen.LocalNode(1, canopen.ObjectDictionary())
od = node.object_dictionary
# Device Type (0x1000) ekle
rec = canopen.objectdictionary.Variable('Device Type', 0x1000, 0)
rec.data_type = canopen.objectdictionary.UNSIGNED32
rec.access_type = 'ro'
rec.default = 0x00040192
od.add_object(rec)
# Heartbeat Time (0x1017)
hb = canopen.objectdictionary.Variable('Producer Heartbeat Time', 0x1017, 0)
hb.data_type = canopen.objectdictionary.UNSIGNED16
hb.access_type = 'rw'
hb.default = 1000
od.add_object(hb)
# EDS olarak kaydet
canopen.export_od(od, 'my_device.eds')
print("EDS kaydedildi: my_device.eds")
canopenshell (can-utils ile birlikte gelen komut satırı aracı) ile hızlı SDO okuma/yazma yapılabilir: canopenshell can0 r 5 0x1000 0. objdictedit (OpenPCS araçları içinde) EDS dosyalarını görsel olarak düzenlemek için kullanılır.