Seri Protokoller
TEKNİK REHBER SERİ PROTOKOLLER CANopen 2026

CANopen
CiA 301 — Endüstriyel CAN Protokolü

Object Dictionary, PDO/SDO haberleşmesi, NMT durum makinesi — CANopen'ı Python ile yönet, motor sürücüleri ve sensörlerle entegre et.

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ı

Endüstriyel otomasyonServo motor sürücüler (Maxon EPOS, Faulhaber MC), PLC'ler, G/Ç modülleri. CiA 402 uygulama profili motor sürücüler için standarttır.
Tıbbi cihazlarISO 11073 tabanlı tıbbi CANopen (CiA 425). X-ray makineleri, robotik cerrahi sistemleri, ilaç dispenserleri.
RobotikEklem kontrol modülleri, güç kaynakları, sensör arayüzleri. Düşük gecikme ve senkron PDO özelliği kritik.
Deniz ve ulaşımCANopen Maritime (CiA 450), araç içi sistemler (CiA 447 otomobil profili), inşaat makinesi kontrol birimleri.

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.

COB-ID

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)

IndexSubNesne AdıAçıklama
0x100000Device TypeCihaz profil numarası (örn. 0x00040192 = servo sürücü)
0x100100Error RegisterAktif hata bayrakları (8 bit)
0x100800Manufacturer Device NameCihaz ismi (string)
0x101700Producer Heartbeat TimeHeartbeat periyodu (ms), 0=devre dışı
0x101801-04Identity ObjectVendor ID, Product Code, Revision, Serial Number
0x1200–0x127FSDO Server ParametersSDO sunucu COB-ID'leri
0x1400–0x15FFRPDO CommunicationRPDO COB-ID, transmission type
0x1600–0x17FFRPDO MappingRPDO'nun hangi OD nesnelerine eşlendiği
0x1800–0x19FFTPDO CommunicationTPDO COB-ID, transmission type
0x1A00–0x1BFFTPDO MappingTPDO'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.

device.eds — örnek (kısaltılmış)
[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

TPDO (Transmit PDO)Node'un ürettiği ve bus'a gönderdiği PDO. Node'un sensör değerleri, durum bilgisi, encoder pozisyonu gibi veriler taşır. COB-ID = 0x180 + Node-ID (TPDO1).
RPDO (Receive PDO)Node'un bus'tan aldığı ve işlediği PDO. Master'dan gelen setpoint, komut, referans değerleri gibi. COB-ID = 0x200 + Node-ID (RPDO1).

PDO COB-ID tablosu

PDOCOB-IDYön
TPDO10x180 + Node-IDNode → Master/diğerleri
RPDO10x200 + Node-IDMaster → Node
TPDO20x280 + Node-IDNode → Master/diğerleri
RPDO20x300 + Node-IDMaster → Node
TPDO30x380 + Node-IDNode → Master/diğerleri
RPDO30x400 + Node-IDMaster → Node
TPDO40x480 + Node-IDNode → Master/diğerleri
RPDO40x500 + Node-IDMaster → Node

PDO Mapping

PDO'nun taşıdığı veriler OD nesneleriyle eşlenir. Mapping OD'de 0x1600-0x1BFF aralığında tanımlanır:

PDO mapping — OD entry formatı
/* 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ğerTipAçıklama
0Synchronous/AcyclicSYNC sonrası yalnızca değişmişse gönderir
1–240Synchronous/CyclicHer N. SYNC'te gönderir (N = değer)
252Synchronous RTRRTR isteğinden sonraki SYNC'te gönderir
253Asynchronous RTRRTR isteğinde hemen gönderir
254Event-driven (mfr)Üretici tanımlı olayda gönderir
255Event-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

MesajCOB-IDAçıklama
SDO Request (Client → Server)0x600 + Node-IDMaster, node'a istek gönderir
SDO Response (Server → Client)0x580 + Node-IDNode, master'a yanıt gönderir

Expedited transfer (≤4 byte)

SDO expedited write — frame yapısı
/* 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 CodeAnlam
0x05030000Toggle bit uyuşmazlığı
0x05040000SDO protokol zaman aşımı
0x06010000Nesneye erişim desteklenmiyor
0x06010001Nesne write-only (okuma yapılamaz)
0x06010002Nesne read-only (yazma yapılamaz)
0x06020000OD'de nesne bulunamadı
0x06040041Nesne PDO'ya mappenemez
0x06090011Subindex bulunamadı
0x08000022Veri 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-IDKomut byteHedefİşlev
0x0000x01Node-ID veya 0 (tüm)Start Node → Operational
0x0000x02Node-ID veya 0Stop Node → Stopped
0x0000x80Node-ID veya 0Pre-Operational'a al
0x0000x81Node-ID veya 0Reset Node (uygulama reset)
0x0000x82Node-ID veya 0Reset Communication

Heartbeat vs Node Guarding

Heartbeat (önerilen)Her node, OD 0x1017'de ayarlanan periyotta otomatik olarak kendi durumunu 0x700+Node-ID adresinden yayınlar. Master bu mesajları izler; timeout olursa node arızalı kabul edilir. CiA 301 v4+ için önerilen yöntem.
Node Guarding (eski)Master, node'lara periyodik RTR frame gönderir; node yanıt verir. Daha yüksek bus trafiği oluşturur. Yeni projelerde kullanımı önerilmez.
heartbeat_frame — yapısı
/* 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.

sync_example.py
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 CodeKategoriAçıklama
0x0000Hata temizlendi (reset)
0x1000GenericGenel hata
0x2000–0x23FFCurrentAşırı akım
0x3000–0x33FFVoltageAşırı/düşük gerilim
0x4000–0x43FFTemperatureAşırı sıcaklık
0x5000–0x53FFDevice HardwareDonanım arızası
0x6000–0x63FFDevice SoftwareYazılım hatası
0x7000–0x73FFAdditional ModulesEk modül hatası
0x8000–0x83FFMonitoringİzleme hatası (heartbeat, NMT)
0x9000–0x93FFExternal ErrorHarici hata girişi
0xFF00–0xFFFFDevice SpecificÜretici tanımlı

Error Register bitleri (OD 0x1001)

error_register.c
/* 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

bash — kurulum
pip install canopen python-can
canopen_basic.py
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

canopen_pdo.py
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

liblely (C/C++)Tam özellikli, üretim düzeyi CANopen kütüphanesi. CiA 301/402/447 desteği, asenkron I/O, C++17 API. sudo apt install liblely-coapp-dev
CANopenNode (gömülü C)Kaynak bazlı, bare-metal ve RTOS uyumlu açık kaynak CANopen stack. Arduino, STM32, Raspberry Pi üzerinde çalışır. GitHub: CANopenNode/CANopenNode

08 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ü

cia402_velocity.py
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

eds_create.py — python-canopen ile EDS üretme
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")
ARAÇLAR

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.